Compare commits

...

42 Commits

Author SHA1 Message Date
Bartosz Podrygajlo
3d049174ca O-RU: clean exit 2026-01-07 17:54:41 +01:00
Bartosz Podrygajlo
9989ba0fce O-RU: PRACH RX and transmission over PRACH UP packet generation 2026-01-07 14:33:19 +01:00
Bartosz Podrygajlo
83f8447eb9 Add per symbol PRACH reception 2026-01-02 10:07:32 +01:00
Bartosz Podrygajlo
02d3f924fb Fix for rebase on top of the FFT size change
Some missing modifications from the change which introduces differentiaton
between PRACH nad PxSCH FFT size.
2026-01-02 09:26:58 +01:00
Bartosz Podrygajlo
cfe85db76d Debug print for frequency domain data per symbol. 2025-12-31 16:18:39 +01:00
Bartosz Podrygajlo
efe7c63362 O-RU: DL FH processing
Implemented downlink fronthaul processing: symbol rotation and DFT.

Introduced new config parameter: tp_cores in ORUs section to specify which
cores will be used for threadpool processing in O-RU.
2025-12-31 16:17:11 +01:00
Bartosz Podrygajlo
28a2149bcf Add a new tx_rf_symbols function to allow per symbol transmission 2025-12-30 09:38:13 +01:00
Bartosz Podrygajlo
64590837af O-RU: Synchronize north read to south read threads.
Perform synchronization between input sample from split8 device and split 7.2
timestamp via a fifo queue between threads.
2025-12-30 07:37:43 +01:00
Bartosz Podrygajlo
eae421cce6 Update threadCreate
Two modifications for threadCreate:
 - if -1 is passed, the thread no longer inherits its parent affinity.
   Instead thread affinity of the process is used.
 - if the name is too long, the thread name is shortened to maximum
   pthread name (16 characters).
2025-12-30 07:36:59 +01:00
Bartosz Podrygajlo
a744dc8f85 O-RU: Add sync thread
Add a small thread which performs initial sync related tasks.
2025-12-29 14:05:28 +01:00
Bartosz Podrygajlo
253ad4dca1 Load vrtsim in O-RU and start reading samples
Added oru_south_read_thread that reads samples from vrtsim.
No UL FH processing is done as of this commit.
2025-12-29 13:11:36 +01:00
Bartosz Podrygajlo
43be360a15 Simplify vrtsim timing job thread. 2025-12-29 13:08:53 +01:00
Bartosz Podrygajlo
670902fbca Add get_timestamp to openair_device_t and vrtsim
This function can be used to convert a timespec struct to a
openair0_timestamp. It can be used to synchronize the realtime
clock to the device sample number.
2025-12-29 13:08:42 +01:00
Bartosz Podrygajlo
1128782fc7 Add a function which loads the specified radio library 2025-12-29 13:06:52 +01:00
Bartosz Podrygajlo
c46b193cc6 O-RU: Return IQ samples to the application 2025-12-29 12:52:50 +01:00
Bartosz Podrygajlo
ef7d1f7020 O-RU: DL IQ preprocessing
Preprocess DL IQ on a separate thread
2025-12-29 12:52:50 +01:00
Bartosz Podrygajlo
4970fc151c O-RU: Offset symbol_callback by T2a_min
Add offset to when symbol_callback is triggered and adjust sense_of_time
struct output to align with the extra offset.
2025-12-29 12:52:50 +01:00
Bartosz Podrygajlo
0c55c94a25 Add Ta3, T2a delay profile params for O-RU 2025-12-29 12:52:50 +01:00
Bartosz Podrygajlo
5b4bbfc953 Add ORAN K release hook patch
This adds XRAN K release hook patch which allows packet processing
in application code without utilizing most of XRAN business logic.

XRAN still handles OWDM, timers and S plane. C/U-plane needs to be
handled by the application. Use xran_hook_install to install packet
processing callbacks.
2025-12-29 12:52:50 +01:00
Bartosz Podrygajlo
3716359dea O-RU: Add empty packet processing functions
Add empty processing function for O-RU. This utilizes hook functionality
in the xran K release hook modification.
2025-12-29 12:52:50 +01:00
Bartosz Podrygajlo
81bf88f4a6 O-RU: Add north_read thread
Add a thread that is supposed to read IQ data in DL and perform DL TX processing
2025-12-29 12:52:50 +01:00
Bartosz Podrygajlo
cb6f10aa55 ORU: Setup frame params according to new configuration
Added initialization of frame params according to configuration added
in the new ORUs section. Only one ORU is supported right now.

Added example config that allows starting the ORU and verifying manually
that the config is read.
2025-12-29 12:52:02 +01:00
Bartosz Podrygajlo
c2aac2259c Add north_in function to oran_fhlib_5g
The north_in function is supposed to be used by the ORU to read IQ data
sent from O-DU.
2025-12-29 12:52:02 +01:00
Mario Joa-Ng
82c9b2534f Use no of fh_config in configuration file to determine the number of peers
Determine number of DU for RU config file or no of RU for DU config file
based on number of fh_config elements.
2025-12-29 12:52:02 +01:00
Raymond Knopp
4a58ba0aa3 Initial implementation of O-RU for 7.2 emulator
Added new executable oainr_ru which acts as a 7.2 O-RU.

Co-authored-by: Bartosz Podrygajlo <bartosz.podrygajlo@openairinterface.org>
Co-authored-by: Mario Joa-Ng <mario.joa-ng@openairinterface.org>
2025-12-29 12:51:56 +01:00
Romain Beurdouche
02ec8dd39e fix(oran_fhlib_5g): Correctly read PRACH beam index in K release
Co-authored-by: Mario Joa-Ng <mario.joa-ng@openairinterface.com>
2025-12-29 12:40:40 +01:00
Mario Joa-Ng
bb7b01caf9 fix two PRACH bugs. 1. Use *pPrbMap = (struct xran_prb_map *)bufs->prachdstdecomp instead of * pPrbMap = (struct xran_prb_map *)&bufs->prachdstdecomp as pointer of PrbMap. 2. Clear nRxPkt of the RbMap of the previous slot. 2025-12-29 12:40:40 +01:00
Romain Beurdouche
9c158f7240 WIP: fix(oran_fhlib_5g): Attempt to fix handling of PRACH
This is an incomplete attempt to complete the parent commit which is also WIP.

Try to add a PRACH callback in order to properly handle PRACH in K release.
As of now a segmentation fault is issued when trying to decompress the PRACH data.
2025-12-29 12:40:40 +01:00
Romain Beurdouche
47880484ec WIP: fix(oran_fhlib_5g): Use new RX PRB mapping
K release introduced a new structure to describe the segmentation of RX symbols.
This commit enables using this structure to retrieve RX data.

The commit is incomplete.
As of this commit, the PRACH buffer is initialized to 0 in order to avoid a segmentation fault but it should normally be initialized using `oran_allocate_cplane_buffers`.
2025-12-29 12:40:40 +01:00
Romain Beurdouche
26783d0b47 fix(oran_fhlib_5g): Trim padding of UL U-Plane packets
Some RUs produce UL U-Plane packets with padding.
Packets with padding are considered erroneous by XRAN and are dropped.
Instead of dropping these packets, we trim their padding.
2025-12-29 12:40:40 +01:00
Romain Beurdouche
bc2d5899d8 feat(oran_fhlib_5g): configuration of perMu
Add functions in oran config to properly configure and print perMu out of the outer fh_config configure and print functions.
2025-12-29 12:40:39 +01:00
Romain Beurdouche
1ee401401c feat(oran_fhlib_5g): RX error counters
K releases added RX error counters
This commits adds a printing of these counters with LOG_I
2025-12-29 12:38:38 +01:00
Romain Beurdouche
84daf5b0c3 fix(oran_fhlib_5g): Indexing with numerology
Several arrays in the xran interface are indexed by the numerology.
It was ambiguous whether they were indexed by the actual numerology number or by the index of the relevant numerology within the numerology array.
They are actually indexed by the numerology number so that when one is using only numerlogy 1 for example, he should only use perMu[1], fftSize[1], ...
2025-12-29 12:38:37 +01:00
Jaroslava Fiedlerova
d0702f648f Install libatomic in FHI72 gNB images
libatomic is required by DPDK 22.11.7
2025-12-29 12:37:37 +01:00
Romain Beurdouche
43a37bcef7 fix(oran_fhlib_5g): Fix build on Arm
Disable new AVX related additions
2025-12-29 12:37:37 +01:00
Robert Schmidt
19874a1be1 TODO FHI7.2 on ARM: fix meson platform error
Avoid error

    config/arm/meson.build:603:8: ERROR: Problem encountered: Unsupported part number 0xd4f of implementer 0x41. Please add support for it or use the generic (-Dplatform=generic) build.

as suggested by meson. More information and a proper fix might be found
here:
https://doc.dpdk.org/guides/linux_gsg/cross_build_dpdk_for_arm64.html#supported-soc-configuration
2025-12-29 12:37:37 +01:00
Robert Schmidt
c2a633e175 FHI7.2 docker images: make output less verbose on build 2025-12-29 12:37:37 +01:00
Romain Beurdouche
23c8179b5f feat(CI): Build FHI with K release
Updated the dockerfiles for building FHI with K release and DPDK 22.11.0
2025-12-29 12:37:37 +01:00
Romain Beurdouche
7ffdfa50a6 feat(oran_fhlib_5g): Changes to run K release
* Initialize leak detector
* Fill IO config field holding the number of mbufs to be allocated
* Allocate and fill `activeMUs` in the FH config
* Start timing source, worker thread and activate CCs upon starting the FH
* Fill `mu_number[0]` in FH config
* Invert trx_oran end and stop
* Set `neAxcUl`
2025-12-29 12:37:37 +01:00
Romain Beurdouche
499b8fb2c4 feat(oran_fhlib_5g): Adapt oran_fhlib_5g for K release
Adapt the oran_fhlib_5g code to compile with xran K release.
Like previously E and F, uses preprocessor directives to separate codes for different xran releases.

Note: Release K of the FHI library supports many numerologies on one instance.
As of now the integration supports only one numerology.
2025-12-29 12:37:36 +01:00
Romain Beurdouche
3e127abbbf feat(oran_fhlib_5g): update Findxran
Update the Cmake find script for xran to detect K release (11.1.1).
2025-12-29 12:33:26 +01:00
Romain Beurdouche
0cdfb3c865 feat(oran_fhlib_5g): patch for K release
Added a patch for K release inspired from the patch of F release.
xran K release compiles with DPDK v22.11 and custom DPDK install path.
2025-12-29 12:33:26 +01:00
42 changed files with 4628 additions and 253 deletions

View File

@@ -1788,6 +1788,30 @@ target_link_libraries(lte-uesoftmodem PRIVATE ${blas_LIBRARIES} ${cblas_LIBRARIE
target_link_libraries(lte-uesoftmodem PRIVATE
asn1_lte_rrc asn1_s1ap asn1_m2ap asn1_m3ap asn1_x2ap)
# nr RRU
add_executable(oainr_ru
${OPENAIR_DIR}/executables/nr-ru.c
${OPENAIR_DIR}/openair1/PHY/INIT/nr_parms.c
${OPENAIR_DIR}/openair1/SCHED_NR/phy_frame_config_nr.c
${OPENAIR_DIR}/openair1/PHY/INIT/nr_parms.c
${OPENAIR_DIR}/openair1/SCHED_NR/nr_prach_procedures.c
${OPENAIR_DIR}/openair1/SCHED/phy_procedures_lte_common.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_prach.c
${OPENAIR_DIR}/common/utils/nr/nr_common.c
${OPENAIR_DIR}/radio/COMMON/common_lib.c
${OPENAIR_DIR}/radio/COMMON/record_player.c
${OPENAIR_DIR}/executables/softmodem-common.c
${OPENAIR_DIR}/executables/main_nr_ru.c
${OPENAIR_DIR}/executables/nr-oru.c
)
target_link_libraries(oainr_ru PRIVATE
-Wl,--start-group
UTIL SCHED_RU_LIB PHY_COMMON PHY_RU shlib_loader
-Wl,--end-group z dl)
target_link_libraries(oainr_ru PRIVATE pthread m CONFIG_LIB rt ${T_LIB} utils
barrier actor)
target_link_libraries(oainr_ru PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_phy_common time_management PHY_NR MAC_NR_COMMON)
# nr-softmodem
###################################################

View File

@@ -23,9 +23,9 @@
# -------
#
# Finds the xran library. Note that the library number is as follows:
# - oran_bronze_release_v1.1 -> 2.1.1 (B = second letter)
# - oran_e_maintenance_release_v1.0 -> 5.1.0
# the version is currently hardcoded to 5.1.0
# - oran_e_maintenance_release_v1.5 -> 5.1.6
# - oran_f_release_v1.3 -> 6.1.4
# - oran_k_release_v1.1 -> 11.1.1
#
# Required options
# ^^^^^^^^^^^^^^^^
@@ -107,6 +107,8 @@ if (xran_VERSION_STRING MATCHES "^oran_e_maintenance_release_v")
string(REGEX REPLACE "oran_e_maintenance_release_v([0-9]+).([0-9]+)" "5.\\1.\\2" xran_VERSION ${xran_VERSION_STRING})
elseif(xran_VERSION_STRING MATCHES "^oran_f_release_v")
string(REGEX REPLACE "oran_f_release_v([0-9]+).([0-9]+)" "6.\\1.\\2" xran_VERSION ${xran_VERSION_STRING})
elseif(xran_VERSION_STRING MATCHES "^oran_k_release_v")
string(REGEX REPLACE "oran_k_release_v([0-9]+).([0-9]+)" "11.\\1.\\2" xran_VERSION ${xran_VERSION_STRING})
elseif(xran_VERSION_STRING MATCHES "^oran_bronze_release_v")
string(REGEX REPLACE "oran_bronze_release_v([0-9]+).([0-9]+)" "2.\\1.\\2" xran_VERSION ${xran_VERSION_STRING})
else()

View File

@@ -0,0 +1,276 @@
diff --git a/fhi_lib/lib/api/xran_fh_o_ru.h b/fhi_lib/lib/api/xran_fh_o_ru.h
index 959479f..db8ef46 100644
--- a/fhi_lib/lib/api/xran_fh_o_ru.h
+++ b/fhi_lib/lib/api/xran_fh_o_ru.h
@@ -28,7 +28,7 @@
* @author Intel Corporation
*
**/
-
+#pragma once
#ifdef __cplusplus
extern "C" {
#endif
@@ -48,6 +48,7 @@ extern "C" {
#include <getopt.h>
#include <unistd.h>
#include "xran_fh_o_du.h"
+#include "xran_transport.h"
/**
* @ingroup
@@ -76,6 +77,24 @@ int32_t xran_5g_bfw_config(void * pHandle, struct xran_buffer_list *pSrcRxCpBuff
xran_transport_callback_fn pCallback,
void *pCallbackTag, uint8_t mu);
+enum xran_mbuf_mem_op_id {
+ MBUF_KEEP,
+ MBUF_FREE
+};
+
+typedef int (*process_uplane_fn)(struct rte_mbuf *pkt, void *handle,
+ struct xran_eaxc_info *p_cid,
+ uint16_t xport_id,
+ struct xran_sense_of_time *sense_of_time);
+typedef int32_t (*process_cplane_fn)(struct rte_mbuf *pkt, void *handle, uint16_t xport_id,
+ struct xran_sense_of_time *sense_of_time);
+
+void xran_hook_install(void *pHandle, process_uplane_fn process_uplane_fn_p,
+ void *process_uplane_fn_args,
+ process_cplane_fn process_cplane_fn_p,
+ void *process_cplane_fn_args, int mu);
+void xran_hook_schedule_packet(void *pHandle, struct rte_mbuf *mbuf, int port,
+ int slot, int symbol);
#ifdef __cplusplus
}
diff --git a/fhi_lib/lib/ethernet/xran_ethdi.h b/fhi_lib/lib/ethernet/xran_ethdi.h
index ddcae75..da6f344 100644
--- a/fhi_lib/lib/ethernet/xran_ethdi.h
+++ b/fhi_lib/lib/ethernet/xran_ethdi.h
@@ -129,11 +129,6 @@ struct xran_ethdi_ctx {
xran_lbm_port_info lbm_port_info[XRAN_VF_MAX];
};
-enum xran_mbuf_mem_op_id {
- MBUF_KEEP,
- MBUF_FREE
-};
-
extern enum xran_if_state xran_if_current_state;
inline struct xran_ethdi_ctx *xran_ethdi_get_ctx(void)
diff --git a/fhi_lib/lib/src/xran_dev.c b/fhi_lib/lib/src/xran_dev.c
index 675328d..2c5fe1c 100644
--- a/fhi_lib/lib/src/xran_dev.c
+++ b/fhi_lib/lib/src/xran_dev.c
@@ -23,6 +23,7 @@
* @author Intel Corporation
**/
+#include <rte_debug.h>
#define _GNU_SOURCE
#include <sched.h>
#include <assert.h>
@@ -57,6 +58,7 @@
#include "xran_ethdi.h"
#include "xran_ethernet.h"
#include "xran_printf.h"
+#include "xran_common.h"
struct xran_device_ctx *g_xran_dev_ctx[XRAN_PORTS_NUM]={NULL};
struct xran_system_config gSysCfg;
@@ -632,3 +634,86 @@ int xran_get_memstat(struct xran_memstat *stat)
return(0);
}
+
+
+#define MAX_PACKETS_SENT_PER_SYMBOL 16 // has to be power of 2
+
+// Process the scheduled packets, done once per symbol at OTA time
+void xran_hook_process_tx_packets(void* pHandle, int port, int slot, int symbol) {
+ struct xran_device_ctx *p_dev_ctx = (struct xran_device_ctx *)pHandle;
+ int ring_index = slot % XRAN_N_FE_BUF_LEN;
+ struct rte_ring *ring = p_dev_ctx->hook.tx_rings[port][ring_index][symbol];
+ void* mbufs[MAX_PACKETS_SENT_PER_SYMBOL];
+ int dequeued = rte_ring_dequeue_burst(ring, mbufs, MAX_PACKETS_SENT_PER_SYMBOL, NULL);
+ struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
+ struct rte_ring *tx_ring = ctx->tx_ring[port];
+ int enqueued = rte_ring_enqueue_burst(tx_ring, mbufs, dequeued, NULL);
+ if (enqueued != dequeued) {
+ rte_panic("Expected to be able to enqueue all the packets on the TX ring\n");
+ }
+}
+
+typedef struct {
+ void* pHandle;
+ int mu;
+ int port;
+} callback_args;
+
+int32_t send_packets(void* arg, struct xran_sense_of_time* p_sense_of_time) {
+ callback_args *cb_args = arg;
+ int slots_per_subframe[XRAN_MAX_NUM_MU] = {1, 2, 4, 8, 16};
+ int slots_in_frame = p_sense_of_time->nSlotIdx + p_sense_of_time->nSubframeIdx * slots_per_subframe[cb_args->mu];
+ xran_hook_process_tx_packets(cb_args->pHandle, cb_args->port, slots_in_frame, p_sense_of_time->nSymIdx);
+}
+
+void xran_hook_install(
+ void *pHandle,
+ process_uplane_fn process_uplane_fn_p,
+ void *process_uplane_fn_args,
+ process_cplane_fn process_cplane_fn_p,
+ void *process_cplane_fn_args,
+ int mu)
+{
+ static bool installed = false;
+ if (installed) rte_panic("Can only install once for one numerology\n");
+ installed = true;
+
+ struct xran_device_ctx *p_dev_ctx = (struct xran_device_ctx *)pHandle;
+ p_dev_ctx->hook.process_uplane_fn = process_uplane_fn_p;
+ p_dev_ctx->hook.process_uplane_fn_args = process_uplane_fn_args;
+ p_dev_ctx->hook.process_cplane_fn = process_cplane_fn_p;
+ p_dev_ctx->hook.process_cplane_fn_args = process_cplane_fn_args;
+
+ struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
+ for (int port = 0; port < ctx->io_cfg.num_vfs; port++) {
+ int ring_index = 0;
+ for (int slot = 0; slot < XRAN_N_FE_BUF_LEN; slot++) {
+ for (int symbol = 0; symbol < N_SYM_PER_SLOT; symbol++) {
+ char ring_name[RTE_RING_NAMESIZE];
+ snprintf(ring_name, RTE_DIM(ring_name), "%s_%d_%d", "hook_tx_sched_ring", port, ring_index++);
+ struct rte_ring *ring = rte_ring_create(ring_name, MAX_PACKETS_SENT_PER_SYMBOL, SOCKET_ID_ANY, RING_F_SC_DEQ);
+ if (ring == NULL) rte_panic("Cannot allocate rte_ring\n");
+ p_dev_ctx->hook.tx_rings[port][slot][symbol] = ring;
+ }
+ }
+ }
+
+ // Setup a callback each OTA symbol to send packets from per-symbol rings into the TX ring
+ static struct xran_sense_of_time xran_sense_of_time[N_SYM_PER_SLOT];
+ static callback_args cb_args;
+ cb_args.port = 0;
+ cb_args.mu = mu;
+ cb_args.pHandle = pHandle;
+ for (int i = 0; i < N_SYM_PER_SLOT; i++) {
+ xran_reg_sym_cb(pHandle, send_packets, &cb_args, &xran_sense_of_time[i], i, XRAN_CB_SYM_OTA_TIME, mu);
+ }
+}
+
+// Schedule packet for slot and symbol
+void xran_hook_schedule_packet(void *pHandle, struct rte_mbuf *mbuf, int port, int slot, int symbol)
+{
+ struct xran_device_ctx *p_dev_ctx = (struct xran_device_ctx *)pHandle;
+ struct rte_ring *ring = p_dev_ctx->hook.tx_rings[port][slot][symbol];
+ int res = rte_ring_enqueue(ring, mbuf);
+ if (res != 0) rte_panic("Cannot enqueue to ring");
+}
diff --git a/fhi_lib/lib/src/xran_dev.h b/fhi_lib/lib/src/xran_dev.h
index 5dad6a2..d5a455d 100644
--- a/fhi_lib/lib/src/xran_dev.h
+++ b/fhi_lib/lib/src/xran_dev.h
@@ -41,6 +41,7 @@ extern "C" {
#include <rte_spinlock.h>
#include "xran_fh_o_du.h"
+#include "xran_fh_o_ru.h"
#include "xran_prach_cfg.h"
#include "xran_up_api.h"
#include "xran_cp_api.h"
@@ -408,6 +409,17 @@ typedef struct xran_device_virtual_mu_fields_s {
xran_ssb_info ssbInfo;
} xran_device_virtual_mu_fields;
+typedef struct {
+ // Used to replace XRAN packet processing functions
+ process_uplane_fn process_uplane_fn;
+ void *process_uplane_fn_args;
+ process_cplane_fn process_cplane_fn;
+ void *process_cplane_fn_args;
+
+ // Used to schedule TX in the future.
+ struct rte_ring *tx_rings[XRAN_VF_MAX][XRAN_N_FE_BUF_LEN][XRAN_SYMBOLNUMBER_MAX];
+} hook_cfg;
+
typedef struct /* TO DO __rte_cache_aligned*/ xran_device_ctx
{
uint8_t sector_id;
@@ -537,6 +549,7 @@ typedef struct /* TO DO __rte_cache_aligned*/ xran_device_ctx
xran_sec_id_mu_map sectIdMUmap[2];
uint8_t sectIdMUmapWriteIndex; /* points to the sectIdMUmap entry that should be updated for a new packet */
#endif
+ hook_cfg hook;
} xran_device_ctx_t;
diff --git a/fhi_lib/lib/src/xran_main.c b/fhi_lib/lib/src/xran_main.c
index a9fd164..f838b43 100644
--- a/fhi_lib/lib/src/xran_main.c
+++ b/fhi_lib/lib/src/xran_main.c
@@ -2423,10 +2423,35 @@ int32_t xran_handle_rx_pkts(struct rte_mbuf* pkt_q[], uint16_t xport_id, struct
}
else
{
+ int numMUs = p_dev_ctx->fh_cfg.numMUs;
+ struct xran_sense_of_time sense_of_time[numMUs];
+ if (p_dev_ctx->hook.process_uplane_fn || p_dev_ctx->hook.process_cplane_fn) {
+ for (int i = 0; i < numMUs; i++) {
+ int mu = p_dev_ctx->fh_cfg.mu_number[i];
+ int32_t slots = xran_lib_ota_sym_idx_mu[mu] / XRAN_NUM_OF_SYMBOL_PER_SLOT;
+ int num_slots_per_frame = 10 << mu;
+ int num_slots_per_subframe = 1 << mu;
+ int frame = slots / num_slots_per_frame;
+ int subframe = (slots % num_slots_per_frame) % num_slots_per_subframe;
+ int slot = slots - frame * num_slots_per_frame - subframe * num_slots_per_subframe;
+ int symbol = xran_lib_ota_sym_idx_mu[mu] % XRAN_NUM_OF_SYMBOL_PER_SLOT;
+ sense_of_time[i].tti_counter = xran_lib_ota_sym_idx_mu[mu];
+ sense_of_time[i].nFrameIdx = xran_getSfnSecStart() + frame;
+ sense_of_time[i].nSymIdx = symbol;
+ sense_of_time[i].nSubframeIdx = subframe;
+ sense_of_time[i].nSlotIdx = slot;
+ sense_of_time[i].type_of_event = XRAN_CB_SYM_OTA_TIME;
+ sense_of_time[i].nSecond = xran_timingsource_get_current_second();
+ }
+ }
// uint64_t tt1 = MLogXRANTick();
for (i = 0; i < num_data; ++i)
{
- ret = process_mbuf(pkt_data[i], (void*)p_dev_ctx, p_cid);
+ if (p_dev_ctx->hook.process_uplane_fn) {
+ ret = p_dev_ctx->hook.process_uplane_fn(pkt_data[i], p_dev_ctx->hook.process_uplane_fn_args, p_cid, xport_id, sense_of_time);
+ } else {
+ ret = process_mbuf(pkt_data[i], (void*)p_dev_ctx, p_cid);
+ }
if (ret == MBUF_FREE)
rte_pktmbuf_free(pkt_data[i]);
}
@@ -2436,7 +2461,11 @@ int32_t xran_handle_rx_pkts(struct rte_mbuf* pkt_q[], uint16_t xport_id, struct
for (i = 0; i < num_control; ++i)
{
t1 = MLogXRANTick();
- ret = process_cplane(pkt_control[i], (void*)p_dev_ctx);
+ if (p_dev_ctx->hook.process_cplane_fn) {
+ ret = p_dev_ctx->hook.process_cplane_fn(pkt_data[i], p_dev_ctx->hook.process_cplane_fn_args, xport_id, sense_of_time);
+ } else {
+ ret = process_cplane(pkt_control[i], (void*)p_dev_ctx);
+ }
++p_dev_ctx->fh_counters.rx_counter;
if (ret == MBUF_FREE)
rte_pktmbuf_free(pkt_control[i]);
@@ -5033,9 +5062,11 @@ int32_t xran_start(void *pHandle)
for(j=0;j<pDevCtx_port->fh_cfg.numMUs;j++)
{
mu = pDevCtx_port->fh_cfg.mu_number[j];
- struct xran_prb_map * prbMap0 = (struct xran_prb_map *) pDevCtx_port->perMu[mu].sFrontHaulRxPrbMapBbuIoBufCtrl[0][0][0].sBufferList.pBuffers->pData;
- for(i = 0; i < XRAN_MAX_SECTIONS_PER_SLOT && i < prbMap0->nPrbElm; i++)
- pDevCtx_port->perMu[mu].numSetBFWs_arr[i] = prbMap0->prbMap[i].bf_weight.numSetBFWs;
+ if (pDevCtx_port->perMu[mu].sFrontHaulRxPrbMapBbuIoBufCtrl[0][0][0].sBufferList.pBuffers) {
+ struct xran_prb_map * prbMap0 = (struct xran_prb_map *) pDevCtx_port->perMu[mu].sFrontHaulRxPrbMapBbuIoBufCtrl[0][0][0].sBufferList.pBuffers->pData;
+ for(i = 0; i < XRAN_MAX_SECTIONS_PER_SLOT && i < prbMap0->nPrbElm; i++)
+ pDevCtx_port->perMu[mu].numSetBFWs_arr[i] = prbMap0->prbMap[i].bf_weight.numSetBFWs;
+ }
}
}
}

View File

@@ -0,0 +1,982 @@
diff --git a/fhi_lib/app/src/common.h b/fhi_lib/app/src/common.h
index 3819d8e..e7bfaa9 100644
--- a/fhi_lib/app/src/common.h
+++ b/fhi_lib/app/src/common.h
@@ -28,7 +28,7 @@
#include <rte_common.h>
#include <rte_mbuf.h>
-#define VERSIONX "#DIRTY#"
+#define VERSIONX "oran_k_release_v1.1"
#define APP_O_DU 0
#define APP_O_RU 1
diff --git a/fhi_lib/lib/Makefile b/fhi_lib/lib/Makefile
index d0c238c..d20c44f 100644
--- a/fhi_lib/lib/Makefile
+++ b/fhi_lib/lib/Makefile
@@ -23,20 +23,41 @@ MYCUSTOMSPACE1='------------------------------------------------------------'
##############################################################
# Tools configuration
##############################################################
-ifeq ($(WIRELESS_SDK_TOOLCHAIN),icc)
- CC := icc
- CPP := icpc
- AS := as
- AR := ar
- LD := icc
-else ifeq ($(WIRELESS_SDK_TOOLCHAIN),icx)
- CC := icx
- CPP := icpx
- AS := as
- AR := llvm-ar
- LD := icx
+
+# Default target architecture and compiler
+TARGET ?= x86
+
+# Architecture and compiler-specific tools and flags
+ifeq ($(TARGET), x86)
+ ifeq ($(WIRELESS_SDK_TOOLCHAIN),gcc)
+ CC := gcc
+ CPP := g++
+ AS := as
+ AR := ar
+ LD := gcc
+ else ifeq ($(WIRELESS_SDK_TOOLCHAIN),icc)
+ CC := icc
+ CPP := icpc
+ AS := as
+ AR := ar
+ LD := icc
+ else ifeq ($(WIRELESS_SDK_TOOLCHAIN),icx)
+ CC := icx
+ CPP := icpx
+ AS := as
+ AR := llvm-ar
+ LD := icx
+ else
+ $(error "Please define WIRELESS_SDK_TOOLCHAIN environment variable")
+ endif
+else ifeq ($(TARGET), armv8) # aarch64
+ CC := gcc
+ CPP := g++
+ LD := gcc
+ CFLAGS += -march=armv8-a
+ LDFLAGS +=
else
- $(error "Please define WIRELESS_SDK_TOOLCHAIN environment variable")
+ $(error Unsupported target architecture: $(TARGET))
endif
ifeq ($(WIRELESS_SDK_TARGET_ISA),avx512)
@@ -79,7 +100,7 @@ ifeq ($(RTE_SDK),)
endif
RTE_TARGET ?= x86_64-native-linux-icc
-RTE_INC := $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH):/usr/lib64/pkgconfig:$(RTE_SDK)/build/meson-uninstalled pkgconf --cflags-only-I libdpdk)
+RTE_INC := $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH):/usr/lib64/pkgconfig:$(RTE_SDK)/build/meson-uninstalled pkg-config --cflags-only-I libdpdk)
API_DIR := $(PROJECT_DIR)/api
SRC_DIR := $(PROJECT_DIR)/src
@@ -110,22 +131,23 @@ CC_SRC = $(ETH_DIR)/xran_ethdi.c \
$(SRC_DIR)/xran_main.c \
$(SRC_DIR)/xran_delay_measurement.c
-CPP_SRC = $(SRC_DIR)/xran_compression.cpp \
- $(SRC_DIR)/xran_bfp_ref.cpp \
- $(SRC_DIR)/xran_bfp_cplane8.cpp \
- $(SRC_DIR)/xran_bfp_cplane16.cpp \
- $(SRC_DIR)/xran_bfp_cplane32.cpp \
- $(SRC_DIR)/xran_bfp_cplane64.cpp \
- $(SRC_DIR)/xran_bfp_uplane.cpp \
- $(SRC_DIR)/xran_mod_compression.cpp
-
-CPP_SRC_SNC = $(SRC_DIR)/xran_compression_snc.cpp \
- $(SRC_DIR)/xran_bfp_cplane8_snc.cpp \
- $(SRC_DIR)/xran_bfp_cplane16_snc.cpp \
- $(SRC_DIR)/xran_bfp_cplane32_snc.cpp \
- $(SRC_DIR)/xran_bfp_cplane64_snc.cpp \
- $(SRC_DIR)/xran_bfp_uplane_snc.cpp \
- $(SRC_DIR)/xran_bfp_uplane_spr.cpp
+ifeq ($(TARGET), x86)
+ CPP_SRC = $(SRC_DIR)/xran_compression.cpp \
+ $(SRC_DIR)/xran_bfp_ref.cpp \
+ $(SRC_DIR)/xran_bfp_cplane8.cpp \
+ $(SRC_DIR)/xran_bfp_cplane16.cpp \
+ $(SRC_DIR)/xran_bfp_cplane32.cpp \
+ $(SRC_DIR)/xran_bfp_cplane64.cpp \
+ $(SRC_DIR)/xran_bfp_uplane.cpp
+
+ CPP_SRC_SNC = $(SRC_DIR)/xran_compression_snc.cpp \
+ $(SRC_DIR)/xran_bfp_cplane8_snc.cpp \
+ $(SRC_DIR)/xran_bfp_cplane16_snc.cpp \
+ $(SRC_DIR)/xran_bfp_cplane32_snc.cpp \
+ $(SRC_DIR)/xran_bfp_cplane64_snc.cpp \
+ $(SRC_DIR)/xran_bfp_uplane_snc.cpp \
+ $(SRC_DIR)/xran_bfp_uplane_spr.cpp
+endif
CC_FLAGS += -std=gnu11 -Wall -Wno-deprecated-declarations \
-fdata-sections \
@@ -134,7 +156,11 @@ CC_FLAGS += -std=gnu11 -Wall -Wno-deprecated-declarations \
-fPIC \
-Wall \
-Wimplicit-function-declaration \
- -g -O3 -mcmodel=large
+ -g -O
+
+ifeq ($(TARGET), x86)
+CC_FLAGS += -mavx512bw -march=skylake-avx512 -mtune=skylake-avx512
+endif
ifeq ($(WIRELESS_SDK_TOOLCHAIN),icc)
CC_FLAGS += -wd1786 -restrict
@@ -148,9 +174,15 @@ ifeq ($(WIRELESS_SDK_TARGET_ISA),spr)
CC_FLAGS += -D_BBLIB_SPR_ -qopt-zmm-usage=high
endif
-CPP_FLAGS := -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D_GNU_SOURCE -D_REENTRANT -pipe \
- -falign-functions=16 \
- -Werror -Wno-unused-variable -std=c++14 -mcmodel=large -fPIC
+ifeq ($(TARGET), x86)
+ CPP_FLAGS := -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D_GNU_SOURCE -D_REENTRANT -pipe \
+ -fPIC \
+ -falign-functions=16 \
+ -Werror -Wno-unused-variable -std=c++14 -mcmodel=large -mavx512bw -march=skylake-avx512 -mtune=skylake-avx512
+else ifeq ($(TARGET), armv8)
+ CPP_FLAGS := -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D_GNU_SOURCE -D_REENTRANT -pipe \
+ -Werror -Wno-unused-variable -std=c++14
+endif
ifeq ($(WIRELESS_SDK_TOOLCHAIN),icc)
CPP_FLAGS += -fp-model fast=2 -no-prec-div -no-prec-sqrt -fast-transcendentals -restrict
@@ -164,7 +196,7 @@ ifeq ($(WIRELESS_SDK_TARGET_ISA),spr)
CPP_FLAGS += -D_BBLIB_SPR_ -qopt-zmm-usage=high
endif
-INC := -I$(API_DIR) -I$(ETH_DIR) -I$(SRC_DIR) -I$(RTE_INC)
+INC := -I$(API_DIR) -I$(ETH_DIR) -I$(SRC_DIR) $(RTE_INC)
DEF :=
ifeq ($(MLOG),1)
INC += -I$(MLOG_DIR)/source
@@ -210,8 +242,13 @@ CPP_SNC_OBJTARGETS := $(addprefix $(PROJECT_OBJ_DIR)/,$(CPP_OBJS_SNC))
AS_OBJTARGETS := $(addprefix $(PROJECT_OBJ_DIR)/,$(AS_OBJS))
#-qopt-report=5 -qopt-matmul -qopt-report-phase=all
-CPP_COMP := -O3 -DNDEBUG -fPIE -fasm-blocks
-CPP_COMP_SNC := -O3 -DNDEBUG -fPIE -fasm-blocks
+ifeq ($(TARGET), x86)
+ CPP_COMP := -O3 -DNDEBUG -fPIE
+ CPP_COMP_SNC := -O3 -DNDEBUG -march=icelake-server -fPIE
+else ifeq ($(TARGET), armv8)
+ CPP_COMP := -O3 -DNDEBUG -fPIE -Wrestrict
+ CPP_COMP_SNC := -O3 -DNDEBUG -march=icelake-server -fPIE -Wrestrict
+endif
CC_FLAGS_FULL := $(CC_FLAGS) $(INC) $(DEF)
CPP_FLAGS_FULL := $(CPP_FLAGS) $(CPP_COMP) $(INC) $(DEF)
CPP_FLAGS_FULL_SNC := $(CPP_FLAGS) $(CPP_COMP_SNC) $(INC) $(DEF)
diff --git a/fhi_lib/lib/api/xran_fh_o_du.h b/fhi_lib/lib/api/xran_fh_o_du.h
index 1261fa0..5d4f942 100644
--- a/fhi_lib/lib/api/xran_fh_o_du.h
+++ b/fhi_lib/lib/api/xran_fh_o_du.h
@@ -158,7 +158,7 @@ extern "C" {
#define XRAN_SSB_MAX_NUM_SC (240) /**< 3GPP TS 38.211 - 7.4.3.1 Time-frequency structure of an SS/PBCH block */
#define XRAN_SSB_MAX_NUM_PRB (XRAN_SSB_MAX_NUM_SC / XRAN_NUM_OF_SC_PER_RB)
-#define XRAN_MAX_FRAGMENT (2) /**< Max number of fragmentations in single symbol */
+#define XRAN_MAX_FRAGMENT (6) /**< Max number of fragmentations in single symbol */
#define XRAN_MAX_RX_PKT_PER_SYM (32) /**< Max number of packets received in single symbol */
#define XRAN_MAX_SET_BFWS (64) /**< Assumed 64Ant, BFP 9bit with 9K jumbo frame */
@@ -1800,7 +1800,7 @@ int32_t xran_start(void *pHandle);
* @return
* 0 - on success
*/
-int32_t xran_activate_cc(int32_t port_id, int32_t cc_id);
+int32_t xran_activate_cc(void *pHandle, int32_t cc_id);
/**
* @ingroup xran
@@ -1816,7 +1816,7 @@ int32_t xran_activate_cc(int32_t port_id, int32_t cc_id);
* @return
* 0 - on success
*/
-int32_t xran_deactivate_cc(int32_t port_id, int32_t cc_id);
+int32_t xran_deactivate_cc(void *pHandle, int32_t cc_id);
/**
* @ingroup xran
diff --git a/fhi_lib/lib/api/xran_pkt_cp.h b/fhi_lib/lib/api/xran_pkt_cp.h
index 0c690a1..8b67b67 100644
--- a/fhi_lib/lib/api/xran_pkt_cp.h
+++ b/fhi_lib/lib/api/xran_pkt_cp.h
@@ -33,6 +33,14 @@
extern "C" {
#endif
+#include <stdint.h>
+#if defined(__arm__) || defined(__aarch64__)
+#include <arm_neon.h>
+typedef int32x4_t simd_data_t;
+#else
+#include <xmmintrin.h>
+typedef __m128i simd_data_t;
+#endif
/**********************************************************************
* Common structures for C/U-plane
@@ -256,7 +264,7 @@ union xran_cp_radioapp_section_ext3_first {
}all_bits;
struct{
- __m128i data_field1;
+ simd_data_t data_field1;
}data_field;
} __attribute__((__packed__));
diff --git a/fhi_lib/lib/api/xran_timer.h b/fhi_lib/lib/api/xran_timer.h
index 2efb9dc..fa628a8 100644
--- a/fhi_lib/lib/api/xran_timer.h
+++ b/fhi_lib/lib/api/xran_timer.h
@@ -119,12 +119,30 @@ inline unsigned long get_ticks_diff(unsigned long curr_tick, unsigned long last_
return (unsigned long)(0xFFFFFFFFFFFFFFFF - last_tick + curr_tick);
}
+#if defined(__x86_64__)
inline uint64_t xran_tick(void)
{
uint32_t hi, lo;
__asm volatile ("rdtsc" : "=a"(lo), "=d"(hi));
return ( (uint64_t)lo)|( ((uint64_t)hi)<<32 );
}
+#elif defined(__aarch64__)
+#include <sys/time.h>
+inline uint64_t xran_tick(void) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;
+}
+#elif defined(__arm__)
+#include <time.h>
+inline uint64_t xran_tick(void) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (uint64_t)ts.tv_sec * 1000000000LL + ts.tv_nsec;
+}
+#else
+#error "Unsupported architecture"
+#endif
int xran_timingsource_set_gpsoffset(int64_t offset_sec, int64_t offset_nsec);
//uint32_t xran_timingsource_get_coreid(void);
diff --git a/fhi_lib/lib/api/xran_up_api.h b/fhi_lib/lib/api/xran_up_api.h
index 28dfb89..c267278 100644
--- a/fhi_lib/lib/api/xran_up_api.h
+++ b/fhi_lib/lib/api/xran_up_api.h
@@ -80,6 +80,7 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
uint8_t *subframe_id,
uint8_t *slot_id,
uint8_t *symb_id,
+ uint8_t *filter_id,
union ecpri_seq_id *seq_id,
uint16_t *num_prbu,
uint16_t *start_prbu,
@@ -90,7 +91,8 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
enum xran_comp_hdr_type staticComp,
uint8_t *compMeth,
uint8_t *iqWidth,
- uint8_t oxu_port_id);
+ uint8_t oxu_port_id,
+ uint8_t *is_prach);
int32_t xran_extract_iq_samples_dataheader(struct rte_mbuf *mbuf,
void **iq_data_start,
diff --git a/fhi_lib/lib/ethernet/xran_ethdi.c b/fhi_lib/lib/ethernet/xran_ethdi.c
index a4f4f0d..04028d2 100644
--- a/fhi_lib/lib/ethernet/xran_ethdi.c
+++ b/fhi_lib/lib/ethernet/xran_ethdi.c
@@ -37,7 +37,10 @@
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
+#if defined(__arm__) || defined(__aarch64__)
+#else
#include <immintrin.h>
+#endif
#include <numa.h>
#include <rte_config.h>
#include <rte_common.h>
@@ -371,8 +374,8 @@ int32_t xran_ethdi_init_dpdk(char *name, char *vfio_name, struct xran_io_cfg *io
char bbdev_vdev_aux[XRAN_MAX_AUX_BBDEV_NUM][32];
char vfio_token[64] = "";
char iova_mode[32] = "--iova-mode=pa";
- char socket_mem[32] = "--socket-mem=8192";
- char socket_limit[32] = "--socket-limit=8192";
+ char socket_mem[32] = "--socket-mem=0";
+ char socket_limit[32] = "--socket-limit=0";
uint32_t cpu = 0;
uint32_t node = 0;
@@ -488,8 +491,11 @@ int32_t xran_ethdi_init_dpdk(char *name, char *vfio_name, struct xran_io_cfg *io
}
printf("\n");
+#if defined(__arm__) || defined(__aarch64__)
+#else
if(rte_vect_set_max_simd_bitwidth(RTE_VECT_SIMD_512) < 0)
rte_panic("Cannot init RTE_VECT_SIMD_512: %s\n", rte_strerror(rte_errno));
+#endif
/* This will return on system_core, which is not necessarily the
* one we're on right now. */
@@ -567,11 +573,13 @@ int32_t xran_ethdi_init_dpdk_ports(struct xran_io_cfg *io_cfg,
ctx->tx_ring[i] = rte_ring_create(ring_name, NUM_MBUFS_RING_TRX,
rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);
PANIC_ON(ctx->tx_ring[i] == NULL, "failed to allocate rx ring");
+ printf("Created ring %s on core %d\n", ring_name, *lcore_id);
for(qi = 0; qi < io_cfg->num_rxq; qi++) {
snprintf(ring_name, RTE_DIM(ring_name), "%s_%d_%d_%d", "rx_ring_cp", i, qi, port[i]);
ctx->rx_ring[i][qi] = rte_ring_create(ring_name, NUM_MBUFS_RING_TRX,
rte_lcore_to_socket_id(*lcore_id), RING_F_SP_ENQ);
PANIC_ON(ctx->rx_ring[i][qi] == NULL, "failed to allocate rx ring");
+ printf("Created ring %s on core %d\n",ring_name,*lcore_id);
}
}
} else {
@@ -640,7 +648,7 @@ int32_t xran_ethdi_init_dpdk_ports(struct xran_io_cfg *io_cfg,
snprintf(ring_name, RTE_DIM(ring_name), "%s_%d_%d", "dl_gen_ring_up", i,io_cfg->nDpdkProcessID);
ctx->up_dl_pkt_gen_ring[i] = rte_ring_create(ring_name, NUM_MBUFS_RING, rte_lcore_to_socket_id(*lcore_id), /*RING_F_SC_DEQ*/0);
PANIC_ON(ctx->up_dl_pkt_gen_ring[i] == NULL, "failed to allocate dl gen ring");
- printf("created %s\n", ring_name);
+ printf("created %s on core %d\n", ring_name, *lcore_id);
}
return 1;
diff --git a/fhi_lib/lib/ethernet/xran_ethernet.c b/fhi_lib/lib/ethernet/xran_ethernet.c
index b8ce4ee..05857f7 100644
--- a/fhi_lib/lib/ethernet/xran_ethernet.c
+++ b/fhi_lib/lib/ethernet/xran_ethernet.c
@@ -37,7 +37,10 @@
#include <sys/types.h>
#include <stdlib.h>
#include <math.h>
+#if defined(__arm__) || defined(__aarch64__)
+#else
#include <immintrin.h>
+#endif
#include <rte_config.h>
#include <rte_common.h>
diff --git a/fhi_lib/lib/src/xran_bfp_byte_packing_utils.hpp b/fhi_lib/lib/src/xran_bfp_byte_packing_utils.hpp
index 483efb3..bf170a2 100644
--- a/fhi_lib/lib/src/xran_bfp_byte_packing_utils.hpp
+++ b/fhi_lib/lib/src/xran_bfp_byte_packing_utils.hpp
@@ -894,7 +894,7 @@ namespace BlockFloatCompander
/// Mask to zero unwanted bits
const __m256i k_expMask = _mm256_set1_epi16(0xFFFC);
- return _mm256_and_epi64(compDataCombined, k_expMask);
+ return _mm256_and_si256(compDataCombined, k_expMask);
}
}
diff --git a/fhi_lib/lib/src/xran_bfp_uplane.cpp b/fhi_lib/lib/src/xran_bfp_uplane.cpp
index 7b70bf2..f412868 100644
--- a/fhi_lib/lib/src/xran_bfp_uplane.cpp
+++ b/fhi_lib/lib/src/xran_bfp_uplane.cpp
@@ -89,7 +89,7 @@ namespace BFP_UPlane
{
const __m512i* rawData = reinterpret_cast<const __m512i*>(dataIn.dataExpanded);
/// Abs
- const auto rawDataAbs = _mm512_abs_epi16(rawData[0]);
+ const auto rawDataAbs = _mm512_abs_epi16(_mm512_loadu_epi16(rawData));
/// No need to do a full horizontal max operation here, just do a max IQ step,
/// compute the exponents and then use a reduce max over all exponent values. This
/// is the fastest way to handle a single RB.
@@ -431,4 +431,4 @@ BlockFloatCompander::BFPExpandUserPlaneAvx512(const CompressedData& dataIn, Expa
BFP_UPlane::expandByAllocN<BlockFloatCompander::networkByteUnpack12b>(dataIn, dataOut, k_totNumBytesPerRB12, k_maxExpShift12);
break;
}
-}
\ No newline at end of file
+}
diff --git a/fhi_lib/lib/src/xran_cb_proc.c b/fhi_lib/lib/src/xran_cb_proc.c
index 56db2bf..35010d5 100644
--- a/fhi_lib/lib/src/xran_cb_proc.c
+++ b/fhi_lib/lib/src/xran_cb_proc.c
@@ -25,7 +25,10 @@
#include <unistd.h>
#include <stdio.h>
+#if defined(__arm__) || defined(__aarch64__)
+#else
#include <immintrin.h>
+#endif
#include <rte_common.h>
#include <rte_eal.h>
#include <rte_errno.h>
diff --git a/fhi_lib/lib/src/xran_common.c b/fhi_lib/lib/src/xran_common.c
index 5613646..f1d0f87 100644
--- a/fhi_lib/lib/src/xran_common.c
+++ b/fhi_lib/lib/src/xran_common.c
@@ -31,7 +31,10 @@
#include <sys/time.h>
#include <time.h>
#include <pthread.h>
+#if defined(__arm__) || defined(__aarch64__)
+#else
#include <immintrin.h>
+#endif
#include <rte_mbuf.h>
#include <stdio.h>
#include <stdbool.h>
@@ -967,11 +970,14 @@ int32_t process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *
uint8_t compMeth = 0;
uint8_t iqWidth = 0;
+ uint8_t is_prach = 0;
+
int ret = MBUF_FREE;
uint32_t mb_free = 0;
int32_t valid_res = 0;
int expect_comp = (p_dev_ctx->fh_cfg.ru_conf.compMeth != XRAN_COMPMETHOD_NONE);
enum xran_comp_hdr_type staticComp = p_dev_ctx->fh_cfg.ru_conf.xranCompHdrType;
+ uint8_t filter_id;
#ifdef POLL_EBBU_OFFLOAD
PXRAN_TIMER_CTX pCtx = xran_timer_get_ctx_ebbu_offload();
@@ -991,9 +997,9 @@ int32_t process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *
return MBUF_FREE;
num_bytes = xran_extract_iq_samples(pkt, &iq_samp_buf,
- &CC_ID, &Ant_ID, &frame_id, &subframe_id, &slot_id, &symb_id, &seq,
+ &CC_ID, &Ant_ID, &frame_id, &subframe_id, &slot_id, &symb_id, &filter_id, &seq,
&num_prbu, &start_prbu, &sym_inc, &rb, &sect_id,
- expect_comp, staticComp, &compMeth, &iqWidth, XRAN_GET_OXU_PORT_ID(p_dev_ctx));
+ expect_comp, staticComp, &compMeth, &iqWidth, XRAN_GET_OXU_PORT_ID(p_dev_ctx), &is_prach);
if (unlikely(num_bytes <= 0))
{
print_err("num_bytes is wrong [%d]\n", num_bytes);
@@ -1128,6 +1134,9 @@ int32_t process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *
} /* else if (Ant_ID >= p_dev_ctx->srs_cfg.srsEaxcOffset ...... */
else
{
+ pCnt->rx_counter++;
+ pCnt->Rx_on_time++;
+ pCnt->Total_msgs_rcvd++;
struct xran_prach_cp_config *PrachCfg = NULL;
if(p_dev_ctx->dssEnable)
@@ -1143,9 +1152,7 @@ int32_t process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *
PrachCfg = &(p_dev_ctx->perMu[mu].PrachCPConfig);
}
- if (Ant_ID >= PrachCfg->prachEaxcOffset
- && Ant_ID < (PrachCfg->prachEaxcOffset +xran_get_num_eAxc(p_dev_ctx))
- && p_dev_ctx->fh_cfg.perMu[mu].prachEnable)
+ if (p_dev_ctx->fh_cfg.perMu[mu].prachEnable && is_prach)
{
if(p_dev_ctx->fh_cfg.ru_conf.xranTech == XRAN_RAN_5GNR)
{
@@ -1992,8 +1999,7 @@ int32_t ring_processing_func(void* args)
rte_timer_manage();
#endif
- if (process_ring(ctx->rx_ring[i][qi], i, qi))
- return 0;
+ process_ring(ctx->rx_ring[i][qi], i, qi);
}
// }
}
diff --git a/fhi_lib/lib/src/xran_compression.cpp b/fhi_lib/lib/src/xran_compression.cpp
index c35f7cd..437326b 100644
--- a/fhi_lib/lib/src/xran_compression.cpp
+++ b/fhi_lib/lib/src/xran_compression.cpp
@@ -52,16 +52,7 @@ struct xran_lib_compander_for_isa
{
xran_lib_compander_for_isa() {
if (gCpuCapability == -1) {
-#ifdef _BBLIB_SPR_
- if (_may_i_use_cpu_feature(_FEATURE_F16C)) {
- gCpuCapability = 2;
- } else
-#endif
- if (_may_i_use_cpu_feature(_FEATURE_AVX512IFMA52)) {
- gCpuCapability = 1;
- } else {
- gCpuCapability = 0;
- }
+ gCpuCapability = 0;
}
printf("xran_lib_compander_for_isa: %d\n", gCpuCapability);
@@ -89,11 +80,7 @@ xranlib_compress(const struct xranlib_compress_request *request,
return xranlib_5gnr_mod_compression(&mod_request, &mod_response);
}
else{
- if(XRANLIB_COMPAND_CHECK_CPU_CAPABILITY()) {
- return xranlib_compress_avxsnc(request,response);
- } else {
- return xranlib_compress_avx512(request,response);
- }
+ return xranlib_compress_avx512(request,response);
}
}
@@ -118,8 +105,6 @@ xranlib_decompress(const struct xranlib_decompress_request *request,
else{
if((gCpuCapability == 2)&&(request->SprEnable == 1)) {
return xranlib_decompress_5gisa(request,response);
- } else if(XRANLIB_COMPAND_CHECK_CPU_CAPABILITY()) {
- return xranlib_decompress_avxsnc(request,response);
} else {
return xranlib_decompress_avx512(request,response);
}
@@ -191,22 +176,14 @@ int32_t
xranlib_compress_bfw(const struct xranlib_compress_request *request,
struct xranlib_compress_response *response)
{
- if(XRANLIB_COMPAND_CHECK_CPU_CAPABILITY()) {
- return xranlib_compress_avxsnc_bfw(request,response);
- } else {
- return xranlib_compress_avx512_bfw(request,response);
- }
+ return xranlib_compress_avx512_bfw(request,response);
}
int32_t
xranlib_decompress_bfw(const struct xranlib_decompress_request *request,
struct xranlib_decompress_response *response)
{
- if(XRANLIB_COMPAND_CHECK_CPU_CAPABILITY()) {
- return xranlib_decompress_avxsnc_bfw(request,response);
- } else {
- return xranlib_decompress_avx512_bfw(request,response);
- }
+ return xranlib_decompress_avx512_bfw(request,response);
}
int32_t
diff --git a/fhi_lib/lib/src/xran_cp_api.c b/fhi_lib/lib/src/xran_cp_api.c
index 92a1edf..47e4afb 100644
--- a/fhi_lib/lib/src/xran_cp_api.c
+++ b/fhi_lib/lib/src/xran_cp_api.c
@@ -25,7 +25,11 @@
* @author Intel Corporation
*
**/
+#if defined(__arm__) || defined(__aarch64__)
+#include <arm_neon.h>
+#else
#include <immintrin.h>
+#endif
#include <rte_branch_prediction.h>
#include <rte_malloc.h>
@@ -839,7 +843,11 @@ xran_prepare_sectionext_3(struct rte_mbuf *mbuf, struct xran_sectionext3_info *p
| (params->layerId << xran_cp_radioapp_sec_ext3_LayerId)
| (params->numLayers << xran_cp_radioapp_sec_ext3_NumLayers);
data_fourth_byte = params->beamIdAP1;
+#if defined(__arm__) || defined(__aarch64__)
+ ext3_f->data_field.data_field1 = (int32x4_t){data_first_byte, data_second_byte, data_third_byte, data_fourth_byte};
+#else
ext3_f->data_field.data_field1 = _mm_set_epi32(data_fourth_byte, data_third_byte, data_second_byte, data_first_byte);
+#endif
/* convert byte order */
tmp = (uint64_t *)ext3_f;
diff --git a/fhi_lib/lib/src/xran_cp_proc.c b/fhi_lib/lib/src/xran_cp_proc.c
index 52c9e72..d1e7dad 100644
--- a/fhi_lib/lib/src/xran_cp_proc.c
+++ b/fhi_lib/lib/src/xran_cp_proc.c
@@ -35,7 +35,10 @@
#include <stdio.h>
#include <pthread.h>
#include <malloc.h>
+#if defined(__arm__) || defined(__aarch64__)
+#else
#include <immintrin.h>
+#endif
#include <rte_common.h>
#include <rte_eal.h>
@@ -640,7 +643,7 @@ int generate_cpmsg_prach(void *pHandle, struct xran_cp_gen_params *params, struc
if(XRAN_FILTERINDEX_PRACH_ABC == pPrachCPConfig->filterIdx)
{
timeOffset = timeOffset >> nNumerology; //original number is Tc, convert to Ts based on mu
- if ((slot_id == 0) || (slot_id == (SLOTNUM_PER_SUBFRAME(xran_fs_get_tti_interval(mu)) >> 1)))
+ if (startSymId > 0 && ((slot_id == 0) || (slot_id == (SLOTNUM_PER_SUBFRAME(xran_fs_get_tti_interval(mu)) >> 1))))
timeOffset += 16;
}
else
diff --git a/fhi_lib/lib/src/xran_delay_measurement.c b/fhi_lib/lib/src/xran_delay_measurement.c
index d8ffe60..b7b4c41 100644
--- a/fhi_lib/lib/src/xran_delay_measurement.c
+++ b/fhi_lib/lib/src/xran_delay_measurement.c
@@ -23,7 +23,10 @@
* @author Intel Corporation
**/
#define _GNU_SOURCE
+#if defined(__arm__) || defined(__aarch64__)
+#else
#include <immintrin.h>
+#endif
#include <assert.h>
#include <err.h>
#include <arpa/inet.h>
diff --git a/fhi_lib/lib/src/xran_dev.c b/fhi_lib/lib/src/xran_dev.c
index 5956ca4..675328d 100644
--- a/fhi_lib/lib/src/xran_dev.c
+++ b/fhi_lib/lib/src/xran_dev.c
@@ -35,7 +35,10 @@
#include <stdio.h>
#include <pthread.h>
#include <malloc.h>
+#if defined(__arm__) || defined(__aarch64__)
+#else
#include <immintrin.h>
+#endif
#include <rte_common.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
diff --git a/fhi_lib/lib/src/xran_main.c b/fhi_lib/lib/src/xran_main.c
index 256fa1d..a9fd164 100644
--- a/fhi_lib/lib/src/xran_main.c
+++ b/fhi_lib/lib/src/xran_main.c
@@ -36,7 +36,11 @@
#include <stdio.h>
#include <pthread.h>
#include <malloc.h>
+#if defined(__arm__) || defined(__aarch64__)
+#include <arm_neon.h>
+#else
#include <immintrin.h>
+#endif
#include <numa.h>
#include <rte_common.h>
#include <rte_eal.h>
@@ -122,6 +126,25 @@ int32_t xran_pkt_gen_desc_free(struct cp_up_tx_desc *p_desc);
int32_t xran_pkt_gen_process_ring(struct rte_ring *r);
int32_t xran_dl_pkt_ring_processing_func(void* args);
+void *mm_allocate_handle(size_t size, size_t alignment) {
+ void *ptr = NULL;
+#if defined(__arm__) || defined(__aarch64__)
+ // ARM-specific memory allocation
+ if (posix_memalign(&ptr, alignment, size) != 0) {
+ fprintf(stderr, "posix_memalign: allocation error\n");
+ return NULL;
+ }
+#else
+ // Intel-specific memory allocation
+ ptr = _mm_malloc(size, alignment);
+ if (ptr == NULL) {
+ fprintf(stderr, "_mm_malloc: allocation error\n");
+ return NULL;
+ }
+#endif
+ return ptr;
+}
+
void
xran_updateSfnSecStart(void)
{
@@ -334,8 +357,8 @@ int32_t xran_init_prach_lte(struct xran_fh_config* pConf, struct xran_device_ctx
pDevCtx->prach_start_symbol[0], pDevCtx->prach_last_symbol[0]);
}
- pPrachCPConfig->prachEaxcOffset = xran_get_num_eAxc(pDevCtx);
- print_dbg("PRACH: eAxC_offset %d\n", pPrachCPConfig->prachEaxcOffset);
+ pPrachCPConfig->prachEaxcOffset = pPRACHConfig->prachEaxcOffset;
+ print_dbg("PRACH: prachEaxcOffset %d\n", pPrachCPConfig->prachEaxcOffset);
/* Save some configs for app */
pPRACHConfig->startSymId = pPrachCPConfig->startSymId;
pPRACHConfig->lastSymId = pPrachCPConfig->startSymId + pPrachCPConfig->numSymbol * pPrachCPConfig->occassionsInPrachSlot - 1;
@@ -611,6 +634,11 @@ void xran_process_nbiot_prach_cp(struct xran_device_ctx * pDevCtx, uint8_t mu)
uint8_t seqid = xran_get_cp_seqid(pDevCtx, XRAN_DIR_UL, ccId, portId);
uint16_t beam_id = xran_get_beamid(pDevCtx, XRAN_DIR_UL, ccId, portId, 0);
+ uint8_t bufId = tti % XRAN_N_FE_BUF_LEN;
+ struct xran_buffer_list *pBufList = &(pDevCtx->perMu[mu].sFrontHaulRxPrbMapBbuIoBufCtrl[bufId][ccId][antId].sBufferList);
+ struct xran_prb_map *prbMap = pBufList->pBuffers->pData;
+ struct xran_prb_elm *pPrbElm = &prbMap->prbMap[0]; //mjoang
+ beam_id = pPrbElm->nBeamIndex;
ret = generate_cpmsg_prach(pDevCtx, &params, sect_geninfo, mbuf, pDevCtx,
frameId, sfId, 0, tti,
beam_id, ccId, portId, 0, seqid, mu, sym_id);
@@ -1880,6 +1908,10 @@ xran_prepare_cp_ul_slot(uint16_t xran_port_id, uint32_t nSlotIdx, uint32_t nCcS
uint8_t seqid = xran_get_cp_seqid(pHandle, XRAN_DIR_UL, ccId, portId);
beam_id = xran_get_beamid(pHandle, XRAN_DIR_UL, ccId, portId, slotId);
+ pBufList = &(pDevCtx->perMu[mu].sFrontHaulRxPrbMapBbuIoBufCtrl[bufId][ccId][antId].sBufferList);
+ struct xran_prb_map *prbMap = pBufList->pBuffers->pData;
+ struct xran_prb_elm *pPrbElm = &prbMap->prbMap[0]; //mjoang
+ beam_id = pPrbElm->nBeamIndex;
ret = generate_cpmsg_prach(pHandle, &params, sect_geninfo, mbuf, pDevCtx,
frameId, sfId, slotId, tti,
beam_id, ccId, portId, occasionid, seqid, mu, 0);
@@ -2128,6 +2160,10 @@ void tx_cp_ul_cb(struct rte_timer *tim, void *arg)
uint8_t seqid = xran_get_cp_seqid(pHandle, XRAN_DIR_UL, ccId, portId);
beam_id = xran_get_beamid(pHandle, XRAN_DIR_UL, ccId, portId, slotId);
+ pBufList = &(pDevCtx->perMu[mu].sFrontHaulRxPrbMapBbuIoBufCtrl[bufId][ccId][antId].sBufferList);
+ struct xran_prb_map *prbMap = pBufList->pBuffers->pData;
+ struct xran_prb_elm *pPrbElm = &prbMap->prbMap[0]; //mjoang
+ beam_id = pPrbElm->nBeamIndex;
ret = generate_cpmsg_prach(pHandle, &params, sect_geninfo, mbuf, pDevCtx,
frameId, sfId, slotId, tti,
beam_id, ccId, portId, occasionid, seqid, mu, 0);
@@ -2309,16 +2345,21 @@ int32_t xran_handle_rx_pkts(struct rte_mbuf* pkt_q[], uint16_t xport_id, struct
// ECPRI payload validation
if(likely(sysCfg->rru_workaround == 0))
{
- if(unlikely(expected_ecpri_payload != (rte_pktmbuf_pkt_len(pkt) - sizeof(union xran_ecpri_cmn_hdr))))
- {
- ++p_dev_ctx->fh_counters.rx_err_ecpri;
- ++p_dev_ctx->fh_counters.rx_err_drop;
- ++p_dev_ctx->fh_counters.rx_counter;
- rte_pktmbuf_free(pkt);
- continue;
+ uint16_t size_tail = (rte_pktmbuf_pkt_len(pkt) - sizeof(union xran_ecpri_cmn_hdr)) - expected_ecpri_payload;
+ if(size_tail > 0) {
+ int trim_ret = rte_pktmbuf_trim(pkt, size_tail);
+ if(unlikely(trim_ret != 0))
+ {
+ ++p_dev_ctx->fh_counters.rx_err_ecpri;
+ ++p_dev_ctx->fh_counters.rx_err_drop;
+ ++p_dev_ctx->fh_counters.rx_counter;
+ rte_pktmbuf_free(pkt);
+ continue;
+ }
}
}
pkt_data[num_data++] = pkt;
+ uint8_t *pkt_bytes = rte_pktmbuf_mtod(pkt, uint8_t*);
break;
// For RU emulation
case ECPRI_RT_CONTROL_DATA:
@@ -3663,8 +3704,7 @@ ring_processing_func_per_port(void* args)
for (i = 0; i < ctx->io_cfg.num_vfs && i < XRAN_VF_MAX; i = i+1) {
if (ctx->vf2xran_port[i] == portId) {
for(qi = 0; qi < ctx->rxq_per_port[portId]; qi++){
- if (process_ring(ctx->rx_ring[i][qi], i, qi))
- return 0;
+ process_ring(ctx->rx_ring[i][qi], i, qi);
}
}
}
@@ -3708,7 +3748,7 @@ xran_status_t xran_update_worker_info(struct xran_worker_info_s *p_worker_info,
continue;
}
- pThCtx = (struct xran_worker_th_ctx*) _mm_malloc(sizeof(struct xran_worker_th_ctx), 64);
+ pThCtx = (struct xran_worker_th_ctx*) mm_allocate_handle(sizeof(struct xran_worker_th_ctx), 64);
if(pThCtx == NULL)
{
print_err("pThCtx allocation error\n");
@@ -3838,8 +3878,6 @@ int32_t xran_spawn_workers(void)
}
}
- icx_cpu = _may_i_use_cpu_feature(_FEATURE_AVX512IFMA52);
-
printf("ORAN operating mode: O-%s\n", (xran_get_syscfg_appmode() == ID_O_DU) ?"DU":"RU");
printf(" Num of configured cores: %d%s\n", total_num_cores, icx_cpu?" (Xeon SP Gen3 or later)":"");
printf(" Num of configured RUs : %d\n", numRUs);
@@ -5018,14 +5056,13 @@ int32_t xran_start(void *pHandle)
return 0;
}
-int32_t xran_activate_cc(int32_t port_id, int32_t cc_id)
+int32_t xran_activate_cc(void *pHandle, int32_t cc_id)
{
- struct xran_device_ctx *pDevCtx;
+ struct xran_device_ctx *pDevCtx = (struct xran_device_ctx *)pHandle;
if(cc_id >= XRAN_MAX_SECTOR_NR)
return(-1);
- pDevCtx = xran_dev_get_ctx_by_id(port_id);
if(pDevCtx)
{
rte_spinlock_lock(&pDevCtx->spinLock);
@@ -5040,6 +5077,7 @@ int32_t xran_activate_cc(int32_t port_id, int32_t cc_id)
}
else
{
+ int32_t port_id = pDevCtx->xran_port_id;
printf("Invalid port(RU) index - %d\n", port_id);
return(-1);
}
@@ -5048,14 +5086,13 @@ int32_t xran_activate_cc(int32_t port_id, int32_t cc_id)
return(0);
}
-int32_t xran_deactivate_cc(int32_t port_id, int32_t cc_id)
+int32_t xran_deactivate_cc(void *pHandle, int32_t cc_id)
{
- struct xran_device_ctx *pDevCtx;
+ struct xran_device_ctx *pDevCtx = (struct xran_device_ctx *)pHandle;
if(cc_id >= XRAN_MAX_SECTOR_NR)
return(-1);
- pDevCtx = xran_dev_get_ctx_by_id(port_id);
if(pDevCtx)
{
rte_spinlock_lock(&pDevCtx->spinLock);
@@ -5070,6 +5107,7 @@ int32_t xran_deactivate_cc(int32_t port_id, int32_t cc_id)
}
else
{
+ int32_t port_id = pDevCtx->xran_port_id;
printf("Invalid port(RU) index - %d\n", port_id);
return(-1);
}
diff --git a/fhi_lib/lib/src/xran_mem_mgr.c b/fhi_lib/lib/src/xran_mem_mgr.c
index 83d43e8..ff2321d 100644
--- a/fhi_lib/lib/src/xran_mem_mgr.c
+++ b/fhi_lib/lib/src/xran_mem_mgr.c
@@ -35,7 +35,11 @@
#include <stdio.h>
#include <pthread.h>
#include <malloc.h>
+#if defined(__arm__) || defined(__aarch64__)
+#include <arm_neon.h>
+#else
#include <immintrin.h>
+#endif
#include <rte_common.h>
#include <rte_eal.h>
diff --git a/fhi_lib/lib/src/xran_mod_compression.cpp b/fhi_lib/lib/src/xran_mod_compression.cpp
index c313beb..8408a42 100644
--- a/fhi_lib/lib/src/xran_mod_compression.cpp
+++ b/fhi_lib/lib/src/xran_mod_compression.cpp
@@ -749,10 +749,7 @@ int xranlib_5gnr_mod_compression(const struct xranlib_5gnr_mod_compression_reque
#ifdef C_Module_Used
return (xranlib_5gnr_mod_compression_c(request, response));
#else
- if(XRANLIB_COMPAND_CHECK_CPU_CAPABILITY())
- return (xranlib_5gnr_mod_compression_snc(request, response));
- else
- return (xranlib_5gnr_mod_compression_avx512(request, response));
+ return (xranlib_5gnr_mod_compression_avx512(request, response));
#endif
}
diff --git a/fhi_lib/lib/src/xran_rx_proc.c b/fhi_lib/lib/src/xran_rx_proc.c
index 4ccd00e..b3e27e8 100644
--- a/fhi_lib/lib/src/xran_rx_proc.c
+++ b/fhi_lib/lib/src/xran_rx_proc.c
@@ -35,7 +35,11 @@
#include <stdio.h>
#include <pthread.h>
#include <malloc.h>
+#if defined(__arm__) || defined(__aarch64__)
+#include <arm_neon.h>
+#else
#include <immintrin.h>
+#endif
#include <rte_common.h>
#include <rte_eal.h>
diff --git a/fhi_lib/lib/src/xran_timer.c b/fhi_lib/lib/src/xran_timer.c
index 387cef8..f4a566f 100644
--- a/fhi_lib/lib/src/xran_timer.c
+++ b/fhi_lib/lib/src/xran_timer.c
@@ -32,7 +32,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
+#if defined(__arm__) || defined(__aarch64__)
+#include <arm_neon.h>
+#else
#include <immintrin.h>
+#endif
#include "xran_timer.h"
#include "xran_main.h"
diff --git a/fhi_lib/lib/src/xran_transport.c b/fhi_lib/lib/src/xran_transport.c
index 70337d6..645b2ef 100644
--- a/fhi_lib/lib/src/xran_transport.c
+++ b/fhi_lib/lib/src/xran_transport.c
@@ -27,7 +27,10 @@
#include <stdint.h>
#include <endian.h>
+#if defined(__arm__) || defined(__aarch64__)
+#else
#include <immintrin.h>
+#endif
#include <rte_common.h>
#include <rte_config.h>
diff --git a/fhi_lib/lib/src/xran_tx_proc.c b/fhi_lib/lib/src/xran_tx_proc.c
index 2d05893..08e9952 100644
--- a/fhi_lib/lib/src/xran_tx_proc.c
+++ b/fhi_lib/lib/src/xran_tx_proc.c
@@ -35,7 +35,11 @@
#include <stdio.h>
#include <pthread.h>
#include <malloc.h>
+#if defined(__arm__) || defined(__aarch64__)
+#include <arm_neon.h>
+#else
#include <immintrin.h>
+#endif
#include <rte_common.h>
#include <rte_eal.h>
diff --git a/fhi_lib/lib/src/xran_up_api.c b/fhi_lib/lib/src/xran_up_api.c
index f3b846e..3eda2de 100644
--- a/fhi_lib/lib/src/xran_up_api.c
+++ b/fhi_lib/lib/src/xran_up_api.c
@@ -25,7 +25,10 @@
*
**/
#include <inttypes.h>
+#if defined(__arm__) || defined(__aarch64__)
+#else
#include <immintrin.h>
+#endif
#include <rte_mbuf.h>
#include "xran_fh_o_du.h"
@@ -318,6 +321,7 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
uint8_t *subframe_id,
uint8_t *slot_id,
uint8_t *symb_id,
+ uint8_t *filter_id,
union ecpri_seq_id *seq_id,
uint16_t *num_prbu,
uint16_t *start_prbu,
@@ -328,7 +332,8 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
enum xran_comp_hdr_type staticComp,
uint8_t *compMeth,
uint8_t *iqWidth,
- uint8_t oxu_port_id)
+ uint8_t oxu_port_id,
+ uint8_t *is_prach)
{
#if XRAN_MLOG_VAR
uint32_t mlogVar[10];
@@ -362,6 +367,7 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
return 0; /* packet too short */
radio_hdr->sf_slot_sym.value = rte_be_to_cpu_16(radio_hdr->sf_slot_sym.value);
+ *is_prach = (radio_hdr->data_feature.filter_id > 0);
if (frame_id)
*frame_id = radio_hdr->frame_id;
@@ -375,6 +381,9 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
if (symb_id)
*symb_id = radio_hdr->sf_slot_sym.symb_id;
+ if (filter_id)
+ *filter_id = radio_hdr->data_feature.filter_id;
+
/* Process data section hdr */
struct data_section_hdr *data_hdr =
(void *)rte_pktmbuf_adj(mbuf, sizeof(*radio_hdr));

View File

@@ -1387,6 +1387,49 @@ unsigned int get_prach_K(int prach_sequence_length, int prach_fmt_id, int pusch_
return K;
}
// Based on 38.211 Table 6.3.3.1-1 and Table 6.3.3.1-2.
uint32_t get_prach_num_reps(int prach_fmt_id)
{
switch (prach_fmt_id) {
case 0:
return 1;
break;
case 1:
return 2;
break;
case 2:
return 4;
break;
case 3:
return 4;
break;
case 4: // A1
return 2;
break;
case 5: // A2
return 4;
break;
case 6: // A3
return 6;
break;
case 7: // B1
return 2;
break;
case 8: // B4
return 12;
break;
case 9: // C0
return 1;
break;
case 10: // C2
return 4;
break;
default:
AssertFatal(0, "Invalid PRACH format %d\n", prach_fmt_id);
break;
}
}
int get_delay_idx(int delay, int max_delay_comp)
{
int delay_idx = max_delay_comp + delay;

View File

@@ -326,6 +326,7 @@ unsigned short get_N_b_srs(int c_srs, int b_srs);
uint8_t get_long_prach_dur(unsigned int format, unsigned int num_slots_subframe);
uint8_t get_PRACH_k_bar(unsigned int delta_f_RA_PRACH, unsigned int delta_f_PUSCH);
unsigned int get_prach_K(int prach_sequence_length, int prach_fmt_id, int pusch_mu, int prach_mu);
uint32_t get_prach_num_reps(int prach_fmt_id);
int get_slot_idx_in_period(const int slot, const frame_structure_t *fs);

View File

@@ -282,14 +282,25 @@ void threadCreate(pthread_t* t, void * (*func)(void*), void * param, char* name,
ret=pthread_create(t, &attr, func, param);
AssertFatal(ret == 0, "Error in pthread_create(): ret: %d, errno: %d\n", ret, errno);
pthread_setname_np(*t, name);
if (affinity != -1 ) {
char short_name[16];
strncpy(short_name, name, sizeof(short_name) - 1);
short_name[sizeof(short_name) - 1] = '\0';
ret = pthread_setname_np(*t, short_name);
AssertFatal(ret == 0, "Error in pthread_setname_np(): ret: %d, errno: %d\n", ret, errno);
if (affinity != -1) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(affinity, &cpuset);
ret = pthread_setaffinity_np(*t, sizeof(cpu_set_t), &cpuset);
AssertFatal(ret == 0, "Error in pthread_getaffinity_np(): ret: %d, errno: %d", ret, errno);
} else {
cpu_set_t cpuset;
ret = sched_getaffinity(0, sizeof(cpu_set_t), &cpuset);
AssertFatal(ret == 0, "Error in sched_getaffinity(): ret: %d, errno: %d", ret, errno);
ret = pthread_setaffinity_np(*t, sizeof(cpu_set_t), &cpuset);
AssertFatal(ret == 0, "Error in pthread_setaffinity_np(): ret: %d, errno: %d", ret, errno);
}
pthread_attr_destroy(&attr);
}

View File

@@ -63,7 +63,9 @@ RUN rm -f /etc/rhsm-host && \
gcc-toolset-13-gcc-c++ \
# python3-pip and pyyaml are used for conf template generation
python3-pip && \
pip3 install --ignore-installed pyyaml && \
pip3 install --ignore-installed \
pyyaml \
pyelftools && \
echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \
echo "/usr/local/lib64" >> /etc/ld.so.conf.d/local-lib.conf

View File

@@ -38,7 +38,8 @@ RUN apt-get update && \
wget \
xz-utils \
pkg-config \
libnuma-dev && \
libnuma-dev \
python3-pyelftools && \
rm -rf /var/lib/apt/lists/*
RUN rm -Rf /oai-ran
@@ -46,20 +47,20 @@ WORKDIR /oai-ran
COPY . .
## Download and build DPDK
RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \
tar -xvf dpdk-20.11.9.tar.xz && \
cd dpdk-stable-20.11.9 && \
meson build && \
RUN wget --no-verbose http://fast.dpdk.org/rel/dpdk-22.11.7.tar.xz && \
tar -xf dpdk-22.11.7.tar.xz && \
cd dpdk-stable-22.11.7 && \
meson build -Dplatform=generic && \
ninja -C build && \
ninja install -C build
## Build Fronthaul library
RUN git clone https://gerrit.o-ran-sc.org/r/o-du/phy.git /opt/phy && \
cd /opt/phy && \
git checkout oran_f_release_v1.0 &&\
git apply /oai-ran/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch && \
git checkout oran_k_release_v1.0 &&\
git apply /oai-ran/cmake_targets/tools/oran_fhi_integration_patches/K/oaioran_K.patch && \
cd /opt/phy/fhi_lib/lib && \
TARGET=armv8 WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-20.11.9/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
TARGET=armv8 WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-22.11.7/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
## Build Arm RAN Acceleration Library
RUN git clone https://git.gitlab.arm.com/networking/ral.git /opt/ral && \

View File

@@ -33,9 +33,9 @@ WORKDIR /oai-ran
COPY . .
## Download and build DPDK
RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \
tar -xvf dpdk-20.11.9.tar.xz && \
cd dpdk-stable-20.11.9 && \
RUN wget --no-verbose http://fast.dpdk.org/rel/dpdk-22.11.7.tar.xz && \
tar -xf dpdk-22.11.7.tar.xz && \
cd dpdk-stable-22.11.7 && \
meson build && \
ninja -C build && \
ninja install -C build
@@ -43,10 +43,10 @@ RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \
## Build Fronthaul library
RUN git clone https://gerrit.o-ran-sc.org/r/o-du/phy.git /opt/phy && \
cd /opt/phy && \
git checkout oran_f_release_v1.0 &&\
git apply /oai-ran/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch && \
git checkout oran_k_release_v1.0 &&\
git apply /oai-ran/cmake_targets/tools/oran_fhi_integration_patches/K/oaioran_K.patch && \
cd /opt/phy/fhi_lib/lib && \
WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-20.11.9/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-22.11.7/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
FROM ran-base AS ran-build-fhi72
ARG E2AP_VERSION=E2AP_V3

View File

@@ -38,7 +38,8 @@ RUN apt-get update && \
wget \
xz-utils \
pkg-config \
libnuma-dev && \
libnuma-dev \
python3-pyelftools && \
rm -rf /var/lib/apt/lists/*
RUN rm -Rf /oai-ran
@@ -46,9 +47,9 @@ WORKDIR /oai-ran
COPY . .
## Download and build DPDK
RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \
tar -xvf dpdk-20.11.9.tar.xz && \
cd dpdk-stable-20.11.9 && \
RUN wget --no-verbose http://fast.dpdk.org/rel/dpdk-22.11.7.tar.xz && \
tar -xf dpdk-22.11.7.tar.xz && \
cd dpdk-stable-22.11.7 && \
meson build && \
ninja -C build && \
ninja install -C build
@@ -56,10 +57,10 @@ RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \
## Build Fronthaul library
RUN git clone https://gerrit.o-ran-sc.org/r/o-du/phy.git /opt/phy && \
cd /opt/phy && \
git checkout oran_f_release_v1.0 &&\
git apply /oai-ran/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch && \
git checkout oran_k_release_v1.0 &&\
git apply /oai-ran/cmake_targets/tools/oran_fhi_integration_patches/K/oaioran_K.patch && \
cd /opt/phy/fhi_lib/lib && \
WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-20.11.9/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-22.11.7/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
FROM ran-base AS ran-build-fhi72
## Build and install OAI

View File

@@ -59,6 +59,7 @@ RUN rm -f /etc/rhsm-host && \
python3-pip \
net-tools \
iputils \
libatomic \
yaml-cpp-devel && \
pip3 install six && \
pip3 install requests && \

View File

@@ -36,6 +36,7 @@ ENV TZ=Europe/Paris
RUN dnf update -y && \
dnf install -y \
procps-ng \
libatomic \
libXpm \
libX11 \
lksctp-tools \

View File

@@ -59,6 +59,7 @@ RUN apt-get update && \
python3 \
python3-six \
python3-requests \
libatomic1 \
libyaml-cpp-dev && \
# if the --sanitize option was used to build, additional packages are required
/bin/bash -c 'if [[ "$BUILD_OPTION" = "--sanitize" ]]; then DEBIAN_FRONTEND=noninteractive apt-get install --yes \

279
executables/main_nr_ru.c Normal file
View File

@@ -0,0 +1,279 @@
/*
* 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 oairu.c
* \brief Top-level threads for radio-unit
* \author R. Knopp
* \date 2020
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr
* \note
* \warning
*/
#include "PHY/INIT/nr_phy_init.h"
#include "PHY/TOOLS/tools_defs.h"
#include "PHY/defs_nr_common.h"
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sched.h>
#include "assertions.h"
#include "PHY/types.h"
#include "PHY/defs_RU.h"
#include "common/oai_version.h"
#include "common/config/config_userapi.h"
#include "common/utils/load_module_shlib.h"
#include "common/ran_context.h"
#include "radio/COMMON/common_lib.h"
#include "radio/ETHERNET/if_defs.h"
#include "PHY/phy_vars.h"
#include "PHY/phy_extern.h"
#include "PHY/TOOLS/phy_scope_interface.h"
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
// #include "PHY/INIT/phy_init.h"
#include "openair2/ENB_APP/enb_paramdef.h"
#include "system.h"
#include "nfapi/oai_integration/vendor_ext.h"
#include <executables/softmodem-common.h>
#include <executables/thread-common.h>
#include "nr-oru.h"
#include "openair1/SCHED_NR/sched_nr.h"
pthread_cond_t sync_cond;
pthread_mutex_t sync_mutex;
int sync_var = -1; //!< protected by mutex \ref sync_mutex.
int config_sync_var = -1;
int oai_exit = 0;
int sf_ahead = 4;
int emulate_rf = 0;
RAN_CONTEXT_t RC;
extern void kill_NR_RU_proc(int inst);
extern void set_function_spec_param(RU_t *ru);
extern void start_NR_RU();
extern void init_NR_RU(configmodule_interface_t *cfg, char *);
void fill_rf_config(RU_t *ru, char *rf_config_file);
void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_request_scf_t *config, const NR_DL_FRAME_PARMS *fp);
int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
void nfapi_setmode(nfapi_mode_t nfapi_mode)
{
return;
}
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
{
if (s != NULL) {
printf("%s:%d %s() Exiting OAI softmodem: %s\n", file, line, function, s);
}
close_log_mem();
oai_exit = 1;
if (assert)
abort();
}
void stop_ru(int sig)
{
exit_function(__FILE__, __FUNCTION__, __LINE__, "interrupted", false);
}
static void get_options(configmodule_interface_t *cfg)
{
CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP);
get_common_options(cfg);
CONFIG_CLEARRTFLAG(CONFIG_NOEXITONHELP);
// NRCConfig();
}
nfapi_mode_t nfapi_getmode(void)
{
return (NFAPI_MODE_PNF);
}
void oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind)
{
AssertFatal(1 == 0, "This is bad ... please check why we get here\n");
}
void wait_eNBs(void)
{
return;
}
void wait_gNBs(void)
{
return;
}
struct timespec timespec_add(struct timespec, struct timespec)
{
struct timespec t = {0};
return t;
};
struct timespec timespec_sub(struct timespec, struct timespec)
{
struct timespec t = {0};
return t;
};
int beam_index_allocation(bool das,
int fapi_beam_index,
NR_gNB_COMMON *common_vars,
int slot,
int symbols_per_slot,
int bitmap_symbols)
{
return 0;
}
void nr_fill_du(uint16_t N_ZC, const uint16_t *prach_root_sequence_map, uint16_t nr_du[NR_PRACH_SEQ_LEN_L - 1])
{
return;
};
uint16_t nr_du[838];
uint64_t downlink_frequency[MAX_NUM_CCs][4];
configmodule_interface_t *uniqCfg = NULL;
THREAD_STRUCT thread_struct;
int main(int argc, char **argv)
{
memset(&RC, 0, sizeof(RC));
if ((uniqCfg = load_configmodule(argc, argv, 0)) == NULL) {
exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
}
logInit();
printf("Reading in command-line options\n");
get_options(uniqCfg);
if (CONFIG_ISFLAGSET(CONFIG_ABORT)) {
fprintf(stderr, "Getting configuration failed\n");
exit(-1);
}
#if T_TRACER
T_Config_Init();
#endif
printf("configuring for RRU\n");
// strdup to put the sring in the core file for post mortem identification
LOG_I(HW, "Version: %s\n", strdup(OAI_PACKAGE_VERSION));
/* Read configuration */
printf("About to Init RU threads\n");
lock_memory_to_ram();
load_dftslib();
RC.nb_RU = 1;
RC.ru = malloc(sizeof(RC.ru));
init_NR_RU(config_get_if(), NULL);
RU_t *ru = RC.ru[0];
ORU_t oru = {0};
oru.ru = ru;
oru.num_sync_messages_needed = 2;
int ret = get_oru_options(&oru);
AssertFatal(ret == 0, "Cannot configure oru, check your config file/cmdline");
ru->numerology = oru.numerology;
oru_init_frame_parms(&oru);
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
nr_dump_frame_parms(fp);
init_symbol_rotation(fp);
ru->if_south = LOCAL_RF;
nr_phy_init_RU(oru.ru);
fill_rf_config(ru, ru->rf_config_file);
fill_split7_2_config(&ru->openair0_cfg.split7, &ru->config, fp);
ru->N_TA_offset = set_default_nta_offset(fp->freq_range, fp->samples_per_subframe);
/* set PRACH configuration */
nfapi_nr_prach_config_t *prach_config = &ru->config.prach_config;
prach_config->prach_ConfigurationIndex.value = oru.prach_config_index;
prach_config->num_prach_fd_occasions_list[0].k1.value = oru.prach_msg1_freq;
prach_config->prach_sequence_length.value = 1;
prach_config->prach_sub_c_spacing.value = 1;
prach_config->num_prach_fd_occasions.value = 1;
reset_meas(&oru.rx_prach);
oru.prach_info = get_nr_prach_occasion_info_from_index(oru.prach_config_index, FR1, fp->frame_type);
LOG_A(PHY, "PRACH configuration index %d\n", oru.prach_config_index);
LOG_A(PHY,
"PRACH format %d start_symbol %d duration %d\n",
oru.prach_info.format,
oru.prach_info.start_symbol,
oru.prach_info.N_dur);
prepare_prach_item(&oru);
ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params);
AssertFatal(ret == 0, "RU %u: openair0_transport_init() ret %d: cannot initialize transport potocol\n", ru->idx, ret);
ret = ru->nr_start_if(ru, NULL);
AssertFatal(ret == 0, "Could not start xran\n");
LOG_I(PHY, "starting vrtsim\n");
ret = openair0_load(&ru->rfdevice, "vrtsim", &ru->openair0_cfg, NULL);
AssertFatal(ret == 0, "RU %u: openair0_load() ret %d: cannot initialize vrtsim\n", ru->idx, ret);
ret = ru->rfdevice.trx_start_func(&ru->rfdevice);
AssertFatal(ret == 0, "RU %u: trx_start_func() ret %d: cannot start vrtsim\n", ru->idx, ret);
signal(SIGINT, stop_ru);
threadCreate(&oru.north_read_thread, oru_north_read_thread, (void *)&oru, "north_read_thread", -1, OAI_PRIORITY_RT_MAX);
threadCreate(&oru.south_read_thread, oru_south_read_thread, (void *)&oru, "south_read_thread", -1, OAI_PRIORITY_RT_MAX);
threadCreate(&oru.oru_sync_thread, oru_sync_thread, (void *)&oru, "oru_sync_thread", -1, OAI_PRIORITY_RT_MAX);
while (oai_exit == 0)
sleep(1);
ret = pthread_join(oru.oru_sync_thread, NULL);
AssertFatal(ret == 0, "pthread_join failed %d\n", ret);
ret = pthread_join(oru.north_read_thread, NULL);
AssertFatal(ret == 0, "pthread_join failed %d\n", ret);
ret = pthread_join(oru.south_read_thread, NULL);
AssertFatal(ret == 0, "pthread_join failed %d\n", ret);
LOG_I(PHY, "Threads joined\n");
if (ru->ifdevice.trx_stop_func) {
ru->ifdevice.trx_stop_func(&ru->ifdevice);
}
if (ru->ifdevice.trx_end_func) {
ru->ifdevice.trx_end_func(&ru->ifdevice);
}
sleep(1);
if (ru->rfdevice.trx_stop_func) {
ru->rfdevice.trx_stop_func(&ru->rfdevice);
}
if (ru->rfdevice.trx_end_func) {
ru->rfdevice.trx_end_func(&ru->rfdevice);
}
logClean();
end_configmodule(uniqCfg);
printf("Bye.\n");
return 0;
}

698
executables/nr-oru.c Normal file
View File

@@ -0,0 +1,698 @@
/*
* 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 "PHY/defs_RU.h"
#include "assertions.h"
#include "common/config/config_userapi.h"
#include "nr-oru.h"
#include "openair1/PHY/defs_nr_common.h"
#include "openair1/PHY/MODULATION/nr_modulation.h"
#include "openair1/SCHED_NR/sched_nr.h"
#include "openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h"
#define CONFIG_SECTION_ORU "ORUs.[0]"
// clang-format off
#define CONFIG_STRING_ORU_TX_BW_LIST "tx_bw"
#define CONFIG_STRING_ORU_RX_BW_LIST "rx_bw"
#define CONFIG_STRING_ORU_CARRIER_TX_LIST "carrier_tx"
#define CONFIG_STRING_ORU_CARRIER_RX_LIST "carrier_rx"
#define CONFIG_STRING_ORU_FRAME_TYPE "frame_type"
#define CONFIG_STRING_ORU_PRACH_CONFIGID "prach_config_index"
#define CONFIG_STRING_ORU_PRACH_MSG1FREQ "prach_msg1_start"
#define CONFIG_STRING_ORU_NUMEROLOGY "mu"
#define CONFIG_STRING_ORU_TDD_PERIOD "tdd_period"
#define CONFIG_STRING_ORU_NUM_DL_SLOTS "num_dl_slots"
#define CONFIG_STRING_ORU_NUM_UL_SLOTS "num_ul_slots"
#define CONFIG_STRING_ORU_NUM_DL_SYMBOLS "num_dl_symbols"
#define CONFIG_STRING_ORU_NUM_UL_SYMBOLS "num_ul_symbols"
#define CONFIG_STRING_ORU_TP_CORES "tp_cores"
#define HLP_ORU_TX_BW "set the TX bandwidth list per component carrier"
#define HLP_ORU_RX_BW "set the RX bandwidth list per component carrier"
#define HLP_ORU_CARRIER_TX "set the TX carrier frequencies per component carrier"
#define HLP_ORU_CARRIER_RX "set the RX carrier frequencies per component carrier"
#define HLP_ORU_FRAMETYPE "set the Frame type TDD/FDD of all component carriers"
#define HLP_ORU_PRACH_CONFIGID "set the PRACH configuration id of all component carriers"
#define HLP_ORU_PRACH_MSG1FREQ "set the PRACH MSG1 frequency of all component carriers"
#define HLP_ORU_NUMEROLOGY "set the numerology of the RU"
#define HLP_ORU_TDD_PERIOD "set the 3GPP TDD periodificty 0-9"
#define HLP_ORU_NUM_DL_SLOTS "set the number of DL Slots in TDD"
#define HLP_ORU_NUM_UL_SLOTS "set the number of UL Slots in TDD"
#define HLP_ORU_NUM_DL_SYMBOLS "set the number of DL symbols in the mixed slot"
#define HLP_ORU_NUM_UL_SYMBOLS "set the number of UL symbols in the mixed slot"
#define HLP_ORU_TP_CORES "CPU cores used for threadpool"
#define CMDLINE_PARAMS_DESC_ORU \
{ \
{CONFIG_STRING_ORU_TX_BW_LIST, HLP_ORU_TX_BW, 0, .iptr=NULL, .defintarrayval=DEFBW, TYPE_INTARRAY, 0}, \
{CONFIG_STRING_ORU_RX_BW_LIST, HLP_ORU_RX_BW, 0, .iptr=NULL, .defintarrayval=DEFBW, TYPE_INTARRAY, 0}, \
{CONFIG_STRING_ORU_CARRIER_TX_LIST, HLP_ORU_CARRIER_TX, 0, .iptr=NULL, .defintarrayval=DEFCARRIER, TYPE_INTARRAY, 0}, \
{CONFIG_STRING_ORU_CARRIER_RX_LIST, HLP_ORU_CARRIER_RX, 0, .iptr=NULL, .defintarrayval=DEFCARRIER, TYPE_INTARRAY, 0}, \
{CONFIG_STRING_ORU_FRAME_TYPE, HLP_ORU_FRAMETYPE, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_ORU_PRACH_CONFIGID, HLP_ORU_PRACH_CONFIGID, 0, .uptr=NULL, .defintval=152, TYPE_UINT, 0}, \
{CONFIG_STRING_ORU_PRACH_MSG1FREQ, HLP_ORU_PRACH_MSG1FREQ, 0, .uptr=NULL, .defintval=0, TYPE_UINT, 0}, \
{CONFIG_STRING_ORU_NUMEROLOGY, HLP_ORU_NUMEROLOGY, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_ORU_TDD_PERIOD, HLP_ORU_TDD_PERIOD, 0, .uptr=NULL, .defintval=5, TYPE_UINT, 0}, \
{CONFIG_STRING_ORU_NUM_DL_SLOTS, HLP_ORU_NUM_DL_SLOTS, 0, .uptr=NULL, .defintval=3, TYPE_UINT, 0}, \
{CONFIG_STRING_ORU_NUM_UL_SLOTS, HLP_ORU_NUM_UL_SLOTS, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_ORU_NUM_DL_SYMBOLS, HLP_ORU_NUM_DL_SYMBOLS, 0, .uptr=NULL, .defintval=7, TYPE_UINT, 0}, \
{CONFIG_STRING_ORU_NUM_UL_SYMBOLS, HLP_ORU_NUM_UL_SYMBOLS, 0, .uptr=NULL, .defintval=3, TYPE_UINT, 0}, \
{CONFIG_STRING_ORU_TP_CORES, HLP_ORU_TP_CORES, 0, .iptr=NULL, .defintarrayval=DEFTPCORES, TYPE_INTARRAY, 4}, \
}
// clang-format on
typedef struct {
openair0_timestamp sample;
int slot;
int frame;
int symbol;
} initial_sync_t;
typedef struct {
int frame_unwrap;
int last_frame;
int64_t sync_offset;
} sync_params_t;
typedef struct {
RU_t *ru;
NR_DL_FRAME_PARMS *fp;
int slot;
int start_symbol;
int num_symbols;
int aatx;
c16_t *txdataF;
task_ans_t *task_ans;
} dl_symbol_process_t;
extern void tx_rf_symbols(RU_t *ru, int frame, int slot, uint64_t timestamp, int start_symbol, int num_symbols);
extern void set_scs_parameters(NR_DL_FRAME_PARMS *fp, int mu, int N_RB_DL);
extern void rx_nr_prach_ru_internal(prach_item_t *p,
int beam_id,
int prachStartSymbol,
int prachOccasion,
int32_t **rxdata,
NR_DL_FRAME_PARMS *fp,
int N_TA_offset,
int rep_index,
uint reps);
static void oru_downlink_processing(ORU_t *oru,
c16_t *txDataF_ptr[oru->ru->nb_tx],
int frame,
int slot,
int start_symbol,
int num_symbols,
openair0_timestamp timestamp_tx);
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];
}
int get_oru_options(ORU_t *oru)
{
int DEFBW[] = {273};
int DEFCARRIER[] = {3430560};
int DEFTPCORES[] = {-1, -1, -1, -1};
paramdef_t param[] = CMDLINE_PARAMS_DESC_ORU;
int nump = sizeofArray(param);
int ret = config_get(config_get_if(), param, nump, CONFIG_SECTION_ORU);
if (ret <= 0) {
printf("problem reading section \"%s\"\n", CONFIG_SECTION_ORU);
return -1;
}
for (int i = 0; i < oru->ru->num_bands; i++) {
oru->bw_tx[i] = gpd(param, nump, CONFIG_STRING_ORU_TX_BW_LIST)->iptr[i];
oru->bw_rx[i] = gpd(param, nump, CONFIG_STRING_ORU_RX_BW_LIST)->iptr[i];
oru->carrier_freq_tx[i] = gpd(param, nump, CONFIG_STRING_ORU_CARRIER_TX_LIST)->iptr[i];
oru->carrier_freq_rx[i] = gpd(param, nump, CONFIG_STRING_ORU_CARRIER_RX_LIST)->iptr[i];
}
oru->frame_type = *gpd(param, nump, CONFIG_STRING_ORU_FRAME_TYPE)->iptr;
oru->prach_config_index = *gpd(param, nump, CONFIG_STRING_ORU_PRACH_CONFIGID)->iptr;
oru->prach_msg1_freq = *gpd(param, nump, CONFIG_STRING_ORU_PRACH_MSG1FREQ)->iptr;
oru->numerology = *gpd(param, nump, CONFIG_STRING_ORU_NUMEROLOGY)->iptr;
oru->tdd_period = *gpd(param, nump, CONFIG_STRING_ORU_TDD_PERIOD)->iptr;
oru->num_DL_slots = *gpd(param, nump, CONFIG_STRING_ORU_NUM_DL_SLOTS)->iptr;
oru->num_UL_slots = *gpd(param, nump, CONFIG_STRING_ORU_NUM_UL_SLOTS)->iptr;
oru->num_DL_symbols = *gpd(param, nump, CONFIG_STRING_ORU_NUM_DL_SYMBOLS)->iptr;
oru->num_UL_symbols = *gpd(param, nump, CONFIG_STRING_ORU_NUM_UL_SYMBOLS)->iptr;
int* tp_cores = gpd(param, nump, CONFIG_STRING_ORU_TP_CORES)->iptr;
int num_tp_cores = gpd(param, nump, CONFIG_STRING_ORU_TP_CORES)->numelt;
AssertFatal(num_tp_cores > 0, "No threadpool cores specified\n");
char tpool_config[(3 + 1) * num_tp_cores + 1];
char* tpool_config_p = tpool_config;
for (int i = 0; i < num_tp_cores; i++) {
int ret = snprintf(tpool_config_p, 4, "%d,", tp_cores[i]);
AssertFatal(ret > 0, "snprintf failed\n");
tpool_config_p += ret;
}
*tpool_config_p = '\0';
LOG_A(PHY, "ORU threadpool cores: %s\n", tpool_config);
initTpool(tpool_config, &oru->tpool, false);
return 0;
}
void oru_init_frame_parms(ORU_t *oru)
{
RU_t *ru = oru->ru;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
fp->frame_type = oru->frame_type;
ru->config.cell_config.frame_duplex_type.value = oru->frame_type;
ru->config.cell_config.frame_duplex_type.tl.tag = 0x100D;
fp->N_RB_DL = oru->bw_tx[0];
ru->config.ssb_config.scs_common.value = ru->numerology;
ru->config.carrier_config.dl_grid_size[ru->config.ssb_config.scs_common.value].value = oru->bw_tx[0];
fp->N_RB_UL = oru->bw_rx[0];
ru->config.carrier_config.ul_grid_size[ru->config.ssb_config.scs_common.value].value = oru->bw_rx[0];
fp->numerology_index = ru->numerology;
fp->nr_band = ru->band[0];
LOG_I(NR_PHY,
"Set RU frame type to %s, N_RB_DL %d, N_RB_UL %d, mu %d\n",
oru->frame_type == TDD ? "TDD" : "FDD",
oru->bw_tx[0],
oru->bw_rx[0],
ru->numerology);
set_scs_parameters(fp, fp->numerology_index, oru->bw_tx[0]);
fp->slots_per_frame = 10 * fp->slots_per_subframe;
fp->nb_antennas_rx = ru->nb_rx;
fp->nb_antennas_tx = ru->nb_tx;
fp->symbols_per_slot = 14;
fp->samples_per_subframe_wCP = fp->ofdm_symbol_size * fp->symbols_per_slot * fp->slots_per_subframe;
fp->samples_per_frame_wCP = 10 * fp->samples_per_subframe_wCP;
fp->samples_per_slot_wCP = fp->symbols_per_slot * fp->ofdm_symbol_size;
fp->samples_per_slotN0 = (fp->nb_prefix_samples + fp->ofdm_symbol_size) * fp->symbols_per_slot;
fp->samples_per_slot0 =
fp->nb_prefix_samples0 + ((fp->symbols_per_slot - 1) * fp->nb_prefix_samples) + (fp->symbols_per_slot * fp->ofdm_symbol_size);
fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2
+ (fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2);
fp->samples_per_frame = 10 * fp->samples_per_subframe;
fp->freq_range = (oru->carrier_freq_tx[0] < 6e6) ? FR1 : FR2;
fp->dl_CarrierFreq = (double)oru->carrier_freq_tx[0] * 1000;
fp->ul_CarrierFreq = (double)oru->carrier_freq_rx[0] * 1000;
fp->Ncp = NORMAL;
fp->ofdm_offset_divisor = 8;
// Split 7.2 parameters
ru->config.prach_config.num_prach_fd_occasions.value = 1;
ru->config.prach_config.prach_ConfigurationIndex.value = oru->prach_config_index;
ru->config.prach_config.prach_ConfigurationIndex.tl.tag = 0x1029;
ru->config.prach_config.num_prach_fd_occasions_list = malloc(sizeof(*ru->config.prach_config.num_prach_fd_occasions_list));
ru->config.prach_config.num_prach_fd_occasions_list[0].k1.value = oru->prach_msg1_freq;
if (ru->config.cell_config.frame_duplex_type.value == 1 /* TDD */) {
ru->config.tdd_table.tdd_period.value = oru->tdd_period;
ru->config.tdd_table.tdd_period.tl.tag = 0x1026;
int numb_slots_frame = (1 << ru->numerology) * NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
int numb_period_frame = get_nb_periods_per_frame(oru->tdd_period);
int numb_slots_period = numb_slots_frame / numb_period_frame;
ru->config.tdd_table.max_tdd_periodicity_list =
malloc(sizeof(*ru->config.tdd_table.max_tdd_periodicity_list) * (numb_slots_frame));
for (int n = 0; n < numb_slots_frame; n++) {
int s = 0;
int p = n % numb_slots_period;
if (p < oru->num_DL_slots) {
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list =
malloc(sizeof(*ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list)
* NR_NUMBER_OF_SYMBOLS_PER_SLOT);
for (s = 0; s < 14; s++)
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 0;
} else if (p == oru->num_DL_slots) {
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list =
malloc(sizeof(*ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list)
* NR_NUMBER_OF_SYMBOLS_PER_SLOT);
for (s = 0; s < oru->num_DL_symbols; s++)
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 0;
for (; s < NR_NUMBER_OF_SYMBOLS_PER_SLOT - oru->num_UL_symbols; s++)
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 2;
for (; s < NR_NUMBER_OF_SYMBOLS_PER_SLOT; s++)
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 1;
} else {
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list =
malloc(sizeof(*ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list)
* NR_NUMBER_OF_SYMBOLS_PER_SLOT);
for (s = 0; s < NR_NUMBER_OF_SYMBOLS_PER_SLOT; s++)
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 1;
}
}
}
}
void initialize_sync_params(NR_DL_FRAME_PARMS *fp, sync_params_t *sync_params, initial_sync_t *initial_sync)
{
sync_params->frame_unwrap = 0;
sync_params->last_frame = initial_sync->frame;
sync_params->sync_offset = initial_sync->sample;
sync_params->sync_offset -=
(uint64_t)(initial_sync->frame) * fp->samples_per_subframe * 10 + get_samples_slot_timestamp(fp, initial_sync->slot);
}
static openair0_timestamp get_timestamp(ORU_t *oru, sense_of_time_t *sense_of_time, sync_params_t *sync_params)
{
if (sync_params->last_frame > sense_of_time->frame) {
sync_params->frame_unwrap++;
}
sync_params->last_frame = sense_of_time->frame;
NR_DL_FRAME_PARMS *fp = oru->ru->nr_frame_parms;
int num_frames = sense_of_time->frame + sync_params->frame_unwrap * 1024;
uint64_t timestamp = (uint64_t)(num_frames)*fp->samples_per_subframe * 10 + get_samples_slot_timestamp(fp, sense_of_time->slot)
+ get_samples_symbol_timestamp(fp, sense_of_time->slot, sense_of_time->symbol);
timestamp += sync_params->sync_offset;
return timestamp;
}
void receive_prach(ORU_t *oru, int frame, int slot, int prach_symbol)
{
RU_t *ru = oru->ru;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
oru->prach_item.frame = frame;
oru->prach_item.slot = slot;
rx_nr_prach_ru_internal(&oru->prach_item,
0,
oru->prach_info.start_symbol,
0,
ru->common.rxdata,
fp,
ru->N_TA_offset,
prach_symbol,
1);
for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) {
ru->ifdevice.xran_api.write_prach((uint32_t *)oru->prach_item.rxsigF[0][aarx], aarx, frame, slot, prach_symbol);
}
}
// Returns PRACH symbol that was received in current frame, slot and symbol.
// If no PRACH symbol was received, returns -1
int get_prach_symbol(ORU_t *oru, int frame, int slot, int symbol, int numerology)
{
uint16_t RA_sfn_index;
AssertFatal(oru->ru->nr_frame_parms->frame_type == TDD, "Only supports TDD\n");
if (get_nr_prach_sched_from_info(oru->prach_info, oru->prach_config_index, frame, slot, numerology, FR1, &RA_sfn_index, true)) {
int format = oru->prach_item.pdu.prach_format;
int start_symbol = oru->prach_item.pdu.prach_start_symbol;
symbol -= start_symbol;
// TODO: Support more PRACH formats
AssertFatal(format == 8, "only support format B4\n");
// TODO: This is not exactly the case but it is correct
if (symbol > 0 && symbol < 12) {
return symbol;
}
}
return -1;
}
void *oru_north_read_thread(void *arg)
{
ORU_t *oru = (ORU_t *)arg;
RU_t *ru = (RU_t *)oru->ru;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
AssertFatal(ru->ifdevice.xran_api.north_in_func != NULL, "No fronthaul interface at north port");
__attribute__((aligned(32))) c16_t txDataF[ru->nb_tx][fp->ofdm_symbol_size * 14];
memset(txDataF, 0, sizeof(txDataF));
c16_t *txDataF_ptr[ru->nb_tx];
for (int aatx = 0; aatx < ru->nb_tx; aatx++) {
txDataF_ptr[aatx] = txDataF[aatx];
}
notifiedFIFO_elt_t *elt = pullNotifiedFIFO(&oru->sync_fifo);
initial_sync_t *initial_sync = NotifiedFifoData(elt);
sync_params_t sync_params;
initialize_sync_params(fp, &sync_params, initial_sync);
LOG_A(PHY,
"ORU North read thread started at frame %d, slot %d, symbol %d\n",
initial_sync->frame,
initial_sync->slot,
initial_sync->symbol);
delNotifiedFIFO_elt(elt);
while (!oai_exit) {
int num_symbols = 0;
sense_of_time_t sense_of_time;
ru->ifdevice.xran_api.north_in_func((uint32_t **)txDataF_ptr, ru->nb_tx, &sense_of_time, &num_symbols);
openair0_timestamp timestamp_tx = get_timestamp(oru, &sense_of_time, &sync_params);
if ((sense_of_time.frame % 256 == 0) && sense_of_time.slot == 0) {
LOG_I(PHY,
"[RU_thread] read data: frame %d, slot %d, start_symbol %d, num_symbols %d\n",
sense_of_time.frame,
sense_of_time.slot,
sense_of_time.symbol,
num_symbols);
}
nfapi_nr_config_request_scf_t *cfg = &ru->config;
int slot_type = nr_slot_select(cfg, sense_of_time.frame, sense_of_time.slot % fp->slots_per_frame);
if (slot_type != NR_UPLINK_SLOT)
oru_downlink_processing(oru,
txDataF_ptr,
sense_of_time.frame,
sense_of_time.slot,
sense_of_time.symbol,
num_symbols,
timestamp_tx);
}
return NULL;
}
void rx_initial_sync(ORU_t *oru, int *slot, int *frame)
{
RU_t *ru = oru->ru;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
const int num_samples = 3000;
c16_t throwaway_samples[ru->nb_rx][num_samples];
void *rxp[ru->nb_rx];
for (int i = 0; i < ru->nb_rx; i++)
rxp[i] = throwaway_samples[i];
openair0_timestamp timestamp;
initial_sync_t initial_sync;
while (!oai_exit) {
int samples_read = ru->rfdevice.trx_read_func(&ru->rfdevice, &timestamp, rxp, num_samples, ru->nb_rx);
AssertFatal(samples_read == num_samples, "Unexpected number of samples received\n");
notifiedFIFO_elt_t *elt = pollNotifiedFIFO(&oru->sync_fifo);
if (elt) {
memcpy(&initial_sync, NotifiedFifoData(elt), sizeof(initial_sync));
break;
}
}
// Synchornize to ORAN timing
int next_slot = initial_sync.slot;
int next_frame = initial_sync.frame;
openair0_timestamp next_sample = timestamp + num_samples;
int64_t diff = next_sample - initial_sync.sample;
LOG_I(PHY,
"Sychronizing to frame slot %d.%d, sample %ld next_sample %ld diff %ld\n",
next_frame,
next_slot,
initial_sync.sample,
next_sample,
diff);
uint64_t samples_to_sync_by = 0;
if (diff < 0) {
samples_to_sync_by = -diff;
} else {
while (diff > 0) {
uint32_t samples_per_slot = get_samples_per_slot(next_slot, fp);
samples_to_sync_by += samples_per_slot;
diff -= samples_per_slot;
next_slot++;
if (next_slot == fp->slots_per_frame) {
next_slot = 0;
next_frame++;
if (next_frame == 1024) {
next_frame = 0;
}
}
}
samples_to_sync_by += diff;
}
LOG_I(PHY, "Thrashing %lu samples to sync to slot %d, frame %d\n", samples_to_sync_by, next_slot, next_frame);
while (!oai_exit && samples_to_sync_by > 0) {
int samples_to_read = min(num_samples, samples_to_sync_by);
int samples_read = ru->rfdevice.trx_read_func(&ru->rfdevice, &timestamp, rxp, samples_to_read, ru->nb_rx);
AssertFatal(samples_to_read == samples_read, "Unexpected number of samples received\n");
samples_to_sync_by -= samples_to_read;
}
*slot = next_slot;
*frame = next_frame;
}
void *oru_south_read_thread(void *arg)
{
ORU_t *oru = arg;
int slot;
int frame;
rx_initial_sync(oru, &slot, &frame);
LOG_A(PHY, "ORU South read thread started at frame %d, slot %d\n", frame, slot);
RU_t *ru = oru->ru;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
while (!oai_exit) {
int rx_slot_type = nr_slot_select(&ru->config, frame, slot);
for (int symbol = 0; symbol < 14; symbol++) {
int samples_to_read = get_samples_symbol_duration(fp, slot, symbol, 1);
size_t offset = get_samples_slot_timestamp(fp, slot) + get_samples_symbol_timestamp(fp, slot, symbol);
c16_t *rxp[fp->nb_antennas_rx];
for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) {
rxp[aarx] = (c16_t *)&ru->common.rxdata[aarx][offset];
}
openair0_timestamp timestamp;
int num_samples_read = ru->rfdevice.trx_read_func(&ru->rfdevice, &timestamp, (void **)rxp, samples_to_read, ru->nb_rx);
AssertFatal(num_samples_read == samples_to_read, "Unexpected number of samples received\n");
LOG_D(PHY,
"[ORU south] read data: frame %d, slot %d, symbol %d, timestamp %ld num_symbols %d, samples %d\n",
frame,
slot,
symbol,
timestamp,
1,
num_samples_read);
if (rx_slot_type == NR_UPLINK_SLOT || rx_slot_type == NR_MIXED_SLOT) {
int prach_symbol = get_prach_symbol(oru, frame, slot, symbol, ru->numerology);
if (prach_symbol == 11) {
receive_prach(oru, frame, slot, prach_symbol);
}
stop_meas(&oru->rx);
}
}
slot++;
if (slot == fp->slots_per_frame) {
slot = 0;
frame++;
if (frame == 1024) {
frame = 0;
}
}
}
// Perform RX processing
return NULL;
}
void perform_initial_sync(ORU_t *oru, sense_of_time_t *sense_of_time, initial_sync_t *initial_sync)
{
initial_sync->frame = sense_of_time->frame;
initial_sync->slot = sense_of_time->slot;
initial_sync->symbol = sense_of_time->symbol;
initial_sync->sample = oru->ru->rfdevice.get_timestamp(&oru->ru->rfdevice, &sense_of_time->ts);
LOG_I(PHY,
"RU synchronized: frame, slot %d.%d, symbol %d, sample: %ld\n",
initial_sync->frame,
initial_sync->slot,
initial_sync->symbol,
initial_sync->sample);
}
void *oru_sync_thread(void *arg)
{
ORU_t *oru = (ORU_t *)arg;
RU_t *ru = (RU_t *)oru->ru;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
AssertFatal(ru->ifdevice.xran_api.north_in_func != NULL, "No fronthaul interface at north port");
__attribute__((aligned(32))) c16_t txDataF[ru->nb_tx][ceil_mod(fp->ofdm_symbol_size * 14, 32)];
c16_t *txDataF_ptr[ru->nb_tx];
for (int aatx = 0; aatx < ru->nb_tx; aatx++) {
txDataF_ptr[aatx] = txDataF[aatx];
}
initial_sync_t initial_sync;
while (!oai_exit) {
int num_symbols = 0;
sense_of_time_t sense_of_time;
ru->ifdevice.xran_api.north_in_func((uint32_t **)txDataF_ptr, ru->nb_tx, &sense_of_time, &num_symbols);
if (sense_of_time.symbol == 0) {
perform_initial_sync(oru, &sense_of_time, &initial_sync);
break;
}
}
for (int i = 0; i < oru->num_sync_messages_needed; i++) {
notifiedFIFO_elt_t *sync_msg = newNotifiedFIFO_elt(sizeof(initial_sync_t), 0, NULL, NULL);
initial_sync_t *initial_sync_p = NotifiedFifoData(sync_msg);
*initial_sync_p = initial_sync;
pushNotifiedFIFO(&oru->sync_fifo, sync_msg);
}
return NULL;
}
static void dl_symbol_process(void *arg)
{
dl_symbol_process_t *args = (dl_symbol_process_t *)arg;
apply_nr_rotation_TX(args->fp,
args->txdataF,
args->fp->symbol_rotation[0],
args->slot,
args->fp->N_RB_DL,
args->start_symbol,
args->num_symbols);
nr_feptx0(args->ru, args->slot, args->start_symbol, args->num_symbols, args->aatx);
completed_task_ans(args->task_ans);
}
static void oru_downlink_processing(ORU_t *oru,
c16_t *txDataF_ptr[oru->ru->nb_tx],
int frame,
int slot,
int start_symbol,
int num_symbols,
openair0_timestamp timestamp_tx)
{
RU_t *ru = oru->ru;
start_meas(&ru->tx_fhaul);
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
int num_paralell_workers_per_antenna = num_symbols > 4 ? 2 : 1; // Ensure at least quarter slot parallelization
task_t tasks[ru->nb_tx][num_paralell_workers_per_antenna];
dl_symbol_process_t dl_process_args[ru->nb_tx][num_paralell_workers_per_antenna];
task_ans_t task_ans;
init_task_ans(&task_ans, num_paralell_workers_per_antenna * ru->nb_tx);
for (int aatx = 0; aatx < ru->nb_tx; aatx++) {
for (int i = 0; i < num_paralell_workers_per_antenna; i++) {
tasks[aatx][i].func = dl_symbol_process;
tasks[aatx][i].args = (void *)&dl_process_args[aatx][i];
dl_process_args[aatx][i].ru = ru;
dl_process_args[aatx][i].fp = fp;
dl_process_args[aatx][i].slot = slot;
dl_process_args[aatx][i].start_symbol = start_symbol + num_symbols / num_paralell_workers_per_antenna * i;
dl_process_args[aatx][i].num_symbols =
min(num_symbols / num_paralell_workers_per_antenna, num_symbols - (num_symbols / num_paralell_workers_per_antenna) * i);
dl_process_args[aatx][i].aatx = aatx;
dl_process_args[aatx][i].txdataF = txDataF_ptr[aatx];
dl_process_args[aatx][i].task_ans = &task_ans;
pushTpool(&oru->tpool, tasks[aatx][i]);
}
}
LOG_D(PHY,
"[RU_thread] transmit data: frame %d, slot %d, start_symbol %d, num_symbols %d, timestamp %ld\n",
frame,
slot,
start_symbol,
num_symbols,
timestamp_tx);
join_task_ans(&task_ans);
tx_rf_symbols(ru, frame, slot, timestamp_tx, start_symbol, num_symbols);
stop_meas(&ru->tx_fhaul);
}
void prepare_prach_item(ORU_t *oru)
{
AssertFatal(oru->ru != NULL, "ORU not configured\n");
AssertFatal(oru->ru->nr_frame_parms != NULL, "ORU not configured\n");
NR_DL_FRAME_PARMS *fp = oru->ru->nr_frame_parms;
RU_t *ru = oru->ru;
prach_item_t *prach_item = &oru->prach_item;
prach_item->num_slots = oru->prach_info.format < 4 ? get_long_prach_dur(oru->prach_info.format, fp->numerology_index) : 1;
prach_item->msg1_frequencystart = oru->prach_msg1_freq;
prach_item->mu = fp->numerology_index;
nfapi_nr_config_request_scf_t *cfg = &ru->config;
prach_item->prach_sequence_length = cfg->prach_config.prach_sequence_length.value;
prach_item->restricted_set = 0;
prach_item->numerology_index = fp->numerology_index;
prach_item->nb_rx = ru->nb_rx;
prach_item->rx_prach = &oru->rx_prach;
prach_item->beams[0] = 0; // TODO: Beamforming not supported yet
// Fill PRACH PDU
nfapi_nr_prach_pdu_t *prach_pdu = &prach_item->pdu;
prach_pdu->prach_start_symbol = oru->prach_info.start_symbol;
prach_pdu->num_prach_ocas = 1; // TODO: Hardcoded.
uint16_t format0 = oru->prach_info.format & 0xff;
uint16_t format1 = (oru->prach_info.format >> 8) & 0xff;
if (format1 != 0xff) {
switch (format0) {
case 0xa1:
prach_pdu->prach_format = 11;
break;
case 0xa2:
prach_pdu->prach_format = 12;
break;
case 0xa3:
prach_pdu->prach_format = 13;
break;
default:
AssertFatal(1 == 0, "Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
}
} else {
switch (format0) {
case 0:
prach_pdu->prach_format = 0;
break;
case 1:
prach_pdu->prach_format = 1;
break;
case 2:
prach_pdu->prach_format = 2;
break;
case 3:
prach_pdu->prach_format = 3;
break;
case 0xa1:
prach_pdu->prach_format = 4;
break;
case 0xa2:
prach_pdu->prach_format = 5;
break;
case 0xa3:
prach_pdu->prach_format = 6;
break;
case 0xb1:
prach_pdu->prach_format = 7;
break;
case 0xb4:
prach_pdu->prach_format = 8;
break;
case 0xc0:
prach_pdu->prach_format = 9;
break;
case 0xc2:
prach_pdu->prach_format = 10;
break;
default:
AssertFatal(1 == 0, "Invalid PRACH format");
}
}
}

78
executables/nr-oru.h Normal file
View File

@@ -0,0 +1,78 @@
/*
* 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 __NR_ORU_H__
#define __NR_ORU_H__
#include "PHY/defs_nr_common.h"
#include "openair1/PHY/defs_RU.h"
#include "thread-pool.h"
#include "common/utils/nr/nr_common.h"
#include "openair2/LAYER2/NR_MAC_COMMON/nr_prach_config.h"
typedef struct {
RU_t *ru;
/// tx carrier
uint64_t carrier_freq_tx[MAX_BANDS_PER_RRU];
/// rx carrier
uint64_t carrier_freq_rx[MAX_BANDS_PER_RRU];
/// tx BW in PRBs
int bw_tx[MAX_BANDS_PER_RRU];
/// rx BW in PRBs
int bw_rx[MAX_BANDS_PER_RRU];
/// 3GPP FRAME Type FDD/TDD
int frame_type;
/// 3GPP PRACH configuration index
int prach_config_index;
/// 3GPP MSG1 Start frequency
int prach_msg1_freq;
/// 3GPP TDD periodicity (0.5 ms, 1 0.625ms, 2 1ms, 3 1.25ms, 4 2ms,5 2.5ms, 6 5ms, 7 10ms, 8 3ms, 9 4ms
int tdd_period;
/// number of DL slots
int num_DL_slots;
/// number of UL slots
int num_UL_slots;
/// number of DL symbols
int num_DL_symbols;
/// number of UL symbols
int num_UL_symbols;
int numerology;
pthread_t north_read_thread;
pthread_t south_read_thread;
pthread_t oru_sync_thread;
int num_sync_messages_needed;
notifiedFIFO_t sync_fifo;
tpool_t tpool;
// PRACH related
nr_prach_info_t prach_info;
time_stats_t rx_prach;
time_stats_t rx;
prach_item_t prach_item;
} ORU_t;
int get_oru_options(ORU_t *oru);
void oru_init_frame_parms(ORU_t *oru);
void *oru_north_read_thread(void *arg);
void *oru_south_read_thread(void *arg);
void *oru_sync_thread(void *arg);
void prepare_prach_item(ORU_t *oru);
#endif

View File

@@ -708,7 +708,7 @@ static radio_tx_gpio_flag_t get_gpio_flags(RU_t *ru, int slot)
return flags_gpio;
}
void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
void tx_rf_symbols(RU_t *ru, int frame, int slot, uint64_t timestamp, int start_symbol, int num_symbols)
{
RU_proc_t *proc = &ru->proc;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
@@ -735,22 +735,23 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
txsymb++;
}
AssertFatal(txsymb>0,"illegal txsymb %d\n",txsymb);
AssertFatal(txsymb > 0, "illegal txsymb %d\n", txsymb);
if (fp->slots_per_subframe == 1) {
if (txsymb <= 7)
siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0) + (txsymb - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
else
siglen = 2 * (fp->ofdm_symbol_size + fp->nb_prefix_samples0) + (txsymb - 2) * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
} else {
if(slot%(fp->slots_per_subframe/2))
siglen = txsymb * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
else
siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0) + (txsymb - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
if (txsymb < start_symbol) {
// No DL symbols in this transmission
return;
}
//+ ru->end_of_burst_delay;
flags_burst = TX_BURST_END;
int end_symbol = start_symbol + num_symbols - 1;
if (end_symbol >= txsymb) {
flags_burst = TX_BURST_END;
} else {
flags_burst = TX_BURST_MIDDLE;
}
int num_symbols_this_transmission = min(txsymb, end_symbol) - start_symbol + 1;
siglen = get_samples_symbol_duration(fp, slot, start_symbol, num_symbols_this_transmission);
} else if (slot_type == NR_DOWNLINK_SLOT) {
int prevslot_type = nr_slot_select(cfg,frame,(slot+(fp->slots_per_frame-1))%fp->slots_per_frame);
int nextslot_type = nr_slot_select(cfg,frame,(slot+1)%fp->slots_per_frame);
@@ -762,9 +763,11 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
} else {
flags_burst = proc->first_tx == 1 ? TX_BURST_START : TX_BURST_MIDDLE;
}
siglen = get_samples_symbol_duration(fp, slot, start_symbol, num_symbols);
}
} else { // FDD
flags_burst = proc->first_tx == 1 ? TX_BURST_START : TX_BURST_MIDDLE;
siglen = get_samples_symbol_duration(fp, slot, start_symbol, num_symbols);
}
if (ru->openair0_cfg.gpio_controller != RU_GPIO_CONTROL_NONE)
@@ -779,8 +782,9 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
int nt = ru->nb_tx * ru->num_beams_period;
void *txp[nt];
uint32_t time_offset = get_samples_slot_timestamp(fp, slot) + get_samples_symbol_timestamp(fp, slot, start_symbol);
for (int i = 0; i < nt; i++)
txp[i] = (void *)&ru->common.txdata[i][get_samples_slot_timestamp(fp, slot)] - sf_extension * sizeof(int32_t);
txp[i] = (void *)&ru->common.txdata[i][time_offset] - sf_extension * sizeof(int32_t);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp + ru->ts_offset) & 0xffffffff);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1);
@@ -807,7 +811,12 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0);
}
static void fill_rf_config(RU_t *ru, char *rf_config_file)
void tx_rf(RU_t *ru, int frame, int slot, uint64_t timestamp)
{
tx_rf_symbols(ru, frame, slot, timestamp, 0, 14);
}
void fill_rf_config(RU_t *ru, char *rf_config_file)
{
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
nfapi_nr_config_request_scf_t *config = &ru->config; //tmp index
@@ -872,7 +881,7 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file)
}
}
static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_request_scf_t *config, const NR_DL_FRAME_PARMS *fp)
void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_request_scf_t *config, const NR_DL_FRAME_PARMS *fp)
{
const nfapi_nr_prach_config_t *prach_config = &config->prach_config;
const nfapi_nr_tdd_table_t *tdd_table = &config->tdd_table;
@@ -1555,8 +1564,13 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file)
}
}
PHY_VARS_gNB *gNB_RC = RC.gNB[0];
PHY_VARS_gNB *gNB0 = ru->gNB_list[0];
PHY_VARS_gNB *gNB_RC = NULL;
PHY_VARS_gNB *gNB0 = NULL;
if (RC.nb_nr_L1_inst > 0) {
gNB_RC = RC.gNB[0];
gNB0 = ru->gNB_list[0];
}
LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south);
if (gNB0) {
@@ -1793,6 +1807,7 @@ static void NRRCconfig_RU(configmodule_interface_t *cfg)
ru->num_bands = param[RU_BAND_LIST_IDX].numelt;
for (int i = 0; i < ru->num_bands; i++)
ru->band[i] = param[RU_BAND_LIST_IDX].iptr[i];
ru->openair0_cfg.nr_flag = *param[RU_NR_FLAG].iptr;
ru->openair0_cfg.nr_band = ru->band[0];
ru->openair0_cfg.nr_scs_for_raster = *param[RU_NR_SCS_FOR_RASTER].iptr;

View File

@@ -379,9 +379,6 @@ int stop_L1(module_id_t gnb_id)
if (RC.nb_nr_L1_inst > 0)
stop_gNB(RC.nb_nr_L1_inst);
if (RC.nb_RU > 0)
stop_RU(RC.nb_RU);
/* stop trx devices, multiple carrier currently not supported by RU */
if (ru->rfdevice.trx_get_stats_func) {
ru->rfdevice.trx_get_stats_func(&ru->rfdevice);
@@ -399,6 +396,9 @@ int stop_L1(module_id_t gnb_id)
LOG_I(GNB_APP, "turned off RU ifdevice\n");
}
if (RC.nb_RU > 0)
stop_RU(RC.nb_RU);
/* release memory used by the RU/gNB threads (incomplete), after all
* threads have been stopped (they partially use the same memory) */
for (int inst = 0; inst < RC.nb_RU; inst++) {

View File

@@ -33,20 +33,23 @@ void nr_phy_init_RU(RU_t *ru)
LOG_D(PHY, "Initializing RU signal buffers (if_south %s) nb_tx %d, nb_rx %d\n", ru_if_types[ru->if_south], ru->nb_tx, ru->nb_rx);
nfapi_nr_config_request_scf_t *cfg = &ru->config;
ru->nb_log_antennas = 0;
for (int n = 0; n < ru->num_gNB; n++) {
if (cfg->carrier_config.num_tx_ant.value > ru->nb_log_antennas)
ru->nb_log_antennas = cfg->carrier_config.num_tx_ant.value;
ru->num_beams_period = 1;
if (ru->num_gNB > 0) {
nfapi_nr_config_request_scf_t *cfg = &ru->config;
ru->nb_log_antennas = 0;
for (int n = 0; n < ru->num_gNB; n++) {
if (cfg->carrier_config.num_tx_ant.value > ru->nb_log_antennas)
ru->nb_log_antennas = cfg->carrier_config.num_tx_ant.value;
}
nfapi_nr_analog_beamforming_ve_t *analog_config = &cfg->analog_beamforming_ve;
ru->num_beams_period = analog_config->analog_bf_vendor_ext.value ? analog_config->num_beams_period_vendor_ext.value : 1;
}
else ru->nb_log_antennas = ru->nb_tx;
// copy configuration from gNB[0] in to RU, assume that all gNB instances sharing RU use the same configuration
// (at least the parts that are needed by the RU, numerology and PRACH)
AssertFatal(ru->nb_log_antennas > 0 && ru->nb_log_antennas < 13, "ru->nb_log_antennas %d ! \n",ru->nb_log_antennas);
nfapi_nr_analog_beamforming_ve_t *analog_config = &cfg->analog_beamforming_ve;
ru->num_beams_period = analog_config->analog_bf_vendor_ext.value ? analog_config->num_beams_period_vendor_ext.value : 1;
int nb_tx_streams = ru->nb_tx * ru->num_beams_period;
int nb_rx_streams = ru->nb_rx * ru->num_beams_period;
LOG_I(NR_PHY, "nb_tx_streams %d, nb_rx_streams %d, num_Beams_period %d\n", nb_tx_streams, nb_rx_streams, ru->num_beams_period);

View File

@@ -125,13 +125,15 @@ prach_item_t *nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_n
return prach;
}
static void rx_nr_prach_ru_internal(prach_item_t *p,
int beam_id,
int prachStartSymbol,
int prachOccasion,
int32_t **rxdata,
NR_DL_FRAME_PARMS *fp,
int N_TA_offset)
void rx_nr_prach_ru_internal(prach_item_t *p,
int beam_id,
int prachStartSymbol,
int prachOccasion,
int32_t **rxdata,
NR_DL_FRAME_PARMS *fp,
int N_TA_offset,
int rep_index,
uint reps)
{
int sample_offset_slot;
const int sum = fp->ofdm_symbol_size + fp->nb_prefix_samples;
@@ -158,7 +160,6 @@ static void rx_nr_prach_ru_internal(prach_item_t *p,
p->pdu.num_ra,
prachStartSymbol,
prachOccasion);
int reps;
int Ncp;
int dftlen;
int mu = p->numerology_index;
@@ -172,25 +173,21 @@ static void rx_nr_prach_ru_internal(prach_item_t *p,
p->msg1_frequencystart);
switch (p->pdu.prach_format) {
case 0:
reps = 1;
Ncp = 3168;
dftlen = 24576;
break;
case 1:
reps = 2;
Ncp = 21024;
dftlen = 24576;
break;
case 2:
reps = 4;
Ncp = 4688;
dftlen = 24576;
break;
case 3:
reps = 4;
Ncp = 3168;
dftlen = 6144;
break;
@@ -209,22 +206,18 @@ static void rx_nr_prach_ru_internal(prach_item_t *p,
prachStartSymbol);
switch (p->pdu.prach_format) {
case 4: // A1
reps = 2;
Ncp = 288 >> mu;
break;
case 5: // A2
reps = 4;
Ncp = 576 >> mu;
break;
case 6: // A3
reps = 6;
Ncp = 864 >> mu;
break;
case 7: // B1
reps = 2;
Ncp = 216 >> mu;
break;
@@ -242,17 +235,14 @@ static void rx_nr_prach_ru_internal(prach_item_t *p,
*/
case 8: // B4
reps = 12;
Ncp = 936 >> mu;
break;
case 9: // C0
reps = 1;
Ncp = 1240 >> mu;
break;
case 10: // C2
reps = 4;
Ncp = 2048 >> mu;
break;
@@ -366,18 +356,25 @@ static void rx_nr_prach_ru_internal(prach_item_t *p,
// do DFT
c16_t *prach2 = prach + Ncp;
c16_t rxsigF_tmp[N_ZC];
memset(rxsigF_tmp, 0, sizeof(rxsigF_tmp));
for (int i = 0; i < reps; i++, prach2 += dftlen) {
for (int i = 0; i < reps; i++) {
c16_t tmp[dftlen] __attribute__((aligned(32)));
dft(dftsize, (int16_t *)prach2, (int16_t *)tmp, 1);
dft(dftsize, (int16_t *)(prach2 + (rep_index + i) * dftlen), (int16_t *)tmp, 1);
// Coherent combining of PRACH repetitions (assumes channel does not change, to be revisted for "long" PRACH)
LOG_D(PHY, "Doing PRACH combining of %d reptitions N_ZC %d\n", reps, N_ZC);
// if (k+N_ZC > dftlen) { // PRACH signal is split around DC
int k2 = k;
for (int j = 0; j < N_ZC; j++, k2++) {
if (k2 == dftlen)
k2 = 0;
rxsigF_tmp[j] = c16add(rxsigF_tmp[j], tmp[k2]);
if (i == 0) {
for (int j = 0; j < N_ZC; j++, k2++) {
if (k2 == dftlen)
k2 = 0;
rxsigF_tmp[j] = tmp[k2];
}
} else {
for (int j = 0; j < N_ZC; j++, k2++) {
if (k2 == dftlen)
k2 = 0;
rxsigF_tmp[j] = c16add(rxsigF_tmp[j], tmp[k2]);
}
}
}
memcpy(p->rxsigF[prachOccasion][aa], rxsigF_tmp, sizeof(rxsigF_tmp));
@@ -394,7 +391,15 @@ void rx_nr_prach_ru(prach_item_t *p, int32_t **rxdata, NR_DL_FRAME_PARMS *fp, in
// comment FK: the standard 38.211 section 5.3.2 has one extra term +14*N_RA_slot. This is because there prachStartSymbol is
// given wrt to start of the 15kHz slot or 60kHz slot. Here we work slot based, so this function is anyway only called in slots
// where there is PRACH. Its up to the MAC to schedule another PRACH PDU in the case there are there N_RA_slot \in {0,1}.
rx_nr_prach_ru_internal(p, beam_id, prachStartSymbol, prach_oc, rxdata, fp, N_TA_offset);
rx_nr_prach_ru_internal(p,
beam_id,
prachStartSymbol,
prach_oc,
rxdata,
fp,
N_TA_offset,
0,
get_prach_num_reps(p->pdu.prach_format));
}
}

View File

@@ -175,6 +175,19 @@ int openair0_transport_load(openair0_device *device,
return rc;
}
int openair0_load(openair0_device *device, char *name, openair0_config_t *openair0_cfg, eth_params_t *eth_params)
{
loader_shlibfunc_t shlib_fdesc[1];
int ret = 0;
shlib_fdesc[0].fname = eth_params == NULL ? "device_init" : "transport_init";
ret = load_module_shlib(name, shlib_fdesc, 1, NULL);
AssertFatal((ret >= 0), "Library %s couldn't be loaded\n", name);
return ((devfunc_t)shlib_fdesc[0].fptr)(device, openair0_cfg, eth_params);
}
static void writerEnqueue(re_order_t *ctx, openair0_timestamp timestamp, void **txp, int nsamps, int nbAnt, int flags)
{
pthread_mutex_lock(&ctx->mutex_store);

View File

@@ -410,6 +410,14 @@ typedef struct {
} queue[WRITE_QUEUE_SZ];
} re_order_t;
/*! \brief Provides a way to map between a symbol and a timespec */
typedef struct {
int frame;
int slot;
int symbol;
struct timespec ts;
} sense_of_time_t;
/*!\brief structure holds the parameters to configure USRP devices */
struct openair0_device_t {
/*!tx write thread*/
@@ -594,6 +602,10 @@ struct openair0_device_t {
*/
int (*trx_stop_func)(openair0_device *device);
/*! \brief Get timestamp from timespec
*/
openair0_timestamp (*get_timestamp)(openair0_device *device, struct timespec *ts);
/* Functions API related to UE*/
/*! \brief Set RX feaquencies
@@ -680,6 +692,28 @@ struct openair0_device_t {
*/
time_stats_t tx_fhaul;
re_order_t reOrder;
// Function pointers used for oran
struct {
/*! \brief O-RU only: reads DL FD IQ. Data is put into the beginning of txdataF buffer regardless
* of the returned start_symbol. maximum number of symbols returned is 7
* \param txdataF An array of nb_tx buffers to write the samples to
* \param nb_tx number of TX antennas and number of buffer in txDataF_BF
* \param sense_of_time frame, slot and symbol with mapping to clock_gettime result
* \param num_symbols number of symbols
*/
void (*north_in_func)(uint32_t **txdataF, int nb_tx, sense_of_time_t* sense_of_time, int *num_symbols);
/*!
* \brief Write prach data for one PRACH symbol
* \param prachF Frequency domain PRACH data size 139 (only short format support)
* \param aarx
* \param frame
* \param slot
* \param symbol
*/
void (*write_prach)(uint32_t *prachF, int aarx, int frame, int slot, int symbol);
} xran_api;
};
/* type of device init function, implemented in shared lib */
@@ -730,7 +764,7 @@ const char *get_devname(int devtype);
int openair0_device_load(openair0_device *device, openair0_config_t *openair0_cfg);
/*! \brief Initialize transport protocol . It returns 0 if OK */
int openair0_transport_load(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params);
int openair0_load(openair0_device *device, char *name, openair0_config_t *openair0_cfg, eth_params_t *eth_params);
/*! \brief Get current timestamp of USRP
* \param device the hardware to use

View File

@@ -11,21 +11,28 @@ pkg_check_modules(numa REQUIRED numa)
add_library(oran_fhlib_5g MODULE
oran_isolate.c
oaioran_ru.c
oaioran.c
oran-config.c
oran-init.c
circular_buffer.c
iq_worker.c
oran_debug.c
)
set(E_VERSION 5.1.6)
set(F_VERSION 6.1.5)
set(K_VERSION 11.1.1)
find_package(xran REQUIRED)
if(xran_VERSION VERSION_EQUAL E_VERSION)
target_compile_definitions(oran_fhlib_5g PRIVATE E_RELEASE)
elseif(xran_VERSION VERSION_EQUAL F_VERSION)
target_compile_definitions(oran_fhlib_5g PRIVATE F_RELEASE)
elseif(xran_VERSION VERSION_EQUAL K_VERSION)
target_compile_definitions(oran_fhlib_5g PRIVATE K_RELEASE)
else()
message(FATAL_ERROR "Found xran version ${xran_VERSION} but needed ${E_VERSION} (E release) or ${F_VERSION} (F release)")
message(FATAL_ERROR "Found xran version ${xran_VERSION} but needed ${E_VERSION} (E release), ${F_VERSION} (F release) or ${K_VERSION} (K release)")
endif()
# Ignore xran-specific warning: we don't care/can't change the following warning, so suppress
@@ -34,7 +41,7 @@ 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} pthread dl rt m numa)
target_link_libraries(oran_fhlib_5g PRIVATE log_headers)
target_link_libraries(oran_fhlib_5g PRIVATE log_headers MAC_NR_COMMON)
target_include_directories(oran_fhlib_5g PRIVATE ${dpdk_INCLUDE_DIRS})
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
find_package(armral REQUIRED)

View File

@@ -0,0 +1,68 @@
/*
* 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 "circular_buffer.h"
#include <stdlib.h>
#include <string.h>
#include <malloc.h> // For memalign or _mm_malloc
#include "assertions.h"
void circular_buffer_init(circular_buffer_t *cb, int num_antennas, int num_slots, int num_symbols, int max_iq_samples)
{
cb->num_antennas = num_antennas;
cb->num_slots = num_slots;
cb->num_symbols = num_symbols;
cb->max_iq_samples = max_iq_samples;
cb->data = (uint32_t ****)malloc(num_antennas * sizeof(uint32_t ***));
for (int i = 0; i < num_antennas; i++) {
cb->data[i] = (uint32_t ***)malloc(num_slots * sizeof(uint32_t **));
for (int j = 0; j < num_slots; j++) {
cb->data[i][j] = (uint32_t **)malloc(num_symbols * sizeof(uint32_t *));
for (int k = 0; k < num_symbols; k++) {
cb->data[i][j][k] = (uint32_t *)memalign(64, max_iq_samples * sizeof(uint32_t));
memset(cb->data[i][j][k], 0, max_iq_samples * sizeof(uint32_t));
AssertFatal(cb->data[i][j][k] != NULL, "Failed to allocate memory for circular buffer data\n");
}
}
}
}
uint32_t *circular_buffer_get_data(circular_buffer_t *cb, int antenna, int slot, int symbol)
{
AssertFatal(antenna < cb->num_antennas, "Antenna index out of bounds\n");
AssertFatal(slot < cb->num_slots, "Slot index out of bounds\n");
AssertFatal(symbol < cb->num_symbols, "Symbol index out of bounds\n");
return cb->data[antenna][slot][symbol];
}
void circular_buffer_destroy(circular_buffer_t *cb)
{
for (int i = 0; i < cb->num_antennas; i++) {
for (int j = 0; j < cb->num_slots; j++) {
for (int k = 0; k < cb->num_symbols; k++) {
free(cb->data[i][j][k]);
}
free(cb->data[i][j]);
}
free(cb->data[i]);
}
}

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 __CIRCULAR_BUFFER_H__
#define __CIRCULAR_BUFFER_H__
#include <stdint.h>
typedef struct {
int num_antennas;
int num_slots;
int num_symbols;
int max_iq_samples;
uint32_t ****data;
} circular_buffer_t;
void circular_buffer_init(circular_buffer_t *cb, int num_antennas, int num_slots, int num_symbols, int max_iq_samples);
uint32_t *circular_buffer_get_data(circular_buffer_t *cb, int antenna, int slot, int symbol);
void circular_buffer_destroy(circular_buffer_t *cb);
#endif

132
radio/fhi_72/iq_worker.c Normal file
View File

@@ -0,0 +1,132 @@
/*
* 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 "iq_worker.h"
#include "system.h"
#include "xran_compression.h"
#include "xran_fh_o_du.h"
#include "xran_up_api.h"
#include <asm-generic/errno.h>
#include <netinet/in.h>
#include <pthread.h>
#include <rte_mbuf.h>
#include <rte_ring.h>
#include <rte_ring_core.h>
#include <rte_cycles.h>
#include <rte_errno.h>
#include <rte_eal.h>
#include <rte_lcore.h>
#include <rte_malloc.h>
#include "assertions.h"
#include <stdint.h>
#include <log.h>
#define DECOMPRESSION_RING_SIZE 1024
#define DECOMPRESSION_BURST_SIZE 32
// Static buffer for decompression tasks
typedef struct {
int comp_method;
int iq_width;
int num_iq;
void *input_buffer;
void *output_buffer;
void *mbuf;
} iq_task_t;
typedef struct {
struct rte_ring *ring;
iq_task_t iq_task_buffer[DECOMPRESSION_RING_SIZE];
pthread_t thread;
uint64_t buffer_idx;
bool stop;
} iq_woker_context_t;
static iq_woker_context_t iq_worker_context;
static void *iq_worker_thread(void *arg)
{
iq_woker_context_t *context = (iq_woker_context_t *)arg;
iq_task_t *tasks[DECOMPRESSION_BURST_SIZE];
uint32_t num_dequeued;
while (!context->stop) {
num_dequeued = rte_ring_dequeue_burst(context->ring, (void **)tasks, DECOMPRESSION_BURST_SIZE, NULL);
if (num_dequeued != 0) {
LOG_D(HW, "Dequeued %d tasks\n", num_dequeued);
}
if (num_dequeued == 0) {
rte_pause();
continue;
}
for (uint32_t i = 0; i < num_dequeued; i++) {
AssertFatal(tasks[i]->comp_method == XRAN_COMPMETHOD_NONE, "Unsupported compression method: %d", tasks[i]->comp_method);
uint16_t *source = (uint16_t *)tasks[i]->input_buffer;
int16_t *destination = (int16_t *)tasks[i]->output_buffer;
for (int j = 0; j < tasks[i]->num_iq * 2; j++) {
destination[j] = (int16_t)ntohs(source[j]);
}
rte_pktmbuf_free(tasks[i]->mbuf);
}
}
return 0;
}
int iq_worker_init(void)
{
memset(&iq_worker_context, 0, sizeof(iq_worker_context));
iq_worker_context.ring = rte_ring_create("iq_worker_ring", DECOMPRESSION_RING_SIZE, SOCKET_ID_ANY, RING_F_SP_ENQ | RING_F_SC_DEQ);
if (iq_worker_context.ring == NULL) {
rte_exit(EXIT_FAILURE, "Cannot create decompression ring: %s\n", rte_strerror(rte_errno));
}
threadCreate(&iq_worker_context.thread, iq_worker_thread, &iq_worker_context, "oran_iq_worker", -1, OAI_PRIORITY_RT_MAX);
return 0;
}
void iq_worker_destroy(void)
{
iq_worker_context.stop = true;
rte_ring_free(iq_worker_context.ring);
int ret = pthread_join(iq_worker_context.thread, NULL);
AssertFatal(ret == 0, "pthread_join failed: %d", ret);
}
void iq_worker_enqueue(int comp_method, int iq_width, int num_iq, void *input_buffer, void *output_buffer, void *mbuf)
{
int buffer_index = iq_worker_context.buffer_idx++ % DECOMPRESSION_RING_SIZE;
iq_task_t *task = &iq_worker_context.iq_task_buffer[buffer_index];
task->comp_method = comp_method;
task->iq_width = iq_width;
task->num_iq = num_iq;
task->input_buffer = input_buffer;
task->output_buffer = output_buffer;
task->mbuf = mbuf;
int ret = rte_ring_enqueue(iq_worker_context.ring, task);
if (ret == ENOBUFS) {
LOG_W(HW, "iq_worker is too slow\n");
rte_pktmbuf_free(mbuf);
}
}

29
radio/fhi_72/iq_worker.h Normal file
View File

@@ -0,0 +1,29 @@
/*
* 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 __IQ_WORKER_H__
#define __IQ_WORKER_H__
int iq_worker_init(void);
void iq_worker_destroy(void);
void iq_worker_enqueue(int comp_method, int iq_width, int num_iq, void *input_buffer, void *output_buffer, void *mbuf);
#endif

View File

@@ -10,6 +10,8 @@ if(xran_VERSION VERSION_EQUAL E_VERSION)
target_compile_definitions(oran_fhlib_5g_mplane PRIVATE E_RELEASE)
elseif(xran_VERSION VERSION_EQUAL F_VERSION)
target_compile_definitions(oran_fhlib_5g_mplane PRIVATE F_RELEASE)
elseif(xran_VERSION VERSION_EQUAL K_VERSION)
target_compile_definitions(oran_fhlib_5g_mplane PRIVATE K_RELEASE)
endif()
# Ignore xran-specific warning: we don't care/can't change the following warning, so suppress

View File

@@ -51,13 +51,24 @@
// Declare variable useful for the send buffer function
volatile bool first_call_set = false;
int xran_is_prach_slot(uint8_t PortId, uint32_t subframe_id, uint32_t slot_id);
int xran_is_prach_slot(uint8_t PortId, uint32_t subframe_id, uint32_t slot_id
#ifdef K_RELEASE
, uint8_t mu
#endif
);
#include "common/utils/LOG/log.h"
#ifndef USE_POLLING
extern notifiedFIFO_t oran_sync_fifo;
#ifdef K_RELEASE
extern notifiedFIFO_t oran_sync_fifo_prach;
#endif
#else
volatile oran_sync_info_t oran_sync_info = {0};
#ifdef K_RELEASE
volatile oran_sync_info_t oran_sync_info_prach = {0};
volatile bool prach_rx_awaiting = false;
#endif
#endif
/** @details xran-specific callback, called when all packets for given CC and
@@ -65,7 +76,11 @@ volatile oran_sync_info_t oran_sync_info = {0};
* timing information and unblock another thread in xran_fh_rx_read_slot()
* through either a message queue, or writing in global memory with polling, on
* a full slot boundary. */
void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status)
void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status
#ifdef K_RELEASE
, uint8_t mu
#endif
)
{
struct xran_cb_tag *callback_tag = (struct xran_cb_tag *)pCallbackTag;
@@ -75,9 +90,13 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status)
const struct xran_fh_init *fh_init = get_xran_fh_init();
int num_ports = fh_init->xran_ports;
#ifdef K_RELEASE
const int slots_in_sf = 1 << mu;
#elif defined(E_RELEASE) || defined(F_RELEASE)
/* assuming all RUs have the same numerology */
const struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
const int slots_in_sf = 1 << fh_cfg->frame_conf.nNumerology;
#endif
const int sf_in_frame = 10;
static int rx_RU[XRAN_PORTS_NUM][160] = {0};
@@ -92,7 +111,7 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status)
LOG_D(HW, "rx_callback at %4d.%3d (subframe %d), rx_sym %d ru_id %d\n", frame, slot, subframe, rx_sym, ru_id);
if (rx_sym == 7) { // in F release this value is defined as XRAN_FULL_CB_SYM (full slot (offset + 7))
#ifdef F_RELEASE
#if defined(F_RELEASE) || defined(K_RELEASE)
for (int ru_idx = 0; ru_idx < num_ports; ru_idx++) {
struct xran_fh_config *fh_config = get_xran_fh_config(ru_idx);
oran_buf_list_t *bufs = get_xran_buffers(ru_idx);
@@ -101,12 +120,14 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status)
struct xran_prb_map *pRbMap = (struct xran_prb_map *)bufs->dstcp[ant_id][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData;
AssertFatal(pRbMap != NULL, "(%d:%d:%d)pRbMap == NULL. Aborting.\n", cc_id, tti % XRAN_N_FE_BUF_LEN, ant_id);
#ifdef F_RELEASE
for (uint32_t sym_id = 0; sym_id < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_id++) {
for (uint32_t idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++ ) {
struct xran_prb_elm *pRbElm = &pRbMap->prbMap[idxElm];
pRbElm->nSecDesc[sym_id] = 0; // number of section descriptors per symbol; M-plane info <supported-section-types>
}
}
#endif
}
}
}
@@ -135,6 +156,26 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status)
info->tti = tti;
info->sl = slot2;
info->f = frame;
#ifdef K_RELEASE
info->mu = mu;
oran_buf_list_t *bufs = get_xran_buffers(ru_id);
struct xran_fh_config *fh_config = get_xran_fh_config(ru_id);
for (uint16_t cc_id = 0; cc_id < 1 /* fh_config->nCC */; cc_id++) { // OAI does not support multiple CC yet.
for(uint32_t ant_id = 0; ant_id < fh_config->neAxc; ant_id++) {
struct xran_prb_map *pRbMap = (struct xran_prb_map *)bufs->dstcp[ant_id][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData;
AssertFatal(pRbMap != NULL, "(%d:%d:%d)pRbMap == NULL. Aborting.\n", cc_id, tti % XRAN_N_FE_BUF_LEN, ant_id);
// struct xran_prb_map *pRbMapPrach = (struct xran_prb_map *)bufs->prachdstdecomp[ant_id][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData;
// AssertFatal(pRbMapPrach != NULL, "(%d:%d:%d)pRbMapPrach == NULL. Aborting.\n", cc_id, tti % XRAN_N_FE_BUF_LEN, ant_id);
for (uint32_t sym_id = 0; sym_id < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_id++) {
info->nRxPkt[cc_id][ant_id][sym_id] = pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt;
pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt = 0;
// AssertFatal(pRbMapPrach->sFrontHaulRxPacketCtrl[sym_id].nRxPkt <= 1, "PRACH segmentation is not supported\n");
// pRbMapPrach->sFrontHaulRxPacketCtrl[sym_id].nRxPkt = 0;
}
}
}
#endif
LOG_D(HW, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot);
pushNotifiedFIFO(&oran_sync_fifo, req);
#else
@@ -142,6 +183,26 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status)
oran_sync_info.tti = tti;
oran_sync_info.sl = slot2;
oran_sync_info.f = frame;
#ifdef K_RELEASE
oran_sync_info.mu = mu;
oran_buf_list_t *bufs = get_xran_buffers(ru_id);
struct xran_fh_config *fh_config = get_xran_fh_config(ru_id);
for (uint16_t cc_id = 0; cc_id < 1 /* fh_config->nCC */; cc_id++) { // OAI does not support multiple CC yet.
for(uint32_t ant_id = 0; ant_id < fh_config->neAxc; ant_id++) {
struct xran_prb_map *pRbMap = (struct xran_prb_map *)bufs->dstcp[ant_id][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData;
AssertFatal(pRbMap != NULL, "(%d:%d:%d)pRbMap == NULL. Aborting.\n", cc_id, tti % XRAN_N_FE_BUF_LEN, ant_id);
// struct xran_prb_map *pRbMapPrach = (struct xran_prb_map *)bufs->prachdstdecomp[ant_id][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData;
// AssertFatal(pRbMapPrach != NULL, "(%d:%d:%d)pRbMapPrach == NULL. Aborting.\n", cc_id, tti % XRAN_N_FE_BUF_LEN, ant_id);
for (uint32_t sym_id = 0; sym_id < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_id++) {
oran_sync_info.nRxPkt[cc_id][ant_id][sym_id] = pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt;
pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt = 0;
// AssertFatal(pRbMapPrach->sFrontHaulRxPacketCtrl[sym_id].nRxPkt <= 1, "PRACH segmentation is not supported\n");
// pRbMapPrach->sFrontHaulRxPacketCtrl[sym_id].nRxPkt = 0;
}
}
}
#endif
#endif
} else
LOG_E(HW, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot);
@@ -150,9 +211,112 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status)
} // rx_sym == 7
}
void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t status
#ifdef K_RELEASE
, uint8_t mu
#endif
)
{
#ifdef K_RELEASE
struct xran_cb_tag *callback_tag = (struct xran_cb_tag *)pCallbackTag;
static int32_t last_slot = -1;
// static int32_t last_frame = -1;
const struct xran_fh_init *fh_init = get_xran_fh_init();
int num_ports = fh_init->xran_ports;
const int slots_in_sf = 1 << mu;
const int sf_in_frame = 10;
static int rx_RU[XRAN_PORTS_NUM][160] = {0};
uint32_t tti = callback_tag->slotiId;
uint32_t frame = XranGetFrameNum(tti, 0, sf_in_frame, slots_in_sf);
uint32_t subframe = XranGetSubFrameNum(tti, slots_in_sf, sf_in_frame);
uint32_t slot = XranGetSlotNum(tti, slots_in_sf);
uint32_t rx_sym = callback_tag->symbol & 0xFF;
uint32_t ru_id = callback_tag->oXuId;
LOG_D(HW, "prach_rx_callback at %4d.%3d (subframe %d), rx_sym %d ru_id %d\n", frame, slot, subframe, rx_sym, ru_id);
// if xran did not call xran_physide_dl_tti callback, it's not ready yet.
// wait till first callback to advance counters, because otherwise users
// would see periodic output with only "0" in stats counters
if (!first_call_set)
return;
uint32_t slot2 = slot + (subframe * slots_in_sf);
rx_RU[ru_id][slot2] = 1;
// if (last_frame > 0 && frame > 0
// && ((slot2 > 0 && last_frame != frame) || (slot2 == 0 && last_frame != ((1024 + frame - 1) & 1023))))
// LOG_E(HW, "Jump in frame counter last_frame %d => %d, slot %d\n", last_frame, frame, slot2);
for (int i = 0; i < num_ports; i++) {
if (rx_RU[i][slot2] == 0)
return;
}
for (int i = 0; i < num_ports; i++)
rx_RU[i][slot2] = 0;
if (last_slot == -1 || slot2 != last_slot) {
#ifndef USE_POLLING
notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(oran_sync_info_t), 0, &oran_sync_fifo_prach, NULL);
oran_sync_info_t *info = NotifiedFifoData(req);
info->tti = tti;
info->sl = slot2;
info->f = frame;
info->mu = mu;
#else
LOG_D(HW, "Writing PRACH slot %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot);
oran_sync_info_prach.tti = tti;
oran_sync_info_prach.sl = slot2;
oran_sync_info_prach.f = frame;
oran_sync_info_prach.mu = mu;
#endif
int32_t ntti = (tti + XRAN_N_FE_BUF_LEN - 1) % XRAN_N_FE_BUF_LEN;
struct xran_cb_tag *callback_tag = (struct xran_cb_tag *)pCallbackTag;
uint32_t tti = callback_tag->slotiId;
uint32_t ru_id = callback_tag->oXuId;
oran_buf_list_t *bufs = get_xran_buffers(ru_id);
struct xran_fh_config *fh_config = get_xran_fh_config(ru_id);
for (uint16_t cc_id = 0; cc_id < 1 /* fh_config->nCC */; cc_id++) { // OAI does not support multiple CC yet.
for(uint32_t ant_id = 0; ant_id < fh_config->neAxc; ant_id++) {
struct xran_prb_map *pRbMap = (struct xran_prb_map *)bufs->prachdstdecomp[ant_id][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData;
AssertFatal(pRbMap != NULL, "(%d:%d:%d)pRbMapPrach == NULL. Aborting.\n", cc_id, tti % XRAN_N_FE_BUF_LEN, ant_id);
struct xran_prb_map *pRbMap_prev = (struct xran_prb_map *)bufs->prachdstdecomp[ant_id][ntti].pBuffers->pData;
AssertFatal(pRbMap_prev != NULL, "(%d:%d:%d)pRbMapPrach == NULL. Aborting.\n", cc_id, ntti, ant_id);
for (uint32_t sym_id = 0; sym_id < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_id++) {
AssertFatal(pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt <= 1, "PRACH segmentation is not supported\n");
#ifndef USE_POLLING
info->nRxPkt[cc_id][ant_id][sym_id] = pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt;
#else
oran_sync_info_prach.nRxPkt[cc_id][ant_id][sym_id] = pRbMap->sFrontHaulRxPacketCtrl[sym_id].nRxPkt;
#endif
pRbMap_prev->sFrontHaulRxPacketCtrl[sym_id].nRxPkt = 0; // Clear nRxPkt of previous slot.
}
}
}
#ifndef USE_POLLING
LOG_D(HW, "Push PRACH slot %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot);
pushNotifiedFIFO(&oran_sync_fifo_prach, req);
#else
prach_rx_awaiting = true;
#endif
} else
LOG_E(HW, "Cannot Push PRACH slot %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot);
last_slot = slot2;
// last_frame = frame;
#elif defined(E_RELEASE) || defined(F_RELEASE)
rte_pause();
#endif
}
/** @details Only used to unblock timing in oai_xran_fh_rx_callback() on first
* call. */
int oai_physide_dl_tti_call_back(void *param)
int oai_physide_dl_tti_call_back(void *param
#ifdef K_RELEASE
, uint8_t mu
#endif
)
{
if (!first_call_set)
LOG_I(HW, "first_call set from phy cb\n");
@@ -165,8 +329,59 @@ int oai_physide_dl_tti_call_back(void *param)
* @details Reads PRACH data from xran-specific buffers and, if I/Q compression
* (bitwidth < 16 bits) is configured, uncompresses the data. Places PRACH data
* in OAI buffer. */
static int read_prach_data(ru_info_t *ru, int frame, int slot)
static int read_prach_data(ru_info_t *ru
#if defined(E_RELEASE) || defined(F_RELEASE)
, int frame, int slot
#endif
)
{
#ifdef K_RELEASE
#ifndef USE_POLLING
// pull next even from oran_sync_fifo_prach if any
notifiedFIFO_elt_t *res = pollNotifiedFIFO(&oran_sync_fifo_prach);
if (res == NULL) {
return (0);
}
notifiedFIFO_elt_t *f;
while ((f = pollNotifiedFIFO(&oran_sync_fifo_prach)) != NULL) {
oran_sync_info_t *old_info = NotifiedFifoData(res);
oran_sync_info_t *new_info = NotifiedFifoData(f);
LOG_E(HW, "Detected double PRACH sync message %d.%d => %d.%d\n", old_info->f, old_info->sl, new_info->f, new_info->sl);
delNotifiedFIFO_elt(res);
res = f;
}
oran_sync_info_t *info = NotifiedFifoData(res);
int slot = info->sl;
int frame = info->f;
uint8_t mu = info->mu;
delNotifiedFIFO_elt(res);
#else
#error "POLLING is not supported for K release unless you know how to fix the race condition on prach_rx_awaiting"
if (!prach_rx_awaiting) {
return (0);
} else {
prach_rx_awaiting = false;
}
int slot = oran_sync_info_prach.sl;
int frame = oran_sync_info_prach.f;
uint8_t mu = oran_sync_info_prach.mu;
uint32_t tti_in = oran_sync_info_prach.tti;
static int last_slot = -1;
LOG_D(HW, "oran slot %d, last_slot %d\n", *slot, last_slot);
int cnt = 0;
// while (*slot == last_slot) {
while (tti_in == oran_sync_info_prach.tti) {
//*slot = oran_sync_info.sl;
cnt++;
}
LOG_D(HW, "cnt %d, Reading %d.%d\n", cnt, *frame, *slot);
last_slot = *slot;
#endif
#endif
/* calculate tti and subframe_id from frame, slot num */
int sym_idx = 0;
@@ -174,6 +389,17 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot)
struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
nr_prach_info_t prach_info = get_prach_info(0);
struct xran_ru_config *ru_conf = &fh_cfg->ru_conf;
#ifdef K_RELEASE
int slots_per_frame = 10 << mu;
int slots_per_subframe = 1 << mu;
int tti = slots_per_frame * (frame) + (slot);
uint32_t subframe = slot / slots_per_subframe;
// PRACH occasion in a frame if and only if SFN % x == y, TS 38.211 Table 6.3.3.2-2/3/4
uint32_t is_prach_frame = (frame % prach_info.x == prach_info.y);
uint32_t is_prach_slot = is_prach_frame && xran_is_prach_slot(0, subframe, (slot % slots_per_subframe), mu);
#elif defined(E_RELEASE) || defined(F_RELEASE)
int slots_per_frame = 10 << fh_cfg->frame_conf.nNumerology;
int slots_per_subframe = 1 << fh_cfg->frame_conf.nNumerology;
@@ -182,22 +408,45 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot)
// PRACH occasion in a frame if and only if SFN % x == y, TS 38.211 Table 6.3.3.2-2/3/4
uint32_t is_prach_frame = (frame % prach_info.x == prach_info.y);
uint32_t is_prach_slot = is_prach_frame && xran_is_prach_slot(0, subframe, (slot % slots_per_subframe));
#endif
int nb_rx_per_ru = ru->nb_rx / fh_init->xran_ports;
/* If it is PRACH slot, copy prach IQ from XRAN PRACH buffer to OAI PRACH buffer */
if (is_prach_slot) {
if (!ru->prach_buf) {
LOG_W(HW, "we get rach data from ru, but it is not scheduled %d.%d\n", frame, slot);
return -1;
}
for (sym_idx = 0; sym_idx < prach_info.N_dur; sym_idx++) {
for (int aa = 0; aa < ru->nb_rx; aa++) {
for (int aa = 0; aa < ru->nb_rx; aa++) {
for (sym_idx = 0; sym_idx < prach_info.N_dur; sym_idx++) {
int16_t *dst, *src;
int idx = 0;
oran_buf_list_t *bufs = get_xran_buffers(aa / nb_rx_per_ru);
// hardcoded to use only first prach occasion
dst = (int16_t *)ru->prach_buf[0][aa];
#ifdef K_RELEASE
struct xran_prb_map * pPrbMap = (struct xran_prb_map *)bufs->prachdstdecomp[aa % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData;
struct xran_rx_packet_ctl *p_rx_packet_ctl = &pPrbMap->sFrontHaulRxPacketCtrl[sym_idx];
if (p_rx_packet_ctl->nRxPkt == 0) {
//LOG_E(HW, "read_prach %d.%d.%d saa = %d: nRxPkt = 0!\n", frame, slot, sym_idx, aa); // comment out as this happens at the beginning
memset(&dst[sym_idx], 0, 139 * 2 * sizeof(*dst));
continue;
} else if (p_rx_packet_ctl->nRxPkt > 1) { // protection
LOG_E(HW, "read_prach %d.%d.%d saa = %d: nRxPkt = %d!\n", frame, slot, sym_idx, aa, p_rx_packet_ctl->nRxPkt);
memset(&dst[sym_idx], 0, 139 * 2 * sizeof(*dst));
continue;
} else {
src = (int16_t *)p_rx_packet_ctl->pData[0];
if (src == NULL) { // protection
LOG_E(HW, "read_prach %d.%d.%d saa = %d: src = NULL!!\n", frame, slot, sym_idx, aa);
memset(&dst[sym_idx], 0, 139 * 2 * sizeof(*dst));
continue;
}
}
#elif defined(E_RELEASE) || defined(F_RELEASE)
src = (int16_t *)bufs->prachdstdecomp[aa % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers[sym_idx].pData;
#endif
/* convert Network order to host order */
if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_NONE) {
if (sym_idx == 0) {
@@ -310,10 +559,16 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
*slot = info->sl;
*frame = info->f;
#ifdef K_RELEASE
uint8_t mu = info->mu;
#endif
delNotifiedFIFO_elt(res);
#else
*slot = oran_sync_info.sl;
*frame = oran_sync_info.f;
#ifdef K_RELEASE
uint8_t mu = oran_sync_info.mu;
#endif
uint32_t tti_in = oran_sync_info.tti;
static int last_slot = -1;
@@ -330,15 +585,28 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
// return(0);
struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
#ifdef K_RELEASE
int slots_per_frame = 10 << mu;
#elif defined(E_RELEASE) || defined(F_RELEASE)
int slots_per_frame = 10 << fh_cfg->frame_conf.nNumerology;
#endif
int tti = slots_per_frame * (*frame) + (*slot);
read_prach_data(ru, *frame, *slot);
read_prach_data(ru
#if defined(E_RELEASE) || defined(F_RELEASE)
, *frame, *slot
#endif
);
const struct xran_fh_init *fh_init = get_xran_fh_init();
#ifdef K_RELEASE
int nPRBs = fh_cfg->perMu[mu].nULRBs;
int fftsize = 1 << fh_cfg->ru_conf.fftSize[mu];
#elif defined(E_RELEASE) || defined(F_RELEASE)
int nPRBs = fh_cfg->nULRBs;
int fftsize = 1 << fh_cfg->nULFftSize;
#endif
int slot_offset_rxdata = 3 & (*slot);
uint32_t slot_size = 4 * 14 * fftsize;
@@ -368,52 +636,80 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
struct xran_prb_elm *pRbElm = &pPrbMap->prbMap[0];
#ifdef E_RELEASE
struct xran_section_desc *p_sec_desc = pRbElm->p_sec_desc[sym_idx][0];
#elif defined F_RELEASE
#elif defined(F_RELEASE)
struct xran_section_desc *p_sec_desc = &pRbElm->sec_desc[sym_idx][0];
#elif defined(K_RELEASE)
struct xran_rx_packet_ctl *p_rx_packet_ctl = &pPrbMap->sFrontHaulRxPacketCtrl[sym_idx];
#endif
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 = bufs->dst[ant_id % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN]
.pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT]
.pData;
else
pData = p_sec_desc->pData;
ptr = pData;
pos = (int32_t *)(start_ptr + (4 * sym_idx * fftsize));
if (ptr == NULL || pos == NULL)
continue;
#ifdef K_RELEASE
#ifndef USE_POLLING
int32_t nRxPkt = RTE_MAX(p_rx_packet_ctl->nRxPkt, info->nRxPkt[cc_id][ant_id][sym_idx]);
#else
int32_t nRxPkt = RTE_MAX(p_rx_packet_ctl->nRxPkt, oran_sync_info.nRxPkt[cc_id][ant_id][sym_idx]);
#endif
LOG_D(HW, "nRxPkt %d\n", nRxPkt);
for (int pkt_idx = 0; pkt_idx < nRxPkt; pkt_idx++) {
if (fh_init->mtu < p_rx_packet_ctl->nRBSize[pkt_idx] * one_rb_size)
#elif defined(E_RELEASE) || defined(F_RELEASE)
struct xran_prb_map *pRbMap = pPrbMap;
uint32_t idxElm = 0;
uint8_t *src = (uint8_t *)ptr;
LOG_D(HW, "pRbMap->nPrbElm %d\n", pRbMap->nPrbElm);
uint32_t idxElm = 0;
for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) {
if (fh_init->mtu < pRbElm->nRBSize * one_rb_size)
#endif
pData = bufs->dst[ant_id % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN]
.pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT]
.pData;
else
#ifdef K_RELEASE
pData = p_rx_packet_ctl->pData[pkt_idx];
#elif defined(E_RELEASE) || defined(F_RELEASE)
pData = p_sec_desc->pData;
#endif
ptr = pData;
pos = (int32_t *)(start_ptr + (4 * sym_idx * fftsize));
if (ptr == NULL || pos == NULL)
continue;
uint8_t *src = (uint8_t *)ptr;
#ifdef K_RELEASE
uint16_t nRBStart = p_rx_packet_ctl->nRBStart[pkt_idx];
uint16_t nRBSize = p_rx_packet_ctl->nRBSize[pkt_idx];
LOG_D(HW,
"Packet %d : PRBstart %d nPRBs %d\n",
pkt_idx,
nRBStart,
nRBSize);
#elif defined(E_RELEASE) || defined(F_RELEASE)
int16_t nRBStart = pRbMap->prbMap[idxElm].nRBStart;
int16_t nRBSize = pRbMap->prbMap[idxElm].nRBSize;
LOG_D(HW,
"prbMap[%d] : PRBstart %d nPRBs %d\n",
idxElm,
pRbMap->prbMap[idxElm].nRBStart,
pRbMap->prbMap[idxElm].nRBSize);
nRBStart,
nRBSize);
pRbElm = &pRbMap->prbMap[idxElm];
#endif
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;
if (nRBStart < (nPRBs >> 1)) // there are PRBs left of DC
neg_len = min((nPRBs * 6) - (nRBStart * 12), nRBSize * N_SC_PER_PRB);
pos_len = (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));
uint8_t *dst1 = (uint8_t *)(pos + (neg_len == 0 ? ((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)));
uint8_t *dst2 = (uint8_t *)(pos + (nRBStart * N_SC_PER_PRB) + fftsize - (nPRBs * 6));
int32_t local_dst[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++)
for (idx = 0; idx < 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);
@@ -422,10 +718,10 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
struct xranlib_decompress_request bfp_decom_req = {};
struct xranlib_decompress_response bfp_decom_rsp = {};
int16_t payload_len = (3 * pRbElm->iqWidth + 1) * pRbElm->nRBSize;
int16_t payload_len = (3 * pRbElm->iqWidth + 1) * nRBSize;
bfp_decom_req.data_in = (int8_t *)src;
bfp_decom_req.numRBs = pRbElm->nRBSize;
bfp_decom_req.numRBs = nRBSize;
bfp_decom_req.len = payload_len;
bfp_decom_req.compMethod = pRbElm->compMethod;
bfp_decom_req.iqWidth = pRbElm->iqWidth;
@@ -435,7 +731,7 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
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);
armral_bfp_decompression(pRbElm->iqWidth, nRBSize, (int8_t *)src, (int16_t *)local_dst);
#else
AssertFatal(1 == 0, "BFP compression not supported on this architecture");
#endif
@@ -446,7 +742,11 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
printf("pRbElm->compMethod == %d is not supported\n", pRbElm->compMethod);
exit(-1);
}
}
#ifdef K_RELEASE
} // pkt_idx < nRxPkt
#elif defined(E_RELEASE) || defined(F_RELEASE)
} // idxElm < pRbMap->nPrbElm
#endif
} // sym_ind
} // ant_ind
} // vv_inf
@@ -472,6 +772,18 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
x_counters[o_xu_id].rx_pusch_packets[rxant],
rxant,
x_counters[o_xu_id].rx_prach_packets[rxant]);
#ifdef K_RELEASE
LOG_I(HW,
"[%s%d][drop errors %7d ecpri errors %7d cp errors %7d up errors %7d pusch errors %7d prach errors %7d]\n",
"o_du",
o_xu_id,
x_counters[o_xu_id].rx_err_drop,
x_counters[o_xu_id].rx_err_ecpri,
x_counters[o_xu_id].rx_err_cp,
x_counters[o_xu_id].rx_err_up,
x_counters[o_xu_id].rx_err_pusch,
x_counters[o_xu_id].rx_err_prach);
#endif
if (x_counters[o_xu_id].rx_counter > old_rx_counter[o_xu_id])
old_rx_counter[o_xu_id] = x_counters[o_xu_id].rx_counter;
if (x_counters[o_xu_id].tx_counter > old_tx_counter[o_xu_id])
@@ -495,8 +807,14 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp)
const struct xran_fh_init *fh_init = get_xran_fh_init();
const struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
#ifdef K_RELEASE
uint8_t mu_number = fh_cfg->mu_number[0];
int nPRBs = fh_cfg->perMu[mu_number].nDLRBs;
int fftsize = 1 << fh_cfg->perMu[mu_number].nDLFftSize;
#elif defined(E_RELEASE) || defined(F_RELEASE)
int nPRBs = fh_cfg->nDLRBs;
int fftsize = 1 << fh_cfg->nDLFftSize;
#endif
int nb_tx_per_ru = ru->nb_tx / fh_init->xran_ports;
int nb_rx_per_ru = ru->nb_rx / fh_init->xran_ports;
@@ -595,8 +913,10 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp)
// assumes one fragment per symbol
#ifdef E_RELEASE
p_sec_desc = p_prbMapElm->p_sec_desc[sym_id][0];
#elif F_RELEASE
#elif defined(F_RELEASE)
p_sec_desc = &p_prbMapElm->sec_desc[sym_id][0];
#elif defined(K_RELEASE)
p_sec_desc = &p_prbMapElm->sec_desc[sym_id];
#endif
dst = xran_add_hdr_offset(dst, p_prbMapElm->compMethod);

View File

@@ -29,11 +29,29 @@ typedef struct {
uint32_t tti;
uint32_t sl;
uint32_t f;
#ifdef K_RELEASE
uint8_t mu;
int32_t nRxPkt[XRAN_MAX_SECTOR_NR][XRAN_MAX_ANTENNA_NR][XRAN_NUM_OF_SYMBOL_PER_SLOT];
#endif
} oran_sync_info_t;
/** @brief xran callback for fronthaul RX, see xran_5g_fronthault_config(). */
void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status);
void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status
#ifdef K_RELEASE
, uint8_t mu
#endif
);
/** @brief xran callback for fronthaul PRACH RX, see xran_5g_prach_req(). */
void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t status
#ifdef K_RELEASE
, uint8_t mu
#endif
);
/** @brief xran callback for time alignment, see xran_reg_physide_cb(). */
int oai_physide_dl_tti_call_back(void *param);
int oai_physide_dl_tti_call_back(void *param
#ifdef K_RELEASE
, uint8_t mu
#endif
);
#endif /* OAIORAN_H */

500
radio/fhi_72/oaioran_ru.c Normal file
View File

@@ -0,0 +1,500 @@
/*
* 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 <netinet/in.h>
#include <rte_ring.h>
#include <rte_ring_core.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "xran_fh_o_du.h"
#include "xran_fh_o_ru.h"
#include "xran_compression.h"
#include "armral_bfp_compression.h"
#include <xran_pkt.h>
#include <xran_pkt_up.h>
#include <xran_transport.h>
#if defined(__arm__) || defined(__aarch64__)
#else
// xran_cp_api.h uses SIMD, but does not include it
#include <immintrin.h>
#endif
#include "xran_cp_api.h"
#include "xran_sync_api.h"
#include "oran_isolate.h"
#include "xran_up_api.h"
#include "oran-init.h"
#include "oaioran.h"
#include <rte_ethdev.h>
#include "oran-config.h" // for g_kbar
#include "common/utils/threadPool/notified_fifo.h"
#include "circular_buffer.h"
#include "iq_worker.h"
#include "oran_debug.h"
#define RATE_LIMIT(n) if (({ static int _counter = 0; _counter++ % (n) == 0; }))
#define ETHER_TYPE_ECPRI 0xAEFE
#define MAX_NUM_ANTENNAS 4
notifiedFIFO_t ru_dl_sync_fifo;
extern volatile bool first_call_set;
static circular_buffer_t dl_iq_buffer;
typedef struct {
int frame;
int slot;
int symbol;
int num_symbols;
struct timespec ts;
} ru_dl_sync_info_t;
typedef struct {
uint16_t cb_symbol_mask;
int num_symbols[NR_NUMBER_OF_SYMBOLS_PER_SLOT];
int start_symbol[NR_NUMBER_OF_SYMBOLS_PER_SLOT];
int symbol_diff;
int numerology;
} oran_symbol_callback_args_t;
typedef struct {
int section_id;
int num_prb;
int start_prb;
int slot;
int frame;
int mu;
int filter_id;
} oran_prach_cplane_config_t;
oran_prach_cplane_config_t prach_config_per_antenna[MAX_NUM_ANTENNAS] = {0};
static uint8_t prach_seq_id[MAX_NUM_ANTENNAS] = {0};
extern int32_t xran_ethdi_mbuf_send(struct rte_mbuf *mb, uint16_t ethertype, uint16_t vf_id);
extern uint16_t xran_map_ecpriPcid_to_vf(void *p_dev_ctx, int32_t dir, int32_t cc_id, int32_t ru_port_id);
void symbol_callback(void *args, struct xran_sense_of_time *p_sense_of_time)
{
if (!first_call_set) {
return;
}
oran_symbol_callback_args_t *callback_args = args;
if ((callback_args->cb_symbol_mask & (1 << p_sense_of_time->nSymIdx)) == 0) {
return;
}
int num_symbols = callback_args->num_symbols[p_sense_of_time->nSymIdx];
int start_symbol = callback_args->start_symbol[p_sense_of_time->nSymIdx];
// Adjust timing by symbol_diff
int slot_index_increments = (p_sense_of_time->nSymIdx + callback_args->symbol_diff) / NR_NUMBER_OF_SYMBOLS_PER_SLOT;
int num_slots_per_subframe = 1 << callback_args->numerology;
int target_slot_in_frame =
p_sense_of_time->nSlotIdx + p_sense_of_time->nSubframeIdx * num_slots_per_subframe + slot_index_increments;
int frame = p_sense_of_time->nFrameIdx;
int num_slots_per_frame = 10 << callback_args->numerology;
while (target_slot_in_frame >= num_slots_per_frame) {
target_slot_in_frame -= num_slots_per_frame;
frame++;
if (frame >= 1024) {
frame = 0;
}
}
const struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
int mu = fh_cfg->mu_number[0];
AssertFatal(mu == 1, "Only numerology 1 supported for RU\n");
LOG_D(HW,
"Callback triggered at frame.slot.synbol %d.%d.%d targets %d.%d.%d, num_symbols %d, symbol_diff %d\n",
p_sense_of_time->nFrameIdx,
p_sense_of_time->nSlotIdx + p_sense_of_time->nSubframeIdx * num_slots_per_subframe,
p_sense_of_time->nSymIdx,
frame,
target_slot_in_frame,
start_symbol,
num_symbols,
callback_args->symbol_diff);
notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(ru_dl_sync_info_t), 0, NULL, NULL);
ru_dl_sync_info_t *info = NotifiedFifoData(req);
info->frame = frame;
info->slot = target_slot_in_frame;
info->symbol = start_symbol;
info->num_symbols = num_symbols;
int slot_duration_uS[] = {1000, 500, 250, 125};
uint64_t slot_in_second_offset_nS = ((uint64_t)p_sense_of_time->tti_counter * slot_duration_uS[mu]) * 1000UL;
float symbol_duration_nS = ((float)slot_duration_uS[mu] * 1000) / 14.0f;
uint64_t symbol_in_slot_offset_nS = (uint64_t)((p_sense_of_time->nSymIdx + callback_args->symbol_diff) * symbol_duration_nS);
info->ts.tv_sec = p_sense_of_time->nSecond;
info->ts.tv_nsec = slot_in_second_offset_nS + symbol_in_slot_offset_nS;
if (info->ts.tv_nsec >= 1000000000UL) {
info->ts.tv_sec += 1;
info->ts.tv_nsec -= 1000000000UL;
}
AssertFatal(info->ts.tv_nsec < 1000000000UL, "ORAN: Invalid tv_nsec %ld\n", info->ts.tv_nsec);
pushNotifiedFIFO(&ru_dl_sync_fifo, req);
}
int xran_oru_tx_read_slot(uint32_t **txdataF, int nb_tx, int *frame, int *slot, int *symbol, int *num_symbols, struct timespec *ts)
{
notifiedFIFO_elt_t *res = pullNotifiedFIFO(&ru_dl_sync_fifo);
ru_dl_sync_info_t *info = NotifiedFifoData(res);
*slot = info->slot;
*frame = info->frame;
*symbol = info->symbol;
*num_symbols = info->num_symbols;
*ts = info->ts;
delNotifiedFIFO_elt(res);
const struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
uint8_t mu = fh_cfg->mu_number[0];
int nPRBs = fh_cfg->perMu[mu].nDLRBs;
int fftsize = 1 << fh_cfg->perMu[mu].nDLFftSize;
int first_carrier_offset = fftsize - (nPRBs * NR_NB_SC_PER_RB / 2);
int num_sc_first_copy = (fftsize - first_carrier_offset);
int num_sc_second_copy = nPRBs * NR_NB_SC_PER_RB - num_sc_first_copy;
for (int aatx = 0; aatx < nb_tx; aatx++) {
uint32_t *txdata_aatx = txdataF[aatx];
for (int sym = *symbol; sym < *symbol + *num_symbols; sym++) {
uint32_t *txdata_sym = &txdata_aatx[sym * fftsize];
uint32_t *ant_data = circular_buffer_get_data(&dl_iq_buffer, aatx, *slot, sym);
memcpy(&txdata_sym[first_carrier_offset], ant_data, num_sc_first_copy * sizeof(uint32_t));
memcpy(txdata_sym, &ant_data[num_sc_first_copy], num_sc_second_copy * sizeof(uint32_t));
memset(ant_data, 0, sizeof(uint32_t) * nPRBs * NR_NB_SC_PER_RB);
if (*frame == 0 && aatx == 0) {
dump_nonzero_symbol((c16_t *)txdata_sym, fftsize, *frame, *slot, sym, "ru_read_dl_iq");
}
}
}
return 0;
}
int process_ru_uplane(struct rte_mbuf *pkt,
void *handle,
struct xran_eaxc_info *p_cid,
uint16_t port_id,
struct xran_sense_of_time *p_sense_of_time)
{
const struct xran_fh_config *fh_cfg = get_xran_fh_config(port_id);
void *iq_data_start = NULL;
uint8_t CC_ID;
uint8_t Ant_ID;
uint8_t frame_id;
uint8_t subframe_id;
uint8_t slot_id;
uint8_t symb_id;
uint8_t filter_id;
union ecpri_seq_id seq_id;
uint16_t num_prbu;
uint16_t start_prbu;
uint16_t sym_inc;
uint16_t rb;
uint16_t sect_id;
int expect_comp = fh_cfg->ru_conf.compMeth != XRAN_COMPMETHOD_NONE;
enum xran_comp_hdr_type staticComp = fh_cfg->ru_conf.xranCompHdrType;
uint8_t compMeth = XRAN_COMPMETHOD_NONE;
uint8_t iqWidth = 0;
uint8_t is_prach;
xran_extract_iq_samples(pkt,
&iq_data_start,
&CC_ID,
&Ant_ID,
&frame_id,
&subframe_id,
&slot_id,
&symb_id,
&filter_id,
&seq_id,
&num_prbu,
&start_prbu,
&sym_inc,
&rb,
&sect_id,
expect_comp,
staticComp,
&compMeth,
&iqWidth,
port_id,
&is_prach);
LOG_D(HW,
"ORAN: U-plane packet received. CC_ID %d, Ant_ID %d, frame_id %d, subframe_id %d, slot_id %d, symb_id %d, filter_id %d, "
"num_prbu %d, start_prbu %d, sym_inc %d, rb %d, sect_id %d, compMeth %d, iqWidth %d, is_prach %d\n",
CC_ID,
Ant_ID,
frame_id,
subframe_id,
slot_id,
symb_id,
filter_id,
num_prbu,
start_prbu,
sym_inc,
rb,
sect_id,
compMeth,
iqWidth,
is_prach);
AssertFatal(compMeth == XRAN_COMPMETHOD_NONE, "Compression not supported\n");
int slot_in_frame = slot_id + subframe_id * 2;
uint32_t *symbol_buffer = circular_buffer_get_data(&dl_iq_buffer, Ant_ID, slot_in_frame, symb_id);
int16_t *target = (int16_t *)(symbol_buffer + start_prbu * NR_NB_SC_PER_RB);
iq_worker_enqueue(compMeth, iqWidth, num_prbu * NR_NB_SC_PER_RB, iq_data_start, target, pkt);
return MBUF_KEEP;
}
int32_t process_ru_cplane(struct rte_mbuf *pkt, void *handle, uint16_t port_id, struct xran_sense_of_time *p_sense_of_time)
{
const struct xran_fh_config *fh_cfg = get_xran_fh_config(port_id);
struct xran_ecpri_hdr *ecpri_hdr;
struct xran_recv_packet_info xran_recv_packet_info;
int ret = xran_parse_ecpri_hdr(port_id, pkt, &ecpri_hdr, &xran_recv_packet_info);
if (ret != XRAN_STATUS_SUCCESS) {
return MBUF_FREE;
}
struct xran_cp_radioapp_common_header *apphdr = (void *)rte_pktmbuf_adj(pkt, sizeof(struct xran_ecpri_hdr));
if (apphdr == NULL) {
LOG_W(HW, "issue extracting apphdr\n");
return MBUF_FREE;
}
apphdr->field.all_bits = rte_be_to_cpu_32(apphdr->field.all_bits);
if (apphdr->field.payloadVer != XRAN_PAYLOAD_VER) {
LOG_W(HW, "Invalid payloadVer field %d\n", apphdr->field.payloadVer);
return MBUF_FREE;
}
switch (apphdr->sectionType) {
case XRAN_CP_SECTIONTYPE_3: {
struct xran_cp_radioapp_section3_header *hdr = (struct xran_cp_radioapp_section3_header *)apphdr;
if (hdr->cmnhdr.numOfSections != 1) {
LOG_W(HW, "Only support one section\n");
return MBUF_FREE;
}
hdr->timeOffset = rte_be_to_cpu_16(hdr->timeOffset);
hdr->cpLength = rte_be_to_cpu_16(hdr->cpLength);
struct xran_cp_radioapp_section3 *section = (void *)rte_pktmbuf_adj(pkt, sizeof(struct xran_cp_radioapp_section3_header));
if (section == NULL) {
LOG_W(HW, "Issue extracting section\n");
return MBUF_FREE;
}
*((uint64_t *)section) = rte_be_to_cpu_64(*((uint64_t *)section));
int mu = hdr->frameStructure.uScs;
int aarx = xran_recv_packet_info.eaxc.ruPortId - fh_cfg->perMu[mu].prach_conf.prachEaxcOffset;
oran_prach_cplane_config_t prach_config = {
.frame = hdr->cmnhdr.field.frameId,
.slot = hdr->cmnhdr.field.slotId + hdr->cmnhdr.field.subframeId + hdr->cmnhdr.field.subframeId * hdr->frameStructure.uScs,
.num_prb = section->hdr.u1.common.numPrbc,
.start_prb = section->hdr.u1.common.startPrbc,
.section_id = section->hdr.u1.common.sectionId,
.mu = mu,
.filter_id = hdr->cmnhdr.field.filterIndex
};
prach_config_per_antenna[aarx] = prach_config;
return MBUF_FREE;
}
default:
return MBUF_FREE;
}
}
static void *g_handle;
void install_symbol_callback(void *handle, int callbacks_per_slot, int mu)
{
g_handle = handle;
AssertFatal(callbacks_per_slot < NR_NUMBER_OF_SYMBOLS_PER_SLOT,
"Can do at most %d callbacks per slot",
NR_NUMBER_OF_SYMBOLS_PER_SLOT);
static bool installed = false;
AssertFatal(!installed, "Cannot install callback twice\n");
installed = true;
for (int aarx = 0; aarx < MAX_NUM_ANTENNAS; aarx++) {
prach_config_per_antenna[aarx].section_id = -1;
prach_config_per_antenna[aarx].num_prb = -1;
prach_config_per_antenna[aarx].start_prb = -1;
prach_config_per_antenna[aarx].slot = -1;
prach_config_per_antenna[aarx].frame = -1;
}
// Represents RX window end
const struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
uint32_t T2a_min = fh_cfg->perMu[mu].T2a_min_up;
int slot_duration_uS[] = {1000, 500, 250, 125};
float symbol_duration_nS = ((float)slot_duration_uS[mu] * 1000) / 14.0f;
uint32_t symbol_offset = (float)(T2a_min * 1000) / symbol_duration_nS;
AssertFatal(symbol_offset > 0, "The amount of time after RX window end for O-RU is 0. Adjust T2a_min_up %u [uS]\n", T2a_min);
LOG_I(HW, "Installing %d callbacks %d symbols before OTA\n", callbacks_per_slot, symbol_offset);
static oran_symbol_callback_args_t args = {0};
args.numerology = mu;
int symbols_per_callback = NR_NUMBER_OF_SYMBOLS_PER_SLOT / callbacks_per_slot;
int start_symbol = 0;
for (int i = 0; i < callbacks_per_slot; i++) {
int extra_symbols = 0;
if (i == callbacks_per_slot - 1) {
// Extend last callback to include leftover symbols
extra_symbols += NR_NUMBER_OF_SYMBOLS_PER_SLOT % callbacks_per_slot;
}
int num_sybmols_this_callback = symbols_per_callback + extra_symbols;
int end_symbol = start_symbol + num_sybmols_this_callback - 1;
int callback_symbol = (end_symbol - symbol_offset + NR_NUMBER_OF_SYMBOLS_PER_SLOT) % NR_NUMBER_OF_SYMBOLS_PER_SLOT;
args.cb_symbol_mask |= (1U << callback_symbol);
args.num_symbols[callback_symbol] = num_sybmols_this_callback;
args.start_symbol[callback_symbol] = start_symbol;
args.symbol_diff = symbol_offset;
start_symbol += symbols_per_callback;
}
circular_buffer_init(&dl_iq_buffer, MAX_NUM_ANTENNAS, 10 << mu, 14, 275 * 12);
iq_worker_init();
xran_hook_install(handle, process_ru_uplane, NULL, process_ru_cplane, NULL, symbol_callback, &args, mu);
}
extern void *xran_ethdi_mbuf_alloc(void);
void fill_ecpri_header(struct xran_ecpri_hdr *ecpri_header,
uint8_t ecpri_mesg_type,
size_t ecpri_payload_size,
uint8_t CC_ID,
uint8_t Ant_ID,
uint8_t seq_id,
uint8_t oxu_port_id)
{
ecpri_header->cmnhdr.data.data_num_1 = 0x0;
ecpri_header->cmnhdr.bits.ecpri_ver = XRAN_ECPRI_VER;
ecpri_header->cmnhdr.bits.ecpri_mesg_type = ecpri_mesg_type;
ecpri_header->cmnhdr.bits.ecpri_payl_size = rte_cpu_to_be_16(ecpri_payload_size);
ecpri_header->ecpri_xtc_id = xran_compose_cid(oxu_port_id, 0, 0, CC_ID, Ant_ID);
ecpri_header->ecpri_seq_id.bits.seq_id = seq_id;
ecpri_header->ecpri_seq_id.bits.e_bit = 1;
ecpri_header->ecpri_seq_id.bits.sub_seq_id = 0;
/// No byteswap for ecpri_seq_id. Possibly because of inverse definition in xran
}
void fill_radio_app_header(struct radio_app_common_hdr *radio_app_header,
int filter_id,
int direction,
int frame,
int slot,
int symbol,
int mu)
{
radio_app_header->frame_id = frame & 0xff;
radio_app_header->sf_slot_sym.slot_id = slot % (1 << mu);
radio_app_header->sf_slot_sym.subframe_id = slot / (1 << mu);
radio_app_header->sf_slot_sym.symb_id = symbol;
radio_app_header->sf_slot_sym.value = rte_cpu_to_be_16(radio_app_header->sf_slot_sym.value);
radio_app_header->data_feature.data_direction = direction;
radio_app_header->data_feature.payl_ver = 1;
radio_app_header->data_feature.filter_id = filter_id;
}
void fill_data_section_header(struct data_section_hdr *data_section_hdr, int num_prb, int start_prb, int section_id)
{
data_section_hdr->fields.all_bits = 0;
data_section_hdr->fields.num_prbu = (uint8_t)XRAN_CONVERT_NUMPRBC(num_prb);
data_section_hdr->fields.start_prbu = (start_prb & 0x03ff);
data_section_hdr->fields.sect_id = section_id;
data_section_hdr->fields.all_bits = rte_cpu_to_be_32(data_section_hdr->fields.all_bits);
}
void xran_oru_send_prach(uint32_t *prachF, int aarx, int frame, int slot, int symbol)
{
const struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
uint8_t mu = fh_cfg->mu_number[0];
AssertFatal(fh_cfg->ru_conf.compMeth_PRACH == XRAN_COMPMETHOD_NONE, "Compression not supported\n");
// TODO: With compression, have to add compression header to header_len
size_t header_length = sizeof(struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr) + sizeof(struct data_section_hdr);
// TODO: For compression, have to re-evaluate data size;
// TODO: Only support short format PRACH
const uint prach_length = 139;
size_t data_len = sizeof(int32_t) * prach_length;
oran_prach_cplane_config_t *prach_config = &prach_config_per_antenna[aarx];
if (prach_config->section_id == -1) {
RATE_LIMIT(1000)
LOG_W(HW, "PRACH was not yet configured by the O-DU\n");
return;
}
if (prach_config->frame != (frame & 0xff) || prach_config->slot != slot) {
RATE_LIMIT(1000)
LOG_W(HW,
"PRACH was not configured for frame.slot %d.%d, configuration is for frame.slot %d.%d\n",
frame,
slot,
prach_config->frame,
prach_config->slot);
return;
}
struct rte_mbuf *mbuf = xran_ethdi_mbuf_alloc();
AssertFatal(mbuf != NULL, "out of mbufs\n");
char *buf = rte_pktmbuf_append(mbuf, header_length + data_len);
AssertFatal(buf, "incorrect mbuf size\n");
struct xran_ecpri_hdr *ecpri_header = (struct xran_ecpri_hdr *)rte_pktmbuf_mtod(mbuf, char *);
uint16_t ecpri_payload_size = xran_get_ecpri_hdr_size() + sizeof(struct radio_app_common_hdr) + sizeof(struct data_section_hdr) + data_len;
fill_ecpri_header(ecpri_header, ECPRI_IQ_DATA, ecpri_payload_size, 0, aarx + fh_cfg->perMu[mu].prach_conf.prachEaxcOffset, prach_seq_id[aarx]++, 0);
struct radio_app_common_hdr *radio_app_header = (struct radio_app_common_hdr *)(ecpri_header + 1);
fill_radio_app_header(radio_app_header, prach_config->filter_id, XRAN_DIR_UL, frame, slot, symbol, mu);
struct data_section_hdr *data_section_header = (struct data_section_hdr *)(radio_app_header + 1);
fill_data_section_header(data_section_header, prach_config->num_prb, prach_config->start_prb, prach_config->section_id);
void *iq_data_start = (void *)(data_section_header + 1);
int16_t *dest = (int16_t *)iq_data_start;
uint16_t *src = (uint16_t *)prachF;
for (int i = 0; i < prach_length * 2; i++) {
dest[i] = (int16_t)htons(src[i]);
}
buf = rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ether_hdr));
AssertFatal(buf != NULL, "incorrect mbuf size\n");
int vf_id = xran_map_ecpriPcid_to_vf(g_handle, XRAN_DIR_UL, 0, aarx + fh_cfg->perMu[mu].prach_conf.prachEaxcOffset);
int ret = xran_ethdi_mbuf_send(mbuf, ETHER_TYPE_ECPRI, vf_id);
AssertFatal(ret == 1, "Error sending mbuf\n");
}
void stop_oru(void) {
iq_worker_destroy();
}

40
radio/fhi_72/oaioran_ru.h Normal file
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 __OAIORAN_RU_H__
#define __OAIORAN_RU_H__
#include <stdint.h>
#include "common/utils/threadPool/notified_fifo.h"
extern notifiedFIFO_t ru_dl_sync_fifo;
// Installs a callback that triggers callbacks_per_slot times in a slot when when all packets for
// corresponding symbols are received. e.g. if callbacks_per_slot == 2, the callback will trigger
// at reception window ends for symbols 7 and 14. This in turn unblocks xran_oru_tx_read_slot and
// can be used for timing purposes
void install_symbol_callback(void* handle, int callbacks_per_slot, int mu);
void stop_oru(void);
// Read samples DL IQ samples for frame slot symbol for all antennas
int xran_oru_tx_read_slot(uint32_t **txdataF, int nb_tx, int *frame, int *slot, int *symbol, int *num_symbols, struct timespec *ts);
void xran_oru_send_prach(uint32_t *prachF, int aarx, int frame, int slot, int symbol);
#endif

View File

@@ -20,6 +20,7 @@
*/
#include "oran-config.h"
#include "common/config/config_userapi.h"
#include "oran-params.h"
#include "common/utils/assertions.h"
#include "common_lib.h"
@@ -124,7 +125,7 @@ static void print_fh_init_io_cfg(const struct xran_io_cfg *io_cfg)
io_cfg->one_vf_cu_plane);
print_fh_eowd_cmn(io_cfg->id, &io_cfg->eowd_cmn[io_cfg->id]);
printf("eowd_port (filled within xran library)\n");
#ifdef F_RELEASE
#if defined(F_RELEASE) || defined(K_RELEASE)
printf("\
bbu_offload %d\n",
io_cfg->bbu_offload);
@@ -170,7 +171,11 @@ 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);
#ifdef K_RELEASE
print_fh_init_eaxcid_conf(&fh_init->eAxCId_conf[0]);
#elif defined(E_RELEASE) || defined(F_RELEASE)
print_fh_init_eaxcid_conf(&fh_init->eAxCId_conf);
#endif
printf("\
xran_ports %d\n\
dpdkBasebandFecMode %d\n\
@@ -184,11 +189,12 @@ void print_fh_init(const struct xran_fh_init *fh_init)
fh_init->filePrefix,
fh_init->mtu,
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);
if (fh_init->p_o_ru_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);
else if (fh_init->p_o_du_addr) 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);
printf("\
totalBfWeights %d\n",
fh_init->totalBfWeights);
#ifdef F_RELEASE
#if defined(F_RELEASE) || defined(K_RELEASE)
printf("\
mlogxranenable %d\n\
dlCpProcBurst %d\n",
@@ -200,22 +206,48 @@ void print_fh_init(const struct xran_fh_init *fh_init)
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",
"
#ifdef K_RELEASE
" prach_config:\n\
nPrachConfIdx %d\n\
nPrachSubcSpacing %d\n\
nPrachZeroCorrConf %d\n\
nPrachRestrictSet %d\n\
nPrachRootSeqIdx %d\n\
nPrachFreqStart %d\n\
nPrachFreqOffset %d\n\
nPrachFilterIdx %d\n\
startSymId %d\n\
lastSymId %d\n\
startPrbc %d\n\
numPrbc %d\n\
timeOffset %d\n\
freqOffset %d\n\
prachEaxcOffset %d\n\
nprachformat %d\n\
periodicity %d\n\
startTime %d\n\
suboffset %d\n\
numSubCarriers %d\n\
nRep %d\n",
#elif defined(E_RELEASE) || defined(F_RELEASE)
" prach_config:\n\
nPrachConfIdx %d\n\
nPrachSubcSpacing %d\n\
nPrachZeroCorrConf %d\n\
nPrachRestrictSet %d\n\
nPrachRootSeqIdx %d\n\
nPrachFreqStart %d\n\
nPrachFreqOffset %d\n\
nPrachFilterIdx %d\n\
startSymId %d\n\
lastSymId %d\n\
startPrbc %d\n\
numPrbc %d\n\
timeOffset %d\n\
freqOffset %d\n\
eAxC_offset %d\n",
#endif
prach_conf->nPrachConfIdx,
prach_conf->nPrachSubcSpacing,
prach_conf->nPrachZeroCorrConf,
@@ -230,8 +262,19 @@ static void print_prach_config(const struct xran_prach_config *prach_conf)
prach_conf->numPrbc,
prach_conf->timeOffset,
prach_conf->freqOffset,
prach_conf->eAxC_offset);
#ifdef F_RELEASE
#ifdef K_RELEASE
prach_conf->prachEaxcOffset,
prach_conf->nprachformat,
prach_conf->periodicity,
prach_conf->startTime,
prach_conf->suboffset,
prach_conf->numSubCarriers,
prach_conf->nRep
#elif defined(E_RELEASE) || defined(F_RELEASE)
prach_conf->eAxC_offset
#endif
);
#if defined(F_RELEASE) || defined(K_RELEASE)
printf("\
nPrachConfIdxLTE %d\n",
prach_conf->nPrachConfIdxLTE);
@@ -242,21 +285,34 @@ static void print_srs_config(const struct xran_srs_config *srs_conf)
{
printf("\
srs_config:\n\
symbMask %04x\n\
eAxC_offset %d\n",
symbMask %04x\n"
#ifdef K_RELEASE
" srsEaxcOffset %d\n",
#elif defined(E_RELEASE) || defined(F_RELEASE)
" eAxC_offset %d\n",
#endif
srs_conf->symbMask,
srs_conf->eAxC_offset);
#ifdef K_RELEASE
srs_conf->srsEaxcOffset
#elif defined(E_RELEASE) || defined(F_RELEASE)
srs_conf->eAxC_offset
#endif
);
}
static void print_frame_config(const struct xran_frame_config *frame_conf)
{
printf("\
frame_conf:\n\
nFrameDuplexType %s\n\
nNumerology %d\n\
nTddPeriod %d\n",
nFrameDuplexType %s\n"
#if defined(E_RELEASE) || defined(F_RELEASE)
" nNumerology %d\n"
#endif
" nTddPeriod %d\n",
frame_conf->nFrameDuplexType == XRAN_TDD ? "TDD" : "FDD",
#if defined(E_RELEASE) || defined(F_RELEASE)
frame_conf->nNumerology,
#endif
frame_conf->nTddPeriod);
for (int i = 0; i < frame_conf->nTddPeriod; ++i) {
printf(" sSlotConfig[%d]: ", i);
@@ -268,7 +324,11 @@ static void print_frame_config(const struct xran_frame_config *frame_conf)
}
}
static void print_ru_config(const struct xran_ru_config *ru_conf)
static void print_ru_config(
#ifdef K_RELEASE
uint8_t mu_number,
#endif
const struct xran_ru_config *ru_conf)
{
printf("\
ru_config:\n\
@@ -278,9 +338,13 @@ static void print_ru_config(const struct xran_ru_config *ru_conf)
iqWidth %d\n\
compMeth %d\n\
iqWidth_PRACH %d\n\
compMeth_PRACH %d\n\
fftSize %d\n\
byteOrder %s\n\
compMeth_PRACH %d\n"
#ifdef K_RELEASE
" fftSize[mu_number] %d\n"
#elif defined(E_RELEASE) || defined(F_RELEASE)
" fftSize %d\n"
#endif
" byteOrder %s\n\
iqOrder %s\n\
xran_max_frame %d\n",
ru_conf->xranTech == XRAN_RAN_5GNR ? "NR" : "LTE",
@@ -290,27 +354,106 @@ static void print_ru_config(const struct xran_ru_config *ru_conf)
ru_conf->compMeth,
ru_conf->iqWidth_PRACH,
ru_conf->compMeth_PRACH,
#ifdef K_RELEASE
ru_conf->fftSize[mu_number],
#elif defined(E_RELEASE) || defined(F_RELEASE)
ru_conf->fftSize,
#endif
ru_conf->byteOrder == XRAN_NE_BE_BYTE_ORDER ? "network/BE" : "CPU/LE",
ru_conf->iqOrder == XRAN_I_Q_ORDER ? "I_Q" : "Q_I",
ru_conf->xran_max_frame);
}
#ifdef K_RELEASE
void print_fh_per_mu_cfg(const struct xran_fh_per_mu_cfg *perMu)
{
printf("\
perMu:\n\
nDLBandwidth %d\n\
nULBandwidth %d\n",
perMu->nDLBandwidth,
perMu->nULBandwidth);
print_prach_config(&perMu->prach_conf);
printf("\
freqOffset %d\n\
nDLFftSize %d\n\
nULFftSize %d\n\
eaxcOffset %d\n\
nDLRBs %d\n\
nULRBs %d\n\
Tadv_cp_dl %d\n\
T2a_min_cp_dl %d\n\
T2a_max_cp_dl %d\n\
T2a_min_cp_ul %d\n\
T2a_max_cp_ul %d\n\
T2a_min_up %d\n\
T2a_max_up %d\n\
Ta3_min %d\n\
Ta3_max %d\n\
T1a_min_cp_dl %d\n\
T1a_max_cp_dl %d\n\
T1a_min_cp_ul %d\n\
T1a_max_cp_ul %d\n\
T1a_min_up %d\n\
T1a_max_up %d\n\
Ta4_min %d\n\
Ta4_max %d\n\
prachEnable %d\n\
prachConfigIndex %d\n\
prachConfigIndexLTE %d\n\
nbIotUlScs %d\n\
adv_tx_time %d\n",
perMu->freqOffset,
perMu->nDLFftSize,
perMu->nULFftSize,
perMu->eaxcOffset,
perMu->nDLRBs,
perMu->nULRBs,
perMu->Tadv_cp_dl,
perMu->T2a_min_cp_dl,
perMu->T2a_max_cp_dl,
perMu->T2a_min_cp_ul,
perMu->T2a_max_cp_ul,
perMu->T2a_min_up,
perMu->T2a_max_up,
perMu->Ta3_min,
perMu->Ta3_max,
perMu->T1a_min_cp_dl,
perMu->T1a_max_cp_dl,
perMu->T1a_min_cp_ul,
perMu->T1a_max_cp_ul,
perMu->T1a_min_up,
perMu->T1a_max_up,
perMu->Ta4_min,
perMu->Ta4_max,
perMu->prachEnable,
perMu->prachConfigIndex,
perMu->prachConfigIndexLTE,
perMu->nbIotUlScs,
perMu->adv_tx_time);
}
#endif
void print_fh_config(const struct xran_fh_config *fh_config)
{
printf("xran_fh_config:\n");
printf("\
dpdk_port %d\n\
sector_id %d\n\
nCC %d\n\
neAxc %d\n\
neAxcUl %d\n\
nAntElmTRx %d\n\
nDLFftSize %d\n\
nAntElmTRx %d\n"
#if defined(E_RELEASE) || defined(F_RELEASE)
" nDLFftSize %d\n\
nULFftSize %d\n\
nDLRBs %d\n\
nULRBs %d\n\
nDLAbsFrePointA %d\n\
nULRBs %d\n"
#endif
" nDLAbsFrePointA %d\n\
nULAbsFrePointA %d\n\
nDLCenterFreqARFCN %d\n\
nULCenterFreqARFCN %d\n\
@@ -322,17 +465,23 @@ void print_fh_config(const struct xran_fh_config *fh_config)
fh_config->neAxc,
fh_config->neAxcUl,
fh_config->nAntElmTRx,
#if defined(E_RELEASE) || defined(F_RELEASE)
fh_config->nDLFftSize,
fh_config->nULFftSize,
fh_config->nDLRBs,
fh_config->nULRBs,
#endif
fh_config->nDLAbsFrePointA,
fh_config->nULAbsFrePointA,
fh_config->nDLCenterFreqARFCN,
fh_config->nULCenterFreqARFCN,
fh_config->ttiCb,
fh_config->ttiCbParam);
#ifdef K_RELEASE
uint8_t mu_number = fh_config->mu_number[0];
print_fh_per_mu_cfg(&fh_config->perMu[mu_number]);
#endif
#if defined(E_RELEASE) || defined(F_RELEASE)
printf("\
Tadv_cp_dl %d\n\
T2a_min_cp_dl %d\n\
@@ -368,34 +517,34 @@ void print_fh_config(const struct xran_fh_config *fh_config)
fh_config->T1a_max_up,
fh_config->Ta4_min,
fh_config->Ta4_max);
#endif
printf("\
enableCP %d\n\
prachEnable %d\n\
srsEnable %d\n\
enableCP %d\n"
#if defined(E_RELEASE) || defined(F_RELEASE)
" prachEnable %d\n"
#endif
" srsEnable %d\n\
puschMaskEnable %d\n\
puschMaskSlot %d\n\
cp_vlan_tag %d\n\
up_vlan_tag %d\n\
debugStop %d\n\
debugStopCount %d\n\
DynamicSectionEna %d\n\
GPS_Alpha %d\n\
GPS_Beta %d\n",
fh_config->enableCP,
#if defined(E_RELEASE) || defined(F_RELEASE)
fh_config->prachEnable,
#endif
fh_config->srsEnable,
fh_config->puschMaskEnable,
fh_config->puschMaskSlot,
fh_config->cp_vlan_tag,
fh_config->up_vlan_tag,
fh_config->debugStop,
fh_config->debugStopCount,
fh_config->DynamicSectionEna,
fh_config->GPS_Alpha,
fh_config->GPS_Beta);
#ifdef F_RELEASE
#if defined(F_RELEASE) || defined(K_RELEASE)
printf("\
srsEnableCp %d\n\
SrsDelaySym %d\n",
@@ -403,10 +552,16 @@ void print_fh_config(const struct xran_fh_config *fh_config)
fh_config->SrsDelaySym);
#endif
#if defined(E_RELEASE) || defined(F_RELEASE)
print_prach_config(&fh_config->prach_conf);
#endif
print_srs_config(&fh_config->srs_conf);
print_frame_config(&fh_config->frame_conf);
print_ru_config(&fh_config->ru_conf);
print_ru_config(
#ifdef K_RELEASE
mu_number,
#endif
&fh_config->ru_conf);
printf("\
bbdev_enc %p\n\
@@ -428,7 +583,7 @@ void print_fh_config(const struct xran_fh_config *fh_config)
fh_config->max_sections_per_slot,
fh_config->max_sections_per_symbol);
#ifdef F_RELEASE
#if defined(F_RELEASE) || defined(K_RELEASE)
printf("\
RunSlotPrbMapBySymbolEnable %d\n\
dssEnable %d\n\
@@ -438,6 +593,16 @@ void print_fh_config(const struct xran_fh_config *fh_config)
fh_config->dssEnable,
fh_config->dssPeriod);
#endif
#ifdef K_RELEASE
printf("\
numMUs %d\n\
mu_number[0] %d\n\
nNumerology[0] %d\n",
fh_config->numMUs,
fh_config->mu_number[0],
fh_config->nNumerology[0]);
#endif
}
static const paramdef_t *gpd(const paramdef_t *pd, int num, const char *name)
@@ -466,14 +631,14 @@ char bbdev_dev[32] = "";
char bbdev_vfio_vf_token[64] = "";
#endif
static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, int nump, const int num_rus)
static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, int nump, const int num_peer, const int is_du)
{
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 -> xran as O-DU; 1 -> xran as O-RU
io_cfg->id = 1 - is_du; // 0 -> xran as O-DU; 1 -> xran as O-RU
io_cfg->num_vfs = num_dev; // number of VFs for C-plane and U-plane (should be even); max = XRAN_VF_MAX
io_cfg->num_rxq = 1; // number of RX queues per VF
for (int i = 0; i < num_dev; ++i) {
@@ -535,7 +700,11 @@ static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, in
io_cfg->io_sleep = 0; // enable sleep on PMD cores; 0 -> no sleep
io_cfg->nEthLinePerPort = *gpd(fhip, nump, ORAN_CONFIG_NETHPERPORT)->uptr; // 1, 2, 3 total number of links per O-RU (Fronthaul Ethernet link)
io_cfg->nEthLineSpeed = *gpd(fhip, nump, ORAN_CONFIG_NETHSPEED)->uptr; // 10G,25G,40G,100G speed of Physical connection on O-RU
io_cfg->one_vf_cu_plane = (io_cfg->num_vfs == num_rus); // C-plane and U-plane use one VF
#ifdef K_RELEASE
io_cfg->num_mbuf_alloc = NUM_MBUFS; // number of mbuf allocated by DPDK (optimal is n = (2^q - 1))
io_cfg->num_mbuf_vf_alloc = NUM_MBUFS_VF; // number of mbuf allocated by DPDK (optimal is n = (2^q - 1))
#endif
io_cfg->one_vf_cu_plane = (io_cfg->num_vfs == num_peer); // C-plane and U-plane use one VF
/* eCPRI One-Way Delay Measurements common settings for O-DU and O-RU;
use owdm to calculate T12 and T34 -> CUS specification, section 2.3.3.3;
@@ -546,7 +715,7 @@ static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, in
/* if RU does support, io_cfg->eowd_cmn[0] should only be filled as id = O_DU; io_cfg->eowd_cmn[1] only used if id = O_RU */
const uint16_t owdm_enable = *gpd(fhip, nump, ORAN_CONFIG_ECPRI_OWDM)->uptr;
if (owdm_enable) {
io_cfg->eowd_cmn[0].initiator_en = 1; // 1 -> initiator (always O-DU), 0 -> recipient (always O-RU)
io_cfg->eowd_cmn[0].initiator_en = is_du ? 1 : 0; // 1 -> initiator (always O-DU), 0 -> recipient (always O-RU)
io_cfg->eowd_cmn[0].numberOfSamples = 8; // total number of samples to be collected and averaged per port
io_cfg->eowd_cmn[0].filterType = 0; // 0 -> simple average based on number of measurements; not used in xran in both E and F releases
io_cfg->eowd_cmn[0].responseTo = 10000000; // response timeout in [ns]
@@ -560,7 +729,7 @@ static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, in
/* eCPRI OWDM per port variables for O-DU; this parameter is filled within xran library */
// eowd_port[0][XRAN_VF_MAX]
#ifdef F_RELEASE
#if defined(F_RELEASE) || defined(K_RELEASE)
io_cfg->bbu_offload = 0; // enable packet handling on BBU cores
#endif
@@ -599,7 +768,7 @@ static bool set_fh_eaxcid_conf_mplane(struct xran_eaxcid_config *eaxcid_conf, en
return true;
}
#else
static bool set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran_category cat)
static bool __attribute__((unused)) set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran_category cat)
{
/* CUS specification, section 3.1.3.1.6
DU_port_ID - used to differentiate processing units at O-DU (e.g., different baseband cards).
@@ -684,13 +853,27 @@ static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xra
const int nfh = sizeofArray(FHconfigs);
config_getlist(config_get_if(), &FH_ConfigList, FHconfigs, nfh, aprefix);
int num_peer = FH_ConfigList.numelt; // based on the number of fh_config sections -> number of RUs
int is_du=0;
int num_ru_addr = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->numelt;
int num_du_addr = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->numelt;
if (num_ru_addr > 0 && num_du_addr == 0) is_du = 1;
else if (num_du_addr > 0 && num_ru_addr == 0) is_du = 0;
else AssertFatal(1==0,"Illegal node configuration, num_du_addr %d, num_ru_addr %d\n",num_du_addr,num_ru_addr);
fh_init->xran_ports = num_peer;
#ifdef OAI_MPLANE
ru_session_list_t *ru_session_list = (ru_session_list_t *)mplane_api;
int num_rus = ru_session_list->num_rus;
fh_init->xran_ports = num_rus; // since we use xran as O-DU, xran_ports is set to the number of RUs
if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_rus))
return false;
#ifdef K_RELEASE
if (!set_fh_eaxcid_conf_mplane(&fh_init->eAxCId_conf[0], xran_cat, ru_session_list))
#elif defined(E_RELEASE) || defined(F_RELEASE)
if (!set_fh_eaxcid_conf_mplane(&fh_init->eAxCId_conf, xran_cat, ru_session_list))
#endif
return false;
/* maximum transmission unit (MTU) is the size of the largest protocol data unit (PDU) that can be
communicated in a single xRAN network layer transaction. Supported 1500 bytes and 9600 bytes (Jumbo Frame);
@@ -710,26 +893,50 @@ static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xra
}
}
#else
int num_rus = FH_ConfigList.numelt; // based on the number of fh_config sections -> number of RUs
fh_init->xran_ports = num_rus; // since we use xran as O-DU, xran_ports is set to the number of RUs
if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_rus))
if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_peer, is_du))
return false;
#ifdef K_RELEASE
if (!set_fh_eaxcid_conf(&fh_init->eAxCId_conf[0], xran_cat))
return false;
#elif defined(E_RELEASE) || defined(F_RELEASE)
if (!set_fh_eaxcid_conf(&fh_init->eAxCId_conf, xran_cat))
return false;
#endif
/* maximum transmission unit (MTU) is the size of the largest protocol data unit (PDU) that can be
communicated in a single xRAN network layer transaction. Supported 1500 bytes and 9600 bytes (Jumbo Frame);
xran only checks if (MTU <= 1500), therefore setting any value > 1500, xran assumes 9600 value is used */
fh_init->mtu = *gpd(fhip, nump, ORAN_CONFIG_MTU)->uptr;
int num_ru_addr = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->numelt;
fh_init->p_o_ru_addr = calloc(num_ru_addr, sizeof(struct rte_ether_addr));
AssertFatal(fh_init->p_o_ru_addr != NULL, "out of memory\n");
char **ru_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->strlistptr;
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->p_o_du_addr = NULL; // DPDK retreives DU MAC address within the xran library with rte_eth_macaddr_get() function
char **ru_addrs,**du_addrs;
if (is_du > 0) {
fh_init->p_o_ru_addr = calloc(num_ru_addr, sizeof(struct rte_ether_addr));
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->p_o_du_addr = NULL;
}
else {
fh_init->p_o_du_addr = calloc(num_du_addr, sizeof(struct rte_ether_addr));
du_addrs = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->strlistptr;
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 = NULL;
}
#endif
@@ -738,10 +945,9 @@ static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xra
/* used to specify a unique prefix for shared memory, and files created by multiple DPDK processes;
it is necessary */
fh_init->filePrefix = strdup(*gpd(fhip, nump, ORAN_CONFIG_FILE_PREFIX)->strptr);
fh_init->p_o_du_addr = NULL; // DPDK retreives DU MAC address within the xran library with rte_eth_macaddr_get() function
fh_init->totalBfWeights = 0; // only used if id = O_RU (for emulation); C-plane extension types; section 5.4.6 of CUS spec
#ifdef F_RELEASE
#if defined(F_RELEASE) || defined(K_RELEASE)
fh_init->mlogxranenable = 0; // enable mlog; 0 -> disabled
fh_init->dlCpProcBurst = 0; /* 1 -> DL CP processing will be done on single symbol,
0 -> DL CP processing will be spread across all allowed symbols and multiple cores to reduce burstiness */
@@ -774,7 +980,7 @@ static bool set_fh_prach_config(void *mplane_api,
prach_config->nPrachRootSeqIdx = 0; // PRACH Root Sequence Index; should be saved from config file; 1 = 839, 2 = 139; not used in xran
prach_config->nPrachFreqStart = s7cfg->prach_freq_start; // PRACH frequency start (MSG1)
prach_config->nPrachFreqOffset = (s7cfg->prach_freq_start * 12 - oai0->num_rb_dl * 6) * 2; // PRACH frequency offset
prach_config->nPrachFilterIdx = 0; /* PRACH filter index; not used in xran;
prach_config->nPrachFilterIdx = XRAN_FILTERINDEX_PRACH_ABC; /* PRACH filter index; not used in xran;
in E release hardcoded to XRAN_FILTERINDEX_PRACH_ABC (preamble format A1~3, B1~4, C0, C2)
in F release properly calculated */
@@ -785,7 +991,7 @@ static bool set_fh_prach_config(void *mplane_api,
prach_config->numPrbc = 0;
prach_config->timeOffset = 0;
prach_config->freqOffset = 0;
#ifdef F_RELEASE
#if defined(F_RELEASE) || defined(K_RELEASE)
prach_config->nPrachConfIdxLTE = 0; // used only if DSS enabled and technology is XRAN_RAN_LTE
#endif
@@ -796,10 +1002,18 @@ static bool set_fh_prach_config(void *mplane_api,
Please note that this approach only applies to the RUs that support this functionality, e.g. LITEON RU. */
#ifdef OAI_MPLANE
xran_mplane_t *xran_mplane = (xran_mplane_t *)mplane_api;
#ifdef K_RELEASE
prach_config->prachEaxcOffset = xran_mplane->prach_offset;
#elif defined(E_RELEASE) || defined(F_RELEASE)
prach_config->eAxC_offset = xran_mplane->prach_offset;
#endif
#else
uint8_t offset = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_EAXC_OFFSET)->u8ptr;
#ifdef K_RELEASE
prach_config->prachEaxcOffset = (offset != 0) ? offset : max_num_ant;
#elif defined(E_RELEASE) || defined(F_RELEASE)
prach_config->eAxC_offset = (offset != 0) ? offset : max_num_ant;
#endif
#endif
g_kbar = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_KBAR)->uptr;
@@ -811,8 +1025,10 @@ static bool set_fh_frame_config(const openair0_config_t *oai0, struct xran_frame
{
const split7_config_t *s7cfg = &oai0->split7;
frame_config->nFrameDuplexType = oai0->duplex_mode == duplex_mode_TDD ? XRAN_TDD : XRAN_FDD; // Frame Duplex type: 0 -> FDD, 1 -> TDD
#if defined(E_RELEASE) || defined(F_RELEASE)
frame_config->nNumerology = oai0->nr_scs_for_raster; /* 0 -> 15kHz, 1 -> 30kHz, 2 -> 60kHz
3 -> 120kHz, 4 -> 240kHz */
#endif
if (frame_config->nFrameDuplexType == XRAN_FDD)
return true;
@@ -829,7 +1045,11 @@ static bool set_fh_frame_config(const openair0_config_t *oai0, struct xran_frame
return true;
}
static bool set_fh_ru_config(void *mplane_api, const paramdef_t *rup, uint16_t fftSize, int nru, enum xran_category xran_cat, struct xran_ru_config *ru_config)
static bool set_fh_ru_config(void *mplane_api, const paramdef_t *rup, uint16_t fftSize, int nru, enum xran_category xran_cat
#ifdef K_RELEASE
, uint8_t mu_number
#endif
, struct xran_ru_config *ru_config)
{
ru_config->xranTech = XRAN_RAN_5GNR; // 5GNR or LTE
ru_config->xranCat = xran_cat; // mode: Catergory A or Category B
@@ -848,7 +1068,11 @@ static bool set_fh_ru_config(void *mplane_api, const paramdef_t *rup, uint16_t f
ru_config->compMeth_PRACH = ru_config->iqWidth_PRACH < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE; // compression method for PRACH
AssertFatal(fftSize > 0, "FFT size cannot be 0\n");
#ifdef K_RELEASE
ru_config->fftSize[mu_number] = fftSize; // FFT Size
#elif defined(E_RELEASE) || defined(F_RELEASE)
ru_config->fftSize = fftSize; // FFT Size
#endif
ru_config->byteOrder = XRAN_NE_BE_BYTE_ORDER; // order of bytes in int16_t in buffer; big or little endian
ru_config->iqOrder = XRAN_I_Q_ORDER; // order of IQs in the buffer
ru_config->xran_max_frame = 0; // max frame number supported; if not specified, default of 1023 is used
@@ -871,7 +1095,104 @@ static bool set_maxmin_pd(const paramdef_t *pd, int num, const char *name, uint1
return true;
}
static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_category xran_cat, const openair0_config_t *oai0, struct xran_fh_config *fh_config)
#ifdef K_RELEASE
static bool set_fh_per_mu_cfg(void *mplane_api,
int ru_idx,
int num_rus,
const openair0_config_t *oai0,
struct xran_fh_per_mu_cfg *perMu,
bool is_du)
{
char aprefix[MAX_OPTNAME_SIZE] = {0};
paramdef_t FHconfigs[] = ORAN_FH_DESC;
paramlist_def_t FH_ConfigList = {CONFIG_STRING_ORAN_FH};
sprintf(aprefix, "%s", CONFIG_STRING_ORAN);
const int nfh = sizeofArray(FHconfigs);
config_getlist(config_get_if(), &FH_ConfigList, FHconfigs, nfh, aprefix);
if (FH_ConfigList.numelt == 0) {
printf("No configuration section \"%s\" found inside \"%s\": cannot initialize fhi_lib!\n", CONFIG_STRING_ORAN_FH, aprefix);
return false;
}
paramdef_t *fhp = FH_ConfigList.paramarray[ru_idx];
paramdef_t prachp[] = ORAN_PRACH_DESC;
int nprach = sizeofArray(prachp);
sprintf(aprefix, "%s.%s.[%d].%s", CONFIG_STRING_ORAN, CONFIG_STRING_ORAN_FH, ru_idx, CONFIG_STRING_ORAN_PRACH);
int ret = config_get(config_get_if(), prachp, nprach, aprefix);
if (ret < 0) {
printf("No configuration section \"%s\": cannot initialize fhi_lib!\n", aprefix);
return false;
}
perMu->nDLBandwidth = 0; // Carrier bandwidth for in MHz. Value: 5->400. Not used in K release
perMu->nULBandwidth = 0; // Carrier bandwidth for in MHz. Value: 5->400. Not used in K release
if (!set_fh_prach_config(mplane_api, oai0, RTE_MAX(oai0->tx_num_channels / num_rus, oai0->rx_num_channels / num_rus), prachp, nprach, &perMu->prach_conf))
return false;
perMu->freqOffset = 0;
perMu->nDLFftSize = 0; // DL FFT size
perMu->nULFftSize = 0; // UL FFT size
perMu->eaxcOffset = 0; // Starting value of Eaxc for PDSCH, PUSCH packets (Absolute value) of this numerology. Should be unique across all numerologies for the RU
perMu->nDLRBs = oai0->num_rb_dl; // DL PRB
perMu->nULRBs = oai0->num_rb_dl; // UL PRB
perMu->nDLFftSize = oai0->split7.fftSize; // DL FFT size; not used in xran
perMu->nULFftSize = oai0->split7.fftSize; // UL FFT size; not used in xran
/* DU delay profile */
if (is_du) {
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_CP_DL, &perMu->T1a_min_cp_dl, &perMu->T1a_max_cp_dl)) // E - min not used in xran, max yes; F - both min and max are used in xran
return false;
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_CP_UL, &perMu->T1a_min_cp_ul, &perMu->T1a_max_cp_ul)) // both E and F - min not used in xran, max yes
return false;
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_UP, &perMu->T1a_min_up, &perMu->T1a_max_up)) // both E and F - min not used in xran, max yes
return false;
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_TA4, &perMu->Ta4_min, &perMu->Ta4_max)) // both E and F - min not used in xran, max yes
return false;
} else {
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_TA3, &perMu->Ta3_min, &perMu->Ta3_max))
return false;
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T2A, &perMu->T2a_min_up, &perMu->T2a_max_up))
return false;
}
perMu->prachEnable = 1; // enable PRACH
const split7_config_t *s7cfg = &oai0->split7;
perMu->prachConfigIndex = s7cfg->prach_index; // TS36.211 - Table 5.7.1-2 : PRACH Configuration Index
perMu->prachConfigIndexLTE = 0; // PRACH Configuration Index for LTE in dss case
perMu->nbIotUlScs = XRAN_NBIOT_UL_SCS_15; /* Applicable only for NB-IOT (mu=4). NBIOT supports asymmetric SCS usage in
downlink and uplink directions. xran library will use this parameter to derive
slot-duration for UL NB-IOT:
XRAN_NBIOT_UL_SCS_15: slot-duration=1ms
XRAN_NBIOT_UL_SCS_3_75: slot-duration=2ms */
perMu->adv_tx_time = 0; // Time by which the packet should be transmitted in advance (microseconds)
return true;
}
xran_active_numerologies_per_tti activeMUs;
static bool set_activeMUs(xran_active_numerologies_per_tti *p_activeMUs, uint8_t mu)
{
for (int i = 0; i < XRAN_N_FE_BUF_LEN; i++) {
for (int j = 0; j < XRAN_MAX_NUM_MU; j++) {
p_activeMUs->numerology[i][j] = false;
}
p_activeMUs->numerology[i][mu] = true;
}
return true;
}
#endif
static bool set_fh_config(void *mplane_api,
int ru_idx,
int num_rus,
enum xran_category xran_cat,
const openair0_config_t *oai0,
struct xran_fh_config *fh_config,
bool is_du)
{
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);
@@ -884,9 +1205,10 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c
for (int i = 1; i < oai0->rx_num_channels; ++i)
DevAssert(oai0->rx_freq[0] == oai0->rx_freq[i]);
DevAssert(oai0->nr_band > 0);
char aprefix[MAX_OPTNAME_SIZE] = {0};
#if defined(E_RELEASE) || defined(F_RELEASE)
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);
@@ -895,6 +1217,7 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c
return false;
}
paramdef_t *fhp = FH_ConfigList.paramarray[ru_idx];
#endif
paramdef_t rup[] = ORAN_RU_DESC;
int nru = sizeofArray(rup);
@@ -904,6 +1227,7 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c
printf("No configuration section \"%s\": cannot initialize fhi_lib!\n", aprefix);
return false;
}
#if defined(E_RELEASE) || defined(F_RELEASE)
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);
@@ -912,6 +1236,7 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c
printf("No configuration section \"%s\": cannot initialize fhi_lib!\n", aprefix);
return false;
}
#endif
memset(fh_config, 0, sizeof(*fh_config));
@@ -919,12 +1244,18 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c
fh_config->sector_id = 0; // Band sector ID for FH; not used in xran
fh_config->nCC = 1; // number of Component carriers supported on FH; M-plane info
fh_config->neAxc = RTE_MAX(oai0->tx_num_channels / num_rus, oai0->rx_num_channels / num_rus); // number of eAxc supported on one CC = max(PDSCH, PUSCH)
#ifdef K_RELEASE
fh_config->neAxcUl = oai0->rx_num_channels / num_rus; // number of eAxc supported on one CC for UL direction = PUSCH
#elif defined(E_RELEASE) || defined(F_RELEASE)
fh_config->neAxcUl = 0; // number of eAxc supported on one CC for UL direction = PUSCH; used only if XRAN_CATEGORY_B
#endif
fh_config->nAntElmTRx = 0; // number of antenna elements for TX and RX = SRS; used only if XRAN_CATEGORY_B
#if defined(E_RELEASE) || defined(F_RELEASE)
fh_config->nDLFftSize = oai0->split7.fftSize; // DL FFT size; not used in xran
fh_config->nULFftSize = oai0->split7.fftSize; // UL FFT size; not used in xran
fh_config->nDLRBs = oai0->num_rb_dl; // DL PRB; used in oaioran.c/oran-init.c; not used in xran, neither in E nor in F release
fh_config->nULRBs = oai0->num_rb_dl; // UL PRB; used in oaioran.c/oran-init.c; in xran E release not used so the patch fixes it, but in xran F release this value is properly used
#endif
fh_config->nDLAbsFrePointA = 0; // Abs Freq Point A of the Carrier Center Frequency for in KHz Value; not used in xran
fh_config->nULAbsFrePointA = 0; // Abs Freq Point A of the Carrier Center Frequency for in KHz Value; not used in xran
fh_config->nDLCenterFreqARFCN = 0; // center frequency for DL in NR-ARFCN; not used in xran
@@ -932,6 +1263,13 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c
fh_config->ttiCb = NULL; // check tti_to_phy_cb(), tx_cp_dl_cb() and tx_cp_ul_cb => first_call
fh_config->ttiCbParam = NULL; // check tti_to_phy_cb(), tx_cp_dl_cb() and tx_cp_ul_cb => first_call
#ifdef K_RELEASE
uint8_t mu_number = oai0->nr_scs_for_raster;
if(!set_fh_per_mu_cfg(mplane_api, ru_idx, num_rus, oai0, &fh_config->perMu[mu_number], is_du))
return false;
#endif
#if defined(E_RELEASE) || defined(F_RELEASE)
/* DU delay profile */
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_CP_DL, &fh_config->T1a_min_cp_dl, &fh_config->T1a_max_cp_dl)) // E - min not used in xran, max yes; F - both min and max are used in xran
return false;
@@ -941,32 +1279,49 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c
return false;
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_TA4, &fh_config->Ta4_min, &fh_config->Ta4_max)) // both E and F - min not used in xran, max yes
return false;
#endif
fh_config->enableCP = 1; // enable C-plane
#if defined(E_RELEASE) || defined(F_RELEASE)
fh_config->prachEnable = 1; // enable PRACH
#endif
fh_config->srsEnable = 0; // enable SRS; used only if XRAN_CATEGORY_B
#ifdef F_RELEASE
#if defined(F_RELEASE) || defined(K_RELEASE)
fh_config->srsEnableCp = 0; // enable SRS CP; used only if XRAN_CATEGORY_B
fh_config->SrsDelaySym = 0; // number of SRS delay symbols; used only if XRAN_CATEGORY_B
#endif
fh_config->puschMaskEnable = 0; // enable PUSCH mask; only used if id = O_RU
fh_config->puschMaskSlot = 0; // specific which slot PUSCH channel masked; only used if id = O_RU
#ifdef K_RELEASE
fh_config->csirsEnable = 0; // enable CSI-RS (Cat B specific)
#elif defined(E_RELEASE) || defined(F_RELEASE)
fh_config->cp_vlan_tag = 0; // C-plane VLAN tag; not used in xran; needed for M-plane
fh_config->up_vlan_tag = 0; // U-plane VLAN tag; not used in xran; needed for M-plane
#endif
fh_config->debugStop = 0; // enable auto stop; only used if id = O_RU
fh_config->debugStopCount = 0; // enable auto stop after number of Tx packets; not used in xran
fh_config->DynamicSectionEna = 0; // enable dynamic C-Plane section allocation
fh_config->GPS_Alpha = 0; // refers to alpha as defined in section 9.7.2 of ORAN spec. this value should be alpha*(1/1.2288ns), range 0 - 1e7 (ns); offset_nsec = (pConf->GPS_Beta - offset_sec * 100) * 1e7 + pConf->GPS_Alpha
fh_config->GPS_Beta = 0; // beta value as defined in section 9.7.2 of ORAN spec. range -32767 ~ +32767; offset_sec = pConf->GPS_Beta / 100
#ifdef K_RELEASE
fh_config->numMUs = 1;
fh_config->mu_number[0] = mu_number; /* 0 -> 15kHz, 1 -> 30kHz, 2 -> 60kHz, 3 -> 120kHz, 4 -> 240kHz */
fh_config->nNumerology[0] = mu_number; /* 0 -> 15kHz, 1 -> 30kHz, 2 -> 60kHz, 3 -> 120kHz, 4 -> 240kHz */
#elif defined(E_RELEASE) || defined(F_RELEASE)
if (!set_fh_prach_config(mplane_api, oai0, fh_config->neAxc, prachp, nprach, &fh_config->prach_conf))
return false;
#endif
/* SRS only used if XRAN_CATEGORY_B
Note: srs_config->eAxC_offset >= prach_config->eAxC_offset + PRACH */
// fh_config->srs_conf = {0};
if (!set_fh_frame_config(oai0, &fh_config->frame_conf))
return false;
if (!set_fh_ru_config(mplane_api, rup, oai0->split7.prach_fftSize, nru, xran_cat, &fh_config->ru_conf))
if (!set_fh_ru_config(mplane_api, rup, oai0->split7.prach_fftSize, nru, xran_cat
#ifdef K_RELEASE
, mu_number
#endif
, &fh_config->ru_conf))
return false;
fh_config->bbdev_enc = NULL; // call back to poll BBDev encoder
@@ -990,13 +1345,18 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c
fh_config->max_sections_per_slot = 0; // not used in xran
fh_config->max_sections_per_symbol = 0; // not used in xran
#ifdef F_RELEASE
#if defined(F_RELEASE) || defined(K_RELEASE)
fh_config->RunSlotPrbMapBySymbolEnable = 0; // enable PRB mapping by symbol with multisection
fh_config->dssEnable = 0; // enable DSS (extension-9)
fh_config->dssPeriod = 0; // DSS pattern period for LTE/NR
// fh_config->technology[XRAN_MAX_DSS_PERIODICITY] // technology array represents slot is LTE(0)/NR(1); used only if DSS enabled
#endif
#ifdef K_RELEASE
if (!set_activeMUs(&activeMUs, mu_number))
return false;
fh_config->activeMUs = &activeMUs;
#endif
return true;
}
@@ -1017,14 +1377,15 @@ bool get_xran_config(void *mplane_api, const struct openair0_config *openair0_cf
ru_session_list_t *ru_session_list = (ru_session_list_t *)mplane_api;
for (int32_t o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) {
xran_mplane_t *xran_mplane = &ru_session_list->ru_session[o_xu_id].xran_mplane;
if (!set_fh_config(xran_mplane, o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id])) {
if (!set_fh_config(xran_mplane, o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id], true)) {
MP_LOG_I("could not read FHI 7.2/RU-specific config\n");
return false;
}
}
#else
bool is_du = fh_init->io_cfg.id == 0;
for (int32_t o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) {
if (!set_fh_config(NULL, o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id])) {
if (!set_fh_config(NULL, o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id], is_du)) {
printf("could not read FHI 7.2/RU-specific config\n");
return false;
}

View File

@@ -19,6 +19,9 @@
* contact@openairinterface.org
*/
#define _GNU_SOURCE
#include <sched.h>
#include "oaioran_ru.h"
#include "xran_fh_o_du.h"
#include "xran_pkt.h"
#include "xran_pkt_up.h"
@@ -98,13 +101,46 @@ static struct xran_prb_map get_xran_prb_map(const struct xran_fh_config *f, cons
e->nStartSymb = start_sym;
e->numSymb = num_sym;
e->nRBStart = 0;
#ifdef K_RELEASE
uint8_t mu_number = f->mu_number[0];
e->nRBSize = (dir == XRAN_DIR_DL) ? f->perMu[mu_number].nDLRBs : f->perMu[mu_number].nULRBs;
#elif defined(E_RELEASE) || defined(F_RELEASE)
e->nRBSize = (dir == XRAN_DIR_DL) ? f->nDLRBs : f->nULRBs;
#endif
e->nBeamIndex = 0;
e->compMethod = f->ru_conf.compMeth;
e->iqWidth = f->ru_conf.iqWidth;
#ifdef K_RELEASE
memset(&prbmap.sFrontHaulRxPacketCtrl, 0, XRAN_NUM_OF_SYMBOL_PER_SLOT * sizeof(struct xran_rx_packet_ctl));
#endif
return prbmap;
}
#ifdef K_RELEASE
static struct xran_prb_map get_xran_prb_map_prach(const struct xran_fh_config *f)
{
struct xran_prb_map prbmap = {
.dir = XRAN_DIR_UL,
.xran_port = 0,
.band_id = 0,
.cc_id = 0,
.ru_port_id = 0,
.tti_id = 0,
.nPrbElm = 1,
};
struct xran_prb_elm *e = &prbmap.prbMap[0];
e->nStartSymb = 0;
e->numSymb = 14;
e->nRBStart = 0;
e->nRBSize = 12;
e->nBeamIndex = 0;
e->compMethod = f->ru_conf.compMeth;
e->iqWidth = f->ru_conf.iqWidth;
memset(&prbmap.sFrontHaulRxPacketCtrl, 0, XRAN_NUM_OF_SYMBOL_PER_SLOT * sizeof(struct xran_rx_packet_ctl));
return prbmap;
}
#endif
static uint32_t next_power_2(uint32_t num)
{
uint32_t power = 2;
@@ -199,10 +235,10 @@ static void oran_allocate_cplane_buffers(void *instHandle,
struct xran_flat_buffer buf[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN],
uint32_t ant,
uint32_t sect,
#ifdef F_RELEASE
#if defined(F_RELEASE) || defined(K_RELEASE)
uint32_t mtu,
const struct xran_fh_config *fh_config,
#endif
#endif
uint32_t size_of_prb_map,
oran_cplane_prb_config *prb_conf)
{
@@ -274,9 +310,14 @@ static void oran_allocate_cplane_buffers(void *instHandle,
}
}
}
#elif defined F_RELEASE
#elif defined(F_RELEASE) || defined(K_RELEASE)
if (fh_config->RunSlotPrbMapBySymbolEnable) {
#ifdef K_RELEASE
uint8_t mu_number = fh_config->mu_number[0];
xran_init_PrbMap_by_symbol_from_cfg(src, ptr, mtu, fh_config->perMu[mu_number].nDLRBs);
#elif defined(F_RELEASE)
xran_init_PrbMap_by_symbol_from_cfg(src, ptr, mtu, fh_config->nDLRBs);
#endif
} else {
xran_init_PrbMap_from_cfg(src, ptr, mtu);
}
@@ -289,19 +330,14 @@ static void oran_allocate_cplane_buffers(void *instHandle,
#endif
}
/* 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,
bool is_du,
int xran_inst,
int num_sectors,
oran_port_instance_t *portInstances,
#ifdef F_RELEASE
#if defined(F_RELEASE) || defined(K_RELEASE)
uint32_t mtu,
#endif
#endif
const struct xran_fh_config *fh_config)
{
AssertFatal(num_sectors == 1, "only support one sector at the moment\n");
@@ -330,6 +366,9 @@ static void oran_allocate_buffers(void *handle,
// DL/UL PRB mapping depending on the duplex mode
struct xran_prb_map dlPm = get_xran_prb_map(fh_config, XRAN_DIR_DL, 0, 14);
struct xran_prb_map ulPm = get_xran_prb_map(fh_config, XRAN_DIR_UL, 0, 14);
#ifdef K_RELEASE
struct xran_prb_map prachPm = get_xran_prb_map_prach(fh_config);
#endif
struct xran_prb_map dlPmMixed = {0};
struct xran_prb_map ulPmMixed = {0};
uint32_t idx = 0;
@@ -354,90 +393,154 @@ static void oran_allocate_buffers(void *handle,
.mixedSlotMap = ulPmMixed,
};
#ifdef K_RELEASE
oran_cplane_prb_config prachConf = {
.nTddPeriod = fh_config->frame_conf.nTddPeriod,
.mixed_slot_index = idx,
.slotMap = prachPm,
.mixedSlotMap = prachPm,
};
#endif
#ifdef E_RELEASE
uint32_t size_of_prb_map = sizeof(struct xran_prb_map) + sizeof(struct xran_prb_elm) * (xran_max_sections_per_slot - 1);
#elif defined F_RELEASE
#elif defined(F_RELEASE) || defined(K_RELEASE)
uint32_t numPrbElm = xran_get_num_prb_elm(&dlPm, mtu);
uint32_t size_of_prb_map = sizeof(struct xran_prb_map) + sizeof(struct xran_prb_elm) * (numPrbElm);
#endif
#ifdef K_RELEASE
uint32_t numPrbElmPrach = xran_get_num_prb_elm(&prachPm, mtu);
uint32_t size_of_prb_map_prach = sizeof(struct xran_prb_map) + sizeof(struct xran_prb_elm) * (numPrbElmPrach);
#endif
// PDSCH
#ifdef K_RELEASE
const uint32_t txBufSize = get_nSW_ToFpga_FTH_TxBufferLen(fh_config->nNumerology[0], fh_config->max_sections_per_slot);
#elif defined(E_RELEASE) || defined(F_RELEASE)
const uint32_t txBufSize = get_nSW_ToFpga_FTH_TxBufferLen(fh_config->frame_conf.nNumerology, fh_config->max_sections_per_slot);
#endif
oran_allocate_uplane_buffers(pi->instanceHandle, bl->src, bl->bufs.tx, xran_max_antenna_nr, txBufSize);
oran_allocate_cplane_buffers(pi->instanceHandle,
bl->srccp,
bl->bufs.tx_prbmap,
xran_max_antenna_nr,
xran_max_sections_per_slot,
#ifdef F_RELEASE
#if defined(F_RELEASE) || defined(K_RELEASE)
mtu,
fh_config,
#endif
#endif
size_of_prb_map,
&dlConf);
// PUSCH
#ifdef K_RELEASE
const uint32_t rxBufSize = get_nFpgaToSW_FTH_RxBufferLen(fh_config->nNumerology[0]);
#elif defined(E_RELEASE) || defined(F_RELEASE)
const uint32_t rxBufSize = get_nFpgaToSW_FTH_RxBufferLen(fh_config->frame_conf.nNumerology);
#endif
oran_allocate_uplane_buffers(pi->instanceHandle, bl->dst, bl->bufs.rx, xran_max_antenna_nr, rxBufSize);
oran_allocate_cplane_buffers(pi->instanceHandle,
bl->dstcp,
bl->bufs.rx_prbmap,
xran_max_antenna_nr,
xran_max_sections_per_slot,
#ifdef F_RELEASE
#if defined(F_RELEASE) || defined(K_RELEASE)
mtu,
fh_config,
#endif
#endif
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);
#ifdef K_RELEASE
oran_allocate_cplane_buffers(pi->instanceHandle,
bl->prachdstdecomp,
bl->bufs.prachdecomp,
xran_max_antenna_nr,
xran_max_sections_per_slot,
mtu,
fh_config,
size_of_prb_map_prach,
&prachConf);
#elif defined(E_RELEASE) || defined(F_RELEASE)
// PRACH decomp buffer does not have separate DPDK-allocated memory pool
// bufs, it points to the same pool as the prach buffer. Unclear to me why
for (uint32_t a = 0; a < xran_max_antenna_nr; ++a) {
for (uint32_t j = 0; j < XRAN_N_FE_BUF_LEN; ++j) {
bl->prachdstdecomp[a][j].pBuffers = &bl->bufs.prachdecomp[a][j][0];
bl->prachdstdecomp[a][j].pBuffers = &bl->bufs.prachdecomp[a][j];
for (uint32_t k = 0; k < XRAN_NUM_OF_SYMBOL_PER_SLOT; ++k) {
struct xran_flat_buffer *fb = &bl->prachdstdecomp[a][j].pBuffers[k];
fb->pData = bl->prachdst[a][j].pBuffers[k].pData;
}
}
}
#endif
struct xran_buffer_list *src[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list *srccp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list *dst[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list *dstcp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list *prach[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list *prachdecomp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list *prachdst[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_buffer_list *prachdstdecomp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
for (uint32_t a = 0; a < XRAN_MAX_ANTENNA_NR; ++a) {
for (uint32_t j = 0; j < XRAN_N_FE_BUF_LEN; ++j) {
src[a][j] = &bl->src[a][j];
srccp[a][j] = &bl->srccp[a][j];
dst[a][j] = &bl->dst[a][j];
dstcp[a][j] = &bl->dstcp[a][j];
prach[a][j] = &bl->prachdst[a][j];
prachdecomp[a][j] = &bl->prachdstdecomp[a][j];
prachdst[a][j] = &bl->prachdst[a][j];
prachdstdecomp[a][j] = &bl->prachdstdecomp[a][j];
}
}
xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, oai_xran_fh_rx_callback, &portInstances->pusch_tag);
xran_5g_prach_req(pi->instanceHandle, prach, prachdecomp, oai_xran_fh_rx_prach_callback, &portInstances->prach_tag);
if (is_du) {
#ifdef K_RELEASE
xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, oai_xran_fh_rx_callback, &portInstances->pusch_tag, fh_config->nNumerology[0]);
xran_5g_prach_req(pi->instanceHandle, prachdst, prachdstdecomp, oai_xran_fh_rx_prach_callback, &portInstances->prach_tag, fh_config->nNumerology[0]);
#elif defined(E_RELEASE) || defined(F_RELEASE)
xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, oai_xran_fh_rx_callback, &portInstances->pusch_tag);
xran_5g_prach_req(pi->instanceHandle, prachdst, prachdstdecomp, oai_xran_fh_rx_prach_callback, &portInstances->prach_tag);
#endif
} else {
xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, NULL, NULL, fh_config->nNumerology[0]);
}
}
int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_config *xran_fh_config)
{
int32_t xret = 0;
#ifdef K_RELEASE
xran_mem_mgr_leak_detector_init();
#endif
print_fh_init(xran_fh_init);
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
int ret = pthread_getaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
AssertFatal(ret != -1, "sched_getaffinity() failed errno %d (%s)", errno, strerror(errno));
xret = xran_init(0, NULL, xran_fh_init, NULL, &gxran_handle);
if (xret != XRAN_STATUS_SUCCESS) {
printf("xran_init failed %d\n", xret);
exit(-1);
}
cpu_set_t cpuset_after;
CPU_ZERO(&cpuset_after);
ret = pthread_getaffinity_np(pthread_self(), sizeof(cpuset_after), &cpuset_after);
AssertFatal(ret != -1, "sched_getaffinity() failed errno %d (%s)", errno, strerror(errno));
if (!CPU_EQUAL(&cpuset_after, &cpuset))
{
LOG_W(HW, "XRAN modifed affinity. Correcting affinity of caller\n");
ret = pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
AssertFatal(ret == 0, "Error in pthread_setaffinity_np(): ret: %d (%s)", ret, strerror(ret));
}
bool is_du = xran_fh_init->io_cfg.id == 0;
/** process all the O-RU|O-DU for use case */
for (int32_t o_xu_id = 0; o_xu_id < xran_fh_init->xran_ports; o_xu_id++) {
print_fh_config(&xran_fh_config[o_xu_id]);
@@ -455,21 +558,37 @@ int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_confi
pi->pusch_tag = tag;
#ifdef E_RELEASE
LOG_W(HW, "Please be aware that E release support will be removed in the future. Consider switching to F release.\n");
oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, &xran_fh_config[o_xu_id]);
#elif defined F_RELEASE
oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, xran_fh_init->mtu, &xran_fh_config[o_xu_id]);
oran_allocate_buffers(gxran_handle, is_du, o_xu_id, 1, pi, &xran_fh_config[o_xu_id]);
#elif defined(F_RELEASE) || defined(K_RELEASE)
oran_allocate_buffers(gxran_handle, is_du, o_xu_id, 1, pi, xran_fh_init->mtu, &xran_fh_config[o_xu_id]);
#endif
#ifdef K_RELEASE
if ((xret = xran_timingsource_reg_tticb(gxran_handle, oai_physide_dl_tti_call_back, NULL, 10, XRAN_CB_TTI)) != XRAN_STATUS_SUCCESS) {
printf("xran_timingsource_reg_tticb failed %d\n", xret);
exit(-1);
}
#elif defined(E_RELEASE) || defined(F_RELEASE)
if ((xret = xran_reg_physide_cb(gxran_handle, oai_physide_dl_tti_call_back, NULL, 10, XRAN_CB_TTI)) != XRAN_STATUS_SUCCESS) {
printf("xran_reg_physide_cb failed %d\n", xret);
exit(-1);
}
#endif
// retrieve and store prach duration
#ifdef K_RELEASE
uint8_t mu = xran_fh_config[o_xu_id].nNumerology[0];
uint8_t idx = xran_fh_config[o_xu_id].perMu[mu].prach_conf.nPrachConfIdx;
#elif defined(E_RELEASE) || defined(F_RELEASE)
uint8_t idx = xran_fh_config[o_xu_id].prach_conf.nPrachConfIdx;
#endif
const struct xran_frame_config *fc = &xran_fh_config[o_xu_id].frame_conf;
g_prach_info[o_xu_id] = get_nr_prach_occasion_info_from_index(idx,
#ifdef K_RELEASE
mu > 2 ? FR2 : FR1,
#elif defined(E_RELEASE) || defined(F_RELEASE)
fc->nNumerology > 2 ? FR2 : FR1,
#endif
fc->nFrameDuplexType == XRAN_FDD ? duplex_mode_FDD : duplex_mode_TDD);
}
@@ -477,6 +596,10 @@ int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_confi
// these structs during initialization
memcpy(&g_fh_init, xran_fh_init, sizeof(*xran_fh_init));
memcpy(&g_fh_config, xran_fh_config, sizeof(*xran_fh_config) * xran_fh_init->xran_ports);
if (!is_du) {
const int num_callbacks_per_slot = 2; // results in callbacks at RX window end of symbol 7 and 14.
install_symbol_callback(gxran_handle, num_callbacks_per_slot, xran_fh_config->nNumerology[0]);
}
return (void *)gxran_handle;
}

View File

@@ -32,7 +32,7 @@ typedef struct oran_bufs {
struct xran_flat_buffer rx_prbmap[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
struct xran_flat_buffer prach[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT];
struct xran_flat_buffer prachdecomp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT];
struct xran_flat_buffer prachdecomp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
} oran_bufs_t;
typedef struct oran_buf_list {

View File

@@ -99,15 +99,19 @@
#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_TA3 "Ta3_up"
#define ORAN_FH_CONFIG_T2A "T2a_up"
#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_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_T1A_CP_DL, "T1a_cp_dl" ORAN_FH_HLP_CPLT, 0, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_T1A_CP_UL, "T1a_cp_ul" ORAN_FH_HLP_CPLT, 0, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_T1A_UP, "T1a_up" ORAN_FH_HLP_CPLT, 0, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_TA4, "Ta4" ORAN_FH_HLP_CPLT, 0, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_TA3, "Ta3" ORAN_FH_HLP_CPLT, 0, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_T2A, "T2a" ORAN_FH_HLP_CPLT, 0, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
}
// clang-format on

53
radio/fhi_72/oran_debug.c Normal file
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
*/
#include "oran_debug.h"
#include "openair1/PHY/TOOLS/tools_defs.h"
void dump_nonzero_symbol(c16_t *txdataF, uint32_t ofdm_symbol_size, int frame, int slot, int symbol, const char* loc)
{
float signal_energy = signal_energy_nodc(txdataF, ofdm_symbol_size);
if (signal_energy > 1) {
// Prepare a buffer to hold the formatted string for the symbol
const int num_chars_per_sample = 4 + 6 * 2;
char symbol_buf[ofdm_symbol_size * num_chars_per_sample]; // Enough for "(r,i) " per sample
int offset = 0;
bool is_zero_block = true;
for (int i = 0; i < ofdm_symbol_size; i++) {
bool is_zero = txdataF[i].r == 0 && txdataF[i].i == 0;
if (is_zero_block && !is_zero) {
offset += snprintf(symbol_buf + offset, sizeof(symbol_buf) - offset, "[sc %d]: ", i);
is_zero_block = false;
}
if (!is_zero_block && is_zero) {
is_zero_block = true;
}
if (!is_zero) {
offset += snprintf(symbol_buf + offset, sizeof(symbol_buf) - offset, "(%d,%d) ", txdataF[i].r, txdataF[i].i);
}
}
symbol_buf[offset] = '\0';
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
LOG_D(HW, "dump_nonzero_symbol: Frame.Slot.Symbol %d.%d.%d (%s) signal_energy %.3f time %ld.%09ld samples: %s\n", frame, slot, symbol, loc, 10 * log10(signal_energy), ts.tv_sec, ts.tv_nsec, symbol_buf);
}
}

29
radio/fhi_72/oran_debug.h Normal file
View File

@@ -0,0 +1,29 @@
/*
* 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_DEBUG_H__
#define __ORAN_DEBUG_H__
#include <stdint.h>
#include "common/platform_types.h"
void dump_nonzero_symbol(c16_t *txdataF, uint32_t ofdm_symbol_size, int frame, int slot, int symbol, const char* loc);
#endif

View File

@@ -34,11 +34,13 @@
#include "openair1/PHY/NR_TRANSPORT/nr_transport_proto.h"
#include "oaioran.h"
#include "oran-config.h"
#include "oaioran_ru.h"
// include the following file for VERSIONX, version of xran lib, to print it during
// startup. Only relevant for printing, if it ever makes problem, remove this
// line and the use of VERSIONX further below. It is relative to phy/fhi_lib/lib/api
#include "../../app/src/common.h"
#include "oran_debug.h"
#ifdef OAI_MPLANE
#include "mplane/init-mplane.h"
@@ -51,9 +53,13 @@ typedef struct {
int capabilities_sent;
void *oran_priv;
void *mplane_priv;
uint32_t nCC;
} oran_eth_state_t;
notifiedFIFO_t oran_sync_fifo;
#ifdef K_RELEASE
notifiedFIFO_t oran_sync_fifo_prach;
#endif
int trx_oran_start(openair0_device *device)
{
@@ -62,27 +68,76 @@ int trx_oran_start(openair0_device *device)
oran_eth_state_t *s = device->priv;
// Start ORAN
#ifdef K_RELEASE
if (xran_timingsource_start() != 0) {
printf("%s:%d:%s: Start timing source failed ... Exit\n", __FILE__, __LINE__, __FUNCTION__);
exit(1);
} else {
printf("Start timing source. Done\n");
}
if (xran_start_worker_threads() != 0) {
printf("%s:%d:%s: Start worker thread failed ... Exit\n", __FILE__, __LINE__, __FUNCTION__);
exit(1);
} else {
printf("Start worker thread. Done\n");
}
xran_mem_mgr_leak_detector_display(0);
#endif
if (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");
}
#ifdef K_RELEASE
for (int32_t cc_id = 0; cc_id < s->nCC; cc_id++) {
if (xran_activate_cc(s->oran_priv, cc_id) != 0) {
printf("%s:%d:%s: Activate CC failed ... Exit\n", __FILE__, __LINE__, __FUNCTION__);
exit(1);
} else {
printf("Activate CC. Done\n");
}
}
#endif
return 0;
}
void trx_oran_end(openair0_device *device)
{
printf("ORAN: %s\n", __FUNCTION__);
stop_oru();
oran_eth_state_t *s = device->priv;
#ifdef K_RELEASE
xran_shutdown(s->oran_priv);
#endif
xran_close(s->oran_priv);
#ifdef K_RELEASE
xran_cleanup();
xran_mem_mgr_leak_detector_destroy();
#endif
}
int trx_oran_stop(openair0_device *device)
{
printf("ORAN: %s\n", __FUNCTION__);
oran_eth_state_t *s = device->priv;
#ifdef K_RELEASE
for (int32_t cc_id = 0; cc_id < s->nCC; cc_id++) {
xran_deactivate_cc(s->oran_priv, cc_id);
xran_stop(s->oran_priv);
}
xran_timingsource_stop();
#elif defined(E_RELEASE) || defined(F_RELEASE)
xran_stop(s->oran_priv);
#endif
#ifdef OAI_MPLANE
printf("[MPLANE] Stopping M-plane.\n");
disconnect_mplane(s->mplane_priv);
@@ -212,6 +267,11 @@ int trx_oran_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len)
return 0;
}
void oran_fh_if4p5_north_in(uint32_t **txdataF, int nb_tx, sense_of_time_t* sense_of_time, int *num_symbols) {
int ret = xran_oru_tx_read_slot(txdataF, nb_tx, &sense_of_time->frame, &sense_of_time->slot, &sense_of_time->symbol, num_symbols, &sense_of_time->ts);
AssertFatal(ret == 0, "ORAN: Error reading slot");
}
void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
{
prach_item_t *prach_id = find_nr_prach(&ru->gNB_list[0]->prach_list, *frame, *slot, SEARCH_EXIST);
@@ -282,7 +342,16 @@ void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp)
};
// printf("south_out:\tframe=%d\tslot=%d\ttimestamp=%ld\n",frame,slot,timestamp);
if (frame == 0) {
for (int sym = 0; sym < 14; sym++) {
dump_nonzero_symbol((c16_t *)&ru->common.txdataF_BF[0][sym * ru->nr_frame_parms->ofdm_symbol_size],
ru->nr_frame_parms->ofdm_symbol_size,
frame,
slot,
sym,
"du_write_dl_iq");
}
}
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");
@@ -381,11 +450,15 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d
// create message queues for ORAN sync
initNotifiedFIFO(&oran_sync_fifo);
#ifdef K_RELEASE
initNotifiedFIFO(&oran_sync_fifo_prach);
#endif
eth->e.flags = ETH_RAW_IF4p5_MODE;
eth->e.compression = NO_COMPRESS;
eth->e.if_name = eth_params->local_if_name;
eth->last_msg = (rru_config_msg_type_t)-1;
eth->nCC = fh_config->nCC;
device->Mod_id = 0;
device->transp_type = ETHERNET_TP;
@@ -403,6 +476,8 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d
device->get_internal_parameter = get_internal_parameter;
device->priv = eth;
device->openair0_cfg = &openair0_cfg[0];
device->xran_api.north_in_func = oran_fh_if4p5_north_in;
device->xran_api.write_prach = xran_oru_send_prach;
return 0;
}

View File

@@ -123,6 +123,7 @@ typedef struct {
Actor_t *channel_modelling_actors;
char *taps_socket;
int client_num_rx_antennas;
struct timespec start_ts;
} vrtsim_state_t;
static void histogram_add(histogram_t *histogram, double diff)
@@ -203,30 +204,24 @@ static void vrtsim_readconfig(vrtsim_state_t *vrtsim_state)
static void *vrtsim_timing_job(void *arg)
{
vrtsim_state_t *vrtsim_state = arg;
struct timespec timestamp;
if (clock_gettime(CLOCK_REALTIME, &timestamp)) {
struct timespec start_ts;
if (clock_gettime(CLOCK_REALTIME, &start_ts)) {
LOG_E(UTIL, "clock_gettime failed\n");
exit(1);
}
double leftover_samples = 0;
int64_t last_sample_index = 0;
vrtsim_state->start_ts = start_ts;
while (vrtsim_state->run_timing_thread) {
struct timespec current_time;
if (clock_gettime(CLOCK_REALTIME, &current_time)) {
LOG_E(UTIL, "clock_gettime failed\n");
exit(1);
}
uint64_t diff = (current_time.tv_sec - timestamp.tv_sec) * 1000000000 + (current_time.tv_nsec - timestamp.tv_nsec);
timestamp = current_time;
double samples_to_produce = vrtsim_state->sample_rate * vrtsim_state->timescale * diff / 1e9;
// Attempt to correct compounding rounding error
leftover_samples += samples_to_produce - (uint64_t)samples_to_produce;
if (leftover_samples > 1.0f) {
samples_to_produce += 1;
leftover_samples -= 1;
}
AssertFatal(samples_to_produce >= 0, "Negative samples to produce: %f\n", samples_to_produce);
uint64_t diff = (current_time.tv_sec - start_ts.tv_sec) * 1000000000 + (current_time.tv_nsec - start_ts.tv_nsec);
double sample_index = vrtsim_state->sample_rate * vrtsim_state->timescale * diff / 1e9;
int64_t samples_to_produce = sample_index - last_sample_index;
shm_td_iq_channel_produce_samples(vrtsim_state->channel, samples_to_produce);
last_sample_index = sample_index;
usleep(1);
}
return 0;
@@ -679,6 +674,14 @@ static int vrtsim_set_beams2(openair0_device *device, int *beam_ids, int num_bea
return 0;
}
openair0_timestamp vrtsim_get_timestamp(openair0_device *device, struct timespec *ts)
{
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
uint64_t diff = (ts->tv_sec - vrtsim_state->start_ts.tv_sec) * 1000000000 + (ts->tv_nsec - vrtsim_state->start_ts.tv_nsec);
double diff_samples = vrtsim_state->sample_rate * vrtsim_state->timescale * diff / 1e9;
return diff_samples > 0 ? diff_samples : 0;
}
__attribute__((__visibility__("default"))) int device_init(openair0_device *device, openair0_config_t *openair0_cfg)
{
randominit();
@@ -698,6 +701,9 @@ __attribute__((__visibility__("default"))) int device_init(openair0_device *devi
device->trx_write_beams_func = vrtsim_write_beams;
device->trx_set_beams = vrtsim_set_beams;
device->trx_set_beams2 = vrtsim_set_beams2;
if (vrtsim_state->role == ROLE_SERVER) {
device->get_timestamp = vrtsim_get_timestamp;
}
device->type = RFSIMULATOR;
device->openair0_cfg = &openair0_cfg[0];

View File

@@ -0,0 +1,100 @@
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
ORUs = (
{
tx_bw = [106];
rx_bw = [106];
carrier_tx = [4049760];
carrier_rx = [4049760];
prach_config_index = 157;
prach_msg1_start = 0;
tdd_period = 5;
num_dl_slots = 3;
num_dl_symbols = 6;
num_ul_slots = 1;
num_ul_symbols = 4;
numerology = 1;
});
RUs = (
{
local_rf = "no";
nb_tx = 2;
nb_rx = 2;
att_tx = 0;
att_rx = 0;
bands = [77];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
sf_extension = 0;
eNB_instances = [0];
sl_ahead = 5;
tr_preference = "raw_if4p5"; # important: activate FHI7.2
do_precoding = 0; # needs to match O-RU configuration
# PRACH configuration
num_tp_cores = 4;
tp_cores = [-1,-1,-1,-1];
});
log_config :
{
global_log_level = "info";
hw_log_level = "info";
phy_log_level = "info";
mac_log_level = "info";
rlc_log_level = "info";
pdcp_log_level = "info";
rrc_log_level = "info";
ngap_log_level = "info";
f1ap_log_level = "info";
};
fhi_72 = {
dpdk_devices = ("0000:05:02.0", "0000:05:02.1"); # one VF can be used as well
system_core = 25;
io_core = 26;
worker_cores = (27);
du_addr = ("00:11:22:33:64:68", "00:11:22:33:64:69");
mtu = 9600;
file_prefix = "ru";
fh_config = ({
T1a_cp_dl = (285, 470);
T1a_cp_ul = (285, 429);
Ta3_up = (200, 470);
T1a_up = (400, 450);
T2a_up = (300, 450);
Ta4 = (100, 350);
ru_config = {
iq_width = 16;
iq_width_prach = 16;
};
});
};
channelmod = {
max_chan=10;
modellist="modellist_rfsimu_1";
modellist_rfsimu_1 = (
{
model_name = "server_tx_channel_model"
type = "Rayleigh8";
ploss_dB = 0;
noise_power_dB = 0;
forgetfact = 0;
offset = 0;
ds_tdl = 0;
},
{
model_name = "rfsimu_channel_ue0"
type = "AWGN";
ploss_dB = 0;
noise_power_dB = 0;
forgetfact = 0;
offset = 0;
ds_tdl = 0;
}
);
}