mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 12:40:28 +00:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff0cf7dfef | ||
|
|
070723a179 | ||
|
|
dea523f0c7 | ||
|
|
6fc718cbbe | ||
|
|
4be054990c | ||
|
|
3d049174ca | ||
|
|
9989ba0fce | ||
|
|
83f8447eb9 | ||
|
|
02d3f924fb | ||
|
|
cfe85db76d | ||
|
|
efe7c63362 | ||
|
|
28a2149bcf | ||
|
|
64590837af | ||
|
|
eae421cce6 | ||
|
|
a744dc8f85 | ||
|
|
253ad4dca1 | ||
|
|
43be360a15 | ||
|
|
670902fbca | ||
|
|
1128782fc7 | ||
|
|
c46b193cc6 | ||
|
|
ef7d1f7020 | ||
|
|
4970fc151c | ||
|
|
0c55c94a25 | ||
|
|
5b4bbfc953 | ||
|
|
3716359dea | ||
|
|
81bf88f4a6 | ||
|
|
cb6f10aa55 | ||
|
|
c2aac2259c | ||
|
|
82c9b2534f | ||
|
|
4a58ba0aa3 | ||
|
|
02ec8dd39e | ||
|
|
bb7b01caf9 | ||
|
|
9c158f7240 | ||
|
|
47880484ec | ||
|
|
26783d0b47 | ||
|
|
bc2d5899d8 | ||
|
|
1ee401401c | ||
|
|
84daf5b0c3 | ||
|
|
d0702f648f | ||
|
|
43a37bcef7 | ||
|
|
19874a1be1 | ||
|
|
c2a633e175 | ||
|
|
23c8179b5f | ||
|
|
7ffdfa50a6 | ||
|
|
499b8fb2c4 | ||
|
|
3e127abbbf | ||
|
|
0cdfb3c865 |
@@ -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
|
||||
###################################################
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
310
cmake_targets/tools/oran_fhi_integration_patches/K/hook.patch
Normal file
310
cmake_targets/tools/oran_fhi_integration_patches/K/hook.patch
Normal file
@@ -0,0 +1,310 @@
|
||||
diff --git a/fhi_lib/lib/api/xran_fh_o_ru.h b/fhi_lib/lib/api/xran_fh_o_ru.h
|
||||
index 959479f..08c7d40 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,30 @@ 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);
|
||||
+typedef void (*sym_ota_fn)(void * handle, 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,
|
||||
+ sym_ota_fn sym_ota_fn_p,
|
||||
+ void *sym_ota_fn_args,
|
||||
+ int mu);
|
||||
+void xran_hook_schedule_packet(void *pHandle, struct rte_mbuf *mbuf, int port,
|
||||
+ enum xran_pkt_dir direction, int ru_port_id,
|
||||
+ int slot, int symbol);
|
||||
+int xran_hook_send_packet(void *pHandle, struct rte_mbuf *mbuf, int port, enum xran_pkt_dir direction, int ru_port_id);
|
||||
|
||||
#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..ab52008 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,114 @@ 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;
|
||||
+ sym_ota_fn sym_ota_fn;
|
||||
+ void *sym_ota_fn_args;
|
||||
+} 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 slot_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, slot_in_frame, p_sense_of_time->nSymIdx);
|
||||
+ if (cb_args->sym_ota_fn) {
|
||||
+ cb_args->sym_ota_fn(cb_args->sym_ota_fn_args, p_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,
|
||||
+ sym_ota_fn sym_ota_fn_p,
|
||||
+ void *sym_ota_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_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 = {0};
|
||||
+ cb_args.port = 0;
|
||||
+ cb_args.mu = mu;
|
||||
+ cb_args.pHandle = pHandle;
|
||||
+ cb_args.sym_ota_fn = sym_ota_fn_p;
|
||||
+ cb_args.sym_ota_fn_args = sym_ota_fn_args;
|
||||
+ 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,
|
||||
+ enum xran_pkt_dir direction, int ru_port_id,
|
||||
+ int slot, int symbol) {
|
||||
+ void *ret = rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ether_hdr));
|
||||
+ if (ret == NULL) rte_panic("not enough headroom for ethernet header");
|
||||
+ struct xran_device_ctx *p_dev_ctx = (struct xran_device_ctx *)pHandle;
|
||||
+ int vf_id = xran_map_ecpriPcid_to_vf(pHandle, direction, 0, ru_port_id);
|
||||
+ struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
|
||||
+
|
||||
+ mbuf->port = ctx->io_cfg.port[vf_id];
|
||||
+ xran_add_eth_hdr_vlan(&ctx->entities[vf_id][ID_O_RU], ETHER_TYPE_ECPRI, mbuf);
|
||||
+
|
||||
+ 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");
|
||||
+}
|
||||
+
|
||||
+int xran_hook_send_packet(void *pHandle, struct rte_mbuf *mbuf, int port, enum xran_pkt_dir direction, int ru_port_id) {
|
||||
+ void *ret = rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ether_hdr));
|
||||
+ if (ret == NULL) rte_panic("not enough headroom for ethernet header");
|
||||
+ int vf_id = xran_map_ecpriPcid_to_vf(pHandle, direction, 0, ru_port_id);
|
||||
+ if (xran_ethdi_mbuf_send(mbuf, ETHER_TYPE_ECPRI, vf_id) == 1) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
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..71be5d9 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_control[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;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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, §_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, ¶ms, 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, ¶ms, 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, ¶ms, 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));
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -208,8 +208,11 @@ IQChannelErrorType shm_td_iq_channel_rx(ShmTDIQChannel *channel,
|
||||
size_t num_samples_first_copy = CIRCULAR_BUFFER_SIZE - first_sample;
|
||||
memcpy(tx_iq_data, base_ptr + first_sample, num_samples_first_copy * sizeof(sample_t));
|
||||
memcpy(tx_iq_data + num_samples_first_copy, base_ptr, (num_samples - num_samples_first_copy) * sizeof(sample_t));
|
||||
memset(base_ptr + first_sample, 0, num_samples_first_copy * sizeof(sample_t));
|
||||
memset(base_ptr, 0, (num_samples - num_samples_first_copy) * sizeof(sample_t));
|
||||
} else {
|
||||
memcpy(tx_iq_data, base_ptr + first_sample, num_samples * sizeof(sample_t));
|
||||
memset(base_ptr + first_sample, 0, num_samples * sizeof(sample_t));
|
||||
}
|
||||
return CHANNEL_NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
18
doc/tutorial_resources/oru/README.md
Normal file
18
doc/tutorial_resources/oru/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
This directory contains example configuration files for running O-RU + O-DU + UE
|
||||
|
||||
For O-DU:
|
||||
|
||||
```
|
||||
sudo ./nr-softmodem -O du.2x2.conf --gNBs.[0].min_rxtxtime 6
|
||||
```
|
||||
|
||||
For O-RU:
|
||||
```
|
||||
sudo ./oainr_ru -O ru.2x2.conf --vrtsim.role server
|
||||
```
|
||||
|
||||
For UE:
|
||||
|
||||
```
|
||||
sudo ./nr-uesoftmodem -C 4049760000 -r 106 --numerology 1 --ssb 516 --band 77 --device.name vrtsim
|
||||
```
|
||||
274
doc/tutorial_resources/oru/du.2x2.conf
Normal file
274
doc/tutorial_resources/oru/du.2x2.conf
Normal file
@@ -0,0 +1,274 @@
|
||||
Active_gNBs = ( "gNB-OAI");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_ID = 0xe00;
|
||||
gNB_name = "gNB-OAI";
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); });
|
||||
|
||||
nr_cellid = 1;
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
pdsch_AntennaPorts_XP = 2;
|
||||
pdsch_AntennaPorts_N1 = 1;
|
||||
maxMIMO_layers = 1;
|
||||
pusch_AntennaPorts = 2;
|
||||
do_CSIRS = 1;
|
||||
do_SRS = 0;
|
||||
sib1_tda = 15;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
#spCellConfigCommon
|
||||
|
||||
physCellId = 0;
|
||||
# n_TimingAdvanceOffset = 0;
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# center frequency = 4049.76 MHz
|
||||
# selected SSB frequency = 4049.76 MHz
|
||||
absoluteFrequencySSB = 669984;
|
||||
dl_frequencyBand = 77;
|
||||
# frequency point A = 4030.68 MHz
|
||||
dl_absoluteFrequencyPointA = 668712;
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing = 1;
|
||||
dl_carrierBandwidth = 106;
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
initialDLBWPlocationAndBandwidth = 28875; #38.101-1 Table 5.3.2-1
|
||||
#
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing = 1;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 11;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
ul_frequencyBand = 77;
|
||||
#scs-SpecificCarrierList
|
||||
ul_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
ul_subcarrierSpacing = 1;
|
||||
ul_carrierBandwidth = 106;
|
||||
pMax = 23;
|
||||
#initialUplinkBWP
|
||||
#genericParameters
|
||||
initialULBWPlocationAndBandwidth = 28875;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialULBWPsubcarrierSpacing = 1;
|
||||
#rach-ConfigCommon
|
||||
#rach-ConfigGeneric
|
||||
prach_ConfigurationIndex = 157;
|
||||
#prach_msg1_FDM
|
||||
#0 = one, 1=two, 2=four, 3=eight
|
||||
prach_msg1_FDM = 0;
|
||||
prach_msg1_FrequencyStart = 0;
|
||||
zeroCorrelationZoneConfig = 0;
|
||||
preambleReceivedTargetPower = -100;
|
||||
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
|
||||
preambleTransMax = 7;
|
||||
#powerRampingStep
|
||||
# 0=dB0,1=dB2,2=dB4,3=dB6
|
||||
powerRampingStep = 2;
|
||||
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
|
||||
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
|
||||
#one (0..15) 4,8,12,16,...60,64
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
|
||||
#ra_ContentionResolutionTimer
|
||||
#(0..7) 8,16,24,32,40,48,56,64
|
||||
ra_ContentionResolutionTimer = 7;
|
||||
rsrp_ThresholdSSB = 19;
|
||||
#prach-RootSequenceIndex_PR
|
||||
#1 = 839, 2 = 139
|
||||
prach_RootSequenceIndex_PR = 2;
|
||||
prach_RootSequenceIndex = 1;
|
||||
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
|
||||
#
|
||||
msg1_SubcarrierSpacing = 1,
|
||||
# restrictedSetConfig
|
||||
# 0=unrestricted, 1=restricted type A, 2=restricted type B
|
||||
restrictedSetConfig = 0,
|
||||
|
||||
# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB
|
||||
msg3_DeltaPreamble = 2;
|
||||
p0_NominalWithGrant = -100;
|
||||
|
||||
# pucch-ConfigCommon setup :
|
||||
# pucchGroupHopping
|
||||
# 0 = neither, 1= group hopping, 2=sequence hopping
|
||||
pucchGroupHopping = 0;
|
||||
hoppingId = 0;
|
||||
p0_nominal = -96;
|
||||
|
||||
ssb_PositionsInBurst_Bitmap = 0x1;
|
||||
|
||||
# ssb_periodicityServingCell
|
||||
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
|
||||
ssb_periodicityServingCell = 2;
|
||||
|
||||
# dmrs_TypeA_position
|
||||
# 0 = pos2, 1 = pos3
|
||||
dmrs_TypeA_Position = 0;
|
||||
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
subcarrierSpacing = 1;
|
||||
|
||||
|
||||
#tdd-UL-DL-ConfigurationCommon
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
referenceSubcarrierSpacing = 1;
|
||||
# pattern1
|
||||
# dl_UL_TransmissionPeriodicity
|
||||
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
|
||||
dl_UL_TransmissionPeriodicity = 5;
|
||||
nrofDownlinkSlots = 3;
|
||||
nrofDownlinkSymbols = 6;
|
||||
nrofUplinkSlots = 1;
|
||||
nrofUplinkSymbols = 4;
|
||||
|
||||
ssPBCH_BlockPower = 0;
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
|
||||
# ------- SCTP definitions
|
||||
SCTP :
|
||||
{
|
||||
# Number of streams to use in input/output
|
||||
SCTP_INSTREAMS = 2;
|
||||
SCTP_OUTSTREAMS = 2;
|
||||
};
|
||||
|
||||
|
||||
////////// AMF parameters:
|
||||
amf_ip_address = ({ ipv4 = "172.21.6.5"; });
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.51";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51";
|
||||
GNB_PORT_FOR_S1U = 2152; # Spec 2152
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
MACRLCs = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "local_RRC";
|
||||
pusch_TargetSNRx10 = 200;
|
||||
pucch_TargetSNRx10 = 200;
|
||||
# dl_bler_target_upper = .35;
|
||||
# dl_bler_target_lower = .15;
|
||||
ul_bler_target_upper = .35;
|
||||
ul_bler_target_lower = .15;
|
||||
pusch_FailureThres = 100;
|
||||
}
|
||||
);
|
||||
|
||||
L1s = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 110;
|
||||
pucch0_dtx_threshold = 80;
|
||||
pusch_dtx_threshold = -100;
|
||||
# thread_pool_size = 8;
|
||||
tx_amp_backoff_dB = 36;
|
||||
L1_rx_thread_core = 11;
|
||||
L1_tx_thread_core = 12;
|
||||
phase_compensation = 0; # needs to match O-RU configuration
|
||||
}
|
||||
);
|
||||
|
||||
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];
|
||||
ru_thread_core = 10;
|
||||
sl_ahead = 5;
|
||||
tr_preference = "raw_if4p5"; # important: activate FHI7.2
|
||||
do_precoding = 0; # needs to match O-RU configuration
|
||||
}
|
||||
);
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nea0, nea1, nea2, nea3
|
||||
ciphering_algorithms = ( "nea0" );
|
||||
|
||||
# preferred integrity algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nia0, nia1, nia2, nia3
|
||||
integrity_algorithms = ( "nia2", "nia0" );
|
||||
|
||||
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
|
||||
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
|
||||
drb_ciphering = "yes";
|
||||
drb_integrity = "no";
|
||||
};
|
||||
|
||||
log_config :
|
||||
{
|
||||
global_log_level = "info";
|
||||
hw_log_level = "info";
|
||||
phy_log_level = "info";
|
||||
mac_log_level = "info";
|
||||
rlc_log_level = "info";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
ngap_log_level = "info";
|
||||
f1ap_log_level = "info";
|
||||
};
|
||||
|
||||
fhi_72 = {
|
||||
dpdk_devices = ("0000:05:02.2", "0000:05:02.3"); # one VF can be used as well
|
||||
system_core = 7;
|
||||
io_core = 8;
|
||||
worker_cores = (9);
|
||||
ru_addr = ("00:11:22:33:64:66", "00:11:22:33:64:67");
|
||||
#ru_addr = ("00:11:22:33:64:66", "00:11:22:33:64:70");
|
||||
mtu = 9600;
|
||||
fh_config = ({
|
||||
T1a_cp_dl = (285, 470);
|
||||
T1a_cp_ul = (285, 429);
|
||||
T1a_up = (300, 450);
|
||||
Ta4 = (400, 440);
|
||||
Ta3_up = (200, 350);
|
||||
T2a_up = (300, 450);
|
||||
ru_config = {
|
||||
iq_width = 16;
|
||||
iq_width_prach = 16;
|
||||
};
|
||||
});
|
||||
};
|
||||
96
doc/tutorial_resources/oru/ru.2x2.conf
Normal file
96
doc/tutorial_resources/oru/ru.2x2.conf
Normal file
@@ -0,0 +1,96 @@
|
||||
# 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;
|
||||
tp_cores = [-1, -1, -1, -1, -1, -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
|
||||
});
|
||||
|
||||
|
||||
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");
|
||||
#du_addr = ("00:11:22:33:64:68", "00:11:22:33:64:69");
|
||||
mtu = 9600;
|
||||
file_prefix = "ru";
|
||||
fh_config = ({
|
||||
Ta3_up = (200, 470);
|
||||
T2a_up = (200, 450);
|
||||
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;
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 && \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 && \
|
||||
|
||||
@@ -36,6 +36,7 @@ ENV TZ=Europe/Paris
|
||||
RUN dnf update -y && \
|
||||
dnf install -y \
|
||||
procps-ng \
|
||||
libatomic \
|
||||
libXpm \
|
||||
libX11 \
|
||||
lksctp-tools \
|
||||
|
||||
@@ -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 \
|
||||
|
||||
280
executables/main_nr_ru.c
Normal file
280
executables/main_nr_ru.c
Normal file
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* 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);
|
||||
init_timeshift_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;
|
||||
}
|
||||
756
executables/nr-oru.c
Normal file
756
executables/nr-oru.c
Normal file
@@ -0,0 +1,756 @@
|
||||
/*
|
||||
* 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"
|
||||
#include "thread-pool.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;
|
||||
|
||||
typedef struct {
|
||||
ORU_t *oru;
|
||||
int frame;
|
||||
int slot;
|
||||
int symbol;
|
||||
int aarx;
|
||||
} pusch_symbol_job_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);
|
||||
static void receive_pusch(void *args);
|
||||
|
||||
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];
|
||||
}
|
||||
ru->common.txdataF_BF = (int32_t **)txDataF_ptr;
|
||||
|
||||
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, ×tamp, 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, ×tamp, 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;
|
||||
|
||||
const int max_pusch_jobs = 300;
|
||||
pusch_symbol_job_t pusch_job_pool[max_pusch_jobs];
|
||||
uint32_t pusch_job_index = 0;
|
||||
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, ×tamp, (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) {
|
||||
|
||||
nfapi_nr_config_request_scf_t *config = &ru->config;
|
||||
nfapi_nr_tdd_table_t *tdd_table = &config->tdd_table;
|
||||
AssertFatal(tdd_table->tdd_period.tl.tag == NFAPI_NR_CONFIG_TDD_PERIOD_TAG, "");
|
||||
int nb_periods_per_frame = get_nb_periods_per_frame(tdd_table->tdd_period.value);
|
||||
int n_tdd_period = fp->slots_per_frame / nb_periods_per_frame;
|
||||
nfapi_nr_max_num_of_symbol_per_slot_t *max_num_of_symbol_per_slot_list =
|
||||
config->tdd_table.max_tdd_periodicity_list[slot % n_tdd_period].max_num_of_symbol_per_slot_list;
|
||||
if (max_num_of_symbol_per_slot_list[symbol].slot_config.value != 1)
|
||||
continue;
|
||||
|
||||
int prach_symbol = get_prach_symbol(oru, frame, slot, symbol, ru->numerology);
|
||||
if (prach_symbol != -1) {
|
||||
receive_prach(oru, frame, slot, prach_symbol);
|
||||
}
|
||||
for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) {
|
||||
pusch_symbol_job_t *job = &pusch_job_pool[pusch_job_index++ % max_pusch_jobs];
|
||||
job->oru = oru;
|
||||
job->aarx = aarx;
|
||||
job->frame = frame;
|
||||
job->slot = slot;
|
||||
job->symbol = symbol;
|
||||
task_t task = {.func = receive_pusch, .args = job};
|
||||
pushTpool(&oru->tpool, task);
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void receive_pusch(void *args)
|
||||
{
|
||||
pusch_symbol_job_t *job = args;
|
||||
ORU_t *oru = job->oru;
|
||||
int frame = job->frame;
|
||||
int slot = job->slot;
|
||||
int symbol = job->symbol;
|
||||
int aarx = job->aarx;
|
||||
RU_t *ru = oru->ru;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
|
||||
c16_t rxdataF[fp->ofdm_symbol_size * fp->symbols_per_slot] __attribute__((aligned(32)));
|
||||
|
||||
nr_slot_fep_ul(fp, ru->common.rxdata[aarx], (int32_t *)rxdataF, symbol, slot, ru->N_TA_offset);
|
||||
apply_nr_rotation_symbol_RX(fp,
|
||||
&rxdataF[symbol * fp->ofdm_symbol_size],
|
||||
fp->symbol_rotation[link_type_ul],
|
||||
fp->N_RB_UL,
|
||||
slot,
|
||||
symbol);
|
||||
ru->ifdevice.xran_api.write_pusch((uint32_t *)&rxdataF[symbol * fp->ofdm_symbol_size], aarx, frame, slot, symbol);
|
||||
}
|
||||
78
executables/nr-oru.h
Normal file
78
executables/nr-oru.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,38 @@ 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);
|
||||
|
||||
/*!
|
||||
* \brief Write data for one PUSCH symbol
|
||||
* \param prachF Frequency domain PUSCH data
|
||||
* \param aarx
|
||||
* \param frame
|
||||
* \param slot
|
||||
* \param symbol
|
||||
*/
|
||||
void (*write_pusch)(uint32_t *prachF, int aarx, int frame, int slot, int symbol);
|
||||
} xran_api;
|
||||
};
|
||||
|
||||
/* type of device init function, implemented in shared lib */
|
||||
@@ -730,7 +774,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
|
||||
|
||||
@@ -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)
|
||||
|
||||
68
radio/fhi_72/circular_buffer.c
Normal file
68
radio/fhi_72/circular_buffer.c
Normal 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]);
|
||||
}
|
||||
}
|
||||
37
radio/fhi_72/circular_buffer.h
Normal file
37
radio/fhi_72/circular_buffer.h
Normal 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
132
radio/fhi_72/iq_worker.c
Normal 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
29
radio/fhi_72/iq_worker.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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->perMu[mu].nDLFftSize;
|
||||
#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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
624
radio/fhi_72/oaioran_ru.c
Normal file
624
radio/fhi_72/oaioran_ru.c
Normal file
@@ -0,0 +1,624 @@
|
||||
/*
|
||||
* 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 "common/platform_types.h"
|
||||
#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_cp.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"
|
||||
#include <stdatomic.h>
|
||||
|
||||
#define RATE_LIMIT(n) if (({ static int _counter = 0; _counter++ % (n) == 0; }))
|
||||
#define ETHER_TYPE_ECPRI 0xAEFE
|
||||
#define MAX_NUM_ANTENNAS 4
|
||||
#define XRAN_GET_MU_FROM_SECT_ID(sectId) (sectId/XRAN_MAX_SECTIONS_PER_SLOT)
|
||||
|
||||
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;
|
||||
|
||||
typedef struct {
|
||||
int section_id;
|
||||
int num_prb;
|
||||
int start_prb;
|
||||
} oran_pusch_cplane_config_t;
|
||||
|
||||
static oran_pusch_cplane_config_t pusch_config[MAX_NUM_ANTENNAS][20][14];
|
||||
|
||||
oran_prach_cplane_config_t prach_config_per_antenna[MAX_NUM_ANTENNAS] = {0};
|
||||
static uint8_t prach_seq_id[MAX_NUM_ANTENNAS] = {0};
|
||||
static _Atomic(uint8_t) pusch_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,
|
||||
§_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;
|
||||
}
|
||||
case XRAN_CP_SECTIONTYPE_1: {
|
||||
struct xran_cp_radioapp_section1_header *hdr = (struct xran_cp_radioapp_section1_header *)apphdr;
|
||||
struct xran_cp_radioapp_section1 *section = (void *)rte_pktmbuf_adj(pkt, sizeof(struct xran_cp_radioapp_section1_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));
|
||||
if (hdr->cmnhdr.field.dataDirection == XRAN_DIR_DL) {
|
||||
// For now skip DL
|
||||
return MBUF_FREE;
|
||||
}
|
||||
//int frame = hdr->cmnhdr.field.frameId;
|
||||
int section_id = section->hdr.u1.common.sectionId;
|
||||
int mu = XRAN_GET_MU_FROM_SECT_ID(section_id);
|
||||
int slot = hdr->cmnhdr.field.slotId + hdr->cmnhdr.field.subframeId * (1 << mu);
|
||||
uint32_t start_symbol = hdr->cmnhdr.field.startSymbolId;
|
||||
int startPrbc = section->hdr.u1.common.startPrbc;
|
||||
int numPrbc = section->hdr.u1.common.numPrbc;
|
||||
int num_symbols = section->hdr.u.s1.numSymbol;
|
||||
int aarx = xran_recv_packet_info.eaxc.ruPortId;
|
||||
if (start_symbol + num_symbols > 14) {
|
||||
LOG_W(HW, "Invalid symbol index >= 14 start_symbol %d num_symbols %d\n", start_symbol, num_symbols);
|
||||
}
|
||||
LOG_D(HW,
|
||||
"section_id %d mu %d slot %d frame %d startprb %d num_prb %d start_sym %u num_sym %d\n",
|
||||
section_id,
|
||||
mu,
|
||||
slot,
|
||||
hdr->cmnhdr.field.frameId,
|
||||
startPrbc,
|
||||
numPrbc,
|
||||
start_symbol,
|
||||
num_symbols);
|
||||
for (int symbol = start_symbol; symbol < start_symbol + num_symbols && symbol < 14; symbol++) {
|
||||
pusch_config[aarx][slot][symbol].section_id = section_id;
|
||||
pusch_config[aarx][slot][symbol].start_prb = startPrbc;
|
||||
pusch_config[aarx][slot][symbol].num_prb = numPrbc;
|
||||
}
|
||||
return MBUF_FREE;
|
||||
}
|
||||
default:
|
||||
return MBUF_FREE;
|
||||
}
|
||||
}
|
||||
|
||||
static void *g_handle = NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
for (int aarx = 0; aarx < MAX_NUM_ANTENNAS; aarx++) {
|
||||
for (int slot = 0; slot < 20; slot++) {
|
||||
for (int symbol = 0; symbol < 14; symbol++) {
|
||||
pusch_config[aarx][slot][symbol].section_id = -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 + g_kbar] = (int16_t)htons(src[i]);
|
||||
}
|
||||
|
||||
int ret = xran_hook_send_packet(g_handle, mbuf, 0, XRAN_DIR_UL, aarx + fh_cfg->perMu[mu].prach_conf.prachEaxcOffset);
|
||||
AssertFatal(ret == 0, "Error sending mbuf\n");
|
||||
}
|
||||
|
||||
|
||||
void xran_oru_send_pusch(uint32_t *puschF, int aarx, int frame, int slot, int symbol)
|
||||
{
|
||||
const struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
|
||||
int section_id = pusch_config[aarx][slot][symbol].section_id;
|
||||
|
||||
if (section_id == -1) {
|
||||
RATE_LIMIT(1000)
|
||||
LOG_W(HW, "PUSCH was not yet configured by the O-DU\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t mu = fh_cfg->mu_number[0];
|
||||
const int num_ul_rbs = fh_cfg->perMu[mu].nULRBs;
|
||||
int num_prb = pusch_config[aarx][slot][symbol].num_prb;
|
||||
int start_prb = pusch_config[aarx][slot][symbol].start_prb;
|
||||
AssertFatal(num_prb == num_ul_rbs && start_prb == 0, "only support full bandwidth reception\n");
|
||||
|
||||
AssertFatal(fh_cfg->ru_conf.compMeth == 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;
|
||||
const uint num_sc = num_ul_rbs * NR_NB_SC_PER_RB;
|
||||
size_t data_len = sizeof(int32_t) * num_sc;
|
||||
|
||||
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, pusch_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, 0, 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, fh_cfg->perMu[mu].nULRBs, 0, section_id);
|
||||
|
||||
// TODO: O-DU expect compression header here even though the standard says it's not required
|
||||
struct data_section_compression_hdr *compression_header = (struct data_section_compression_hdr *)(data_section_header + 1);
|
||||
compression_header->ud_comp_hdr.ud_comp_meth = XRAN_COMPMETHOD_NONE;
|
||||
compression_header->ud_comp_hdr.ud_iq_width = XRAN_CONVERT_IQWIDTH(16);
|
||||
compression_header->rsrvd = 0;
|
||||
|
||||
int fftsize = 1 << fh_cfg->perMu[mu].nULFftSize;
|
||||
int first_carrier_offset = fftsize - (fh_cfg->perMu[mu].nULRBs * NR_NB_SC_PER_RB / 2);
|
||||
int num_sc_first_copy = (fftsize - first_carrier_offset);
|
||||
int num_sc_second_copy = fh_cfg->perMu[mu].nULRBs * NR_NB_SC_PER_RB - num_sc_first_copy;
|
||||
void *iq_data_start = (void *)(compression_header + 1);
|
||||
int16_t* dest = (int16_t*)iq_data_start;
|
||||
uint16_t* src = (uint16_t*)&puschF[first_carrier_offset];
|
||||
for (int i = 0; i < num_sc_first_copy * 2; i++) {
|
||||
*dest++ = (int16_t)htons(src[i]);
|
||||
}
|
||||
src = (uint16_t*)puschF;
|
||||
for (int i = 0; i < num_sc_second_copy * 2; i++) {
|
||||
*dest++ = (int16_t)htons(src[i]);
|
||||
}
|
||||
|
||||
int ret = xran_hook_send_packet(g_handle, mbuf, 0, XRAN_DIR_UL, aarx);
|
||||
AssertFatal(ret == 0, "Error sending mbuf\n");
|
||||
}
|
||||
|
||||
void stop_oru(void) {
|
||||
if (g_handle)
|
||||
iq_worker_destroy();
|
||||
}
|
||||
41
radio/fhi_72/oaioran_ru.h
Normal file
41
radio/fhi_72/oaioran_ru.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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);
|
||||
void xran_oru_send_pusch(uint32_t *puschF, int aarx, int frame, int slot, int symbol);
|
||||
|
||||
#endif
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
53
radio/fhi_72/oran_debug.c
Normal 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
29
radio/fhi_72/oran_debug.h
Normal 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
|
||||
@@ -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,9 @@ __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;
|
||||
device->xran_api.write_pusch = xran_oru_send_pusch;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -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, ×tamp)) {
|
||||
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, ¤t_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];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user