From 984b917e59250fa904e7efcf2017a796a58634d2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 13 Jan 2025 11:30:47 +0100 Subject: [PATCH 01/10] FHI72: Remove unused defines and comments --- radio/fhi_72/oaioran.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index b7cce2964b..136bd89ca3 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -43,21 +43,6 @@ volatile uint8_t first_call_set = 0; volatile uint8_t first_rx_set = 0; volatile int first_read_set = 0; -// Variable declaration useful for fill IQ samples from file -#define IQ_PLAYBACK_BUFFER_BYTES (XRAN_NUM_OF_SLOT_IN_TDD_LOOP * N_SYM_PER_SLOT * XRAN_MAX_PRBS * N_SC_PER_PRB * 4L) -/* -int rx_tti; -int rx_sym; -volatile uint32_t rx_cb_tti = 0; -volatile uint32_t rx_cb_frame = 0; -volatile uint32_t rx_cb_subframe = 0; -volatile uint32_t rx_cb_slot = 0; -*/ - -#define GetFrameNum(tti, SFNatSecStart, numSubFramePerSystemFrame, numSlotPerSubFrame) \ - ((((uint32_t)tti / ((uint32_t)numSubFramePerSystemFrame * (uint32_t)numSlotPerSubFrame)) + SFNatSecStart) & 0x3FF) -#define GetSlotNum(tti, numSlotPerSfn) ((uint32_t)tti % ((uint32_t)numSlotPerSfn)) - int xran_is_prach_slot(uint8_t PortId, uint32_t subframe_id, uint32_t slot_id); #include "common/utils/LOG/log.h" From 2cd0bba9c455269ce057410ef94d012fd2f1e285 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 13 Jan 2025 11:36:04 +0100 Subject: [PATCH 02/10] notified_fifo: include malloc.h for memalign() --- common/utils/threadPool/notified_fifo.h | 1 + 1 file changed, 1 insertion(+) diff --git a/common/utils/threadPool/notified_fifo.h b/common/utils/threadPool/notified_fifo.h index c845c40b56..2a27f82936 100644 --- a/common/utils/threadPool/notified_fifo.h +++ b/common/utils/threadPool/notified_fifo.h @@ -23,6 +23,7 @@ #define NOTIFIED_FIFO_H #include "pthread_utils.h" #include +#include #include #include "time_meas.h" #include From 0e5bc42e3ef97226b581c50f464eab6b14361d97 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 13 Jan 2025 11:31:41 +0100 Subject: [PATCH 03/10] FHI72: no poll: use pullNotifiedFIFO(), cleanup code, make compile Move the extern definition to the header, to avoid type errors. --- radio/fhi_72/oaioran.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index 136bd89ca3..ef8e81dbc5 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -37,6 +37,8 @@ #include "oran-config.h" // for g_kbar +#include "common/utils/threadPool/notified_fifo.h" + #define USE_POLLING 1 // Declare variable useful for the send buffer function volatile uint8_t first_call_set = 0; @@ -130,19 +132,17 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) if (last_slot == -1 || slot2 != last_slot) { #ifndef USE_POLLING notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(oran_sync_info_t), 0, &oran_sync_fifo, NULL); - oran_sync_info_t *info = (oran_sync_info_t *)NotifiedFifoData(req); + oran_sync_info_t *info = NotifiedFifoData(req); + info->tti = tti; info->sl = slot2; info->f = frame; LOG_D(PHY, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot); + pushNotifiedFIFO(&oran_sync_fifo, req); #else LOG_D(PHY, "Writing %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); oran_sync_info.tti = tti; oran_sync_info.sl = slot2; oran_sync_info.f = frame; -#endif -#ifndef USE_POLLING - pushNotifiedFIFO(&oran_sync_fifo, req); -#else #endif } else LOG_E(PHY, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); @@ -271,7 +271,6 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) void *ptr = NULL; int32_t *pos = NULL; int idx = 0; - static int last_slot = -1; first_read_set = 1; static int64_t old_rx_counter[XRAN_PORTS_NUM] = {0}; @@ -280,11 +279,8 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) static int outcnt = 0; #ifndef USE_POLLING // pull next even from oran_sync_fifo - notifiedFIFO_elt_t *res = pollNotifiedFIFO(&oran_sync_fifo); - while (res == NULL) { - res = pollNotifiedFIFO(&oran_sync_fifo); - } - oran_sync_info_t *info = (oran_sync_info_t *)NotifiedFifoData(res); + notifiedFIFO_elt_t *res = pullNotifiedFIFO(&oran_sync_fifo); + oran_sync_info_t *info = NotifiedFifoData(res); *slot = info->sl; *frame = info->f; @@ -298,6 +294,7 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) *frame = oran_sync_info.f; uint32_t tti_in = oran_sync_info.tti; + static int last_slot = -1; LOG_D(PHY, "oran slot %d, last_slot %d\n", *slot, last_slot); int cnt = 0; // while (*slot == last_slot) { From 540d918a09b5d3d7282c665c37eb920b7cc01fc4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 16 Jan 2025 13:22:23 +0100 Subject: [PATCH 04/10] Detect double sync message and skip frames --- radio/fhi_72/oaioran.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index ef8e81dbc5..034035b4bc 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -280,6 +280,16 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) #ifndef USE_POLLING // pull next even from oran_sync_fifo notifiedFIFO_elt_t *res = pullNotifiedFIFO(&oran_sync_fifo); + + notifiedFIFO_elt_t *f; + while ((f = pollNotifiedFIFO(&oran_sync_fifo)) != NULL) { + oran_sync_info_t *old_info = NotifiedFifoData(res); + oran_sync_info_t *new_info = NotifiedFifoData(f); + LOG_E(PHY, "Detected double 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); *slot = info->sl; From 99c849c2494d9e0259cd875be685828feb08e24a Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 13 Jan 2025 15:59:04 +0100 Subject: [PATCH 05/10] Refactor code to wait for free RX job Some radios (e.g., RFsim) can run faster. A mechanism has been put in place to keep RX/TX frame/slot numbers not too far from each other. Refactor in a separate function with documentation to make this clearer. --- executables/nr-ru.c | 72 +++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 8d240b72a3..3921f6ca60 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1084,6 +1084,48 @@ void ru_tx_func(void *param) }//else emulate_rf } +/* @brief wait for the next RX TTI to be free + * + * Certain radios, e.g., RFsim, can run faster than real-time. This might + * create problems, e.g., if RX and TX get too far from each other. This + * function ensures that a maximum of 4 RX slots are processed at a time (and + * not more than those four are started). + * + * Through the queue L1_rx_out, we are informed about completed RX jobs. + * rx_tti_busy keeps track of individual slots that have been started; this + * function blocks until the current frame/slot is completed, signaled through + * a message. + * + * @param L1_rx_out the queue from which to read completed RX jobs + * @param rx_tti_busy array to mark RX job completion + * @param frame_rx the frame to wait for + * @param slot_rx the slot to wait for + */ +static bool wait_free_rx_tti(notifiedFIFO_t *L1_rx_out, bool rx_tti_busy[RU_RX_SLOT_DEPTH], int frame_rx, int slot_rx) +{ + int idx = slot_rx % RU_RX_SLOT_DEPTH; + if (rx_tti_busy[idx]) { + bool not_done = true; + LOG_D(NR_PHY, "%d.%d Waiting to access RX slot %d\n", frame_rx, slot_rx, idx); + // block and wait for frame_rx/slot_rx free from previous slot processing. + // as we can get other slots, we loop on the queue + while (not_done) { + notifiedFIFO_elt_t *res = pullNotifiedFIFO(L1_rx_out); + if (!res) + return false; + processingData_L1_t *info = NotifiedFifoData(res); + LOG_D(NR_PHY, "%d.%d Got access to RX slot %d.%d (%d)\n", frame_rx, slot_rx, info->frame_rx, info->slot_rx, idx); + rx_tti_busy[info->slot_rx % RU_RX_SLOT_DEPTH] = false; + if ((info->slot_rx % RU_RX_SLOT_DEPTH) == idx) + not_done = false; + delNotifiedFIFO_elt(res); + } + } + // set the tti to busy: the caller will process this slot now + rx_tti_busy[idx] = true; + return true; +} + void *ru_thread(void *param) { static int ru_thread_status; @@ -1250,34 +1292,8 @@ void *ru_thread(void *param) int slot_type = nr_slot_select(&ru->config, proc->frame_rx, proc->tti_rx); if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) { if (ru->feprx) { - if (rx_tti_busy[proc->tti_rx % RU_RX_SLOT_DEPTH]) { - bool not_done = true; - LOG_D(NR_PHY, "%d.%d Waiting to access RX slot %d\n", proc->frame_rx, proc->tti_rx, proc->tti_rx % RU_RX_SLOT_DEPTH); - // now we block and wait our slot memory zone is freed from previous slot processing - // as we can get other slots ending, we loop on the queue - notifiedFIFO_elt_t *res = NULL; - while (not_done) { - res = pullNotifiedFIFO(&gNB->L1_rx_out); - if (!res) - break; - processingData_L1_t *info = (processingData_L1_t *)NotifiedFifoData(res); - LOG_D(NR_PHY, - "%d.%d Got access to RX slot %d.%d (%d)\n", - proc->frame_rx, - proc->tti_rx, - info->frame_rx, - info->slot_rx, - proc->tti_rx % RU_RX_SLOT_DEPTH); - rx_tti_busy[info->slot_rx % RU_RX_SLOT_DEPTH] = false; - if ((info->slot_rx % RU_RX_SLOT_DEPTH) == (proc->tti_rx % RU_RX_SLOT_DEPTH)) - not_done = false; - delNotifiedFIFO_elt(res); - } - if (!res) - break; - } - // set the tti that was generated to busy - rx_tti_busy[proc->tti_rx % RU_RX_SLOT_DEPTH] = true; + if (!wait_free_rx_tti(&gNB->L1_rx_out, rx_tti_busy, proc->frame_rx, proc->tti_rx)) + break; // nothing to wait for: we have to stop ru->feprx(ru,proc->tti_rx); LOG_D(NR_PHY, "Setting %d.%d (%d) to busy\n", proc->frame_rx, proc->tti_rx, proc->tti_rx % RU_RX_SLOT_DEPTH); //LOG_M("rxdata.m","rxs",ru->common.rxdata[0],1228800,1,1); From 595a80a3f7fd152899d3a30fadeb20469fa3520d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 13 Jan 2025 16:00:04 +0100 Subject: [PATCH 06/10] Remove FHI72 memory workaround The queue L1_rx_out was in place to keep RX/TX processing relatively "close" to each other (in terms of time, since in RFsim, they might advance faster than realtime; see also parent commit). This lead to a memory leak in radios that do not use ru->feprx (no front-end processing for RX, e.g., PRACH), as the code to read the L1_rx_out messages was inside a block of if (ru->feprx). Move it out so that the queue is always read and messages are freed to eliminate the memory leak, and remove the workaround for FHI72 to avoid this memory leak. This also allows to run RFsim when compiling FHI72, which was not possible before this commit. Closes: #812 --- executables/nr-gnb.c | 2 -- executables/nr-ru.c | 8 ++------ radio/fhi_72/CMakeLists.txt | 3 --- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 0aa538c348..6acd649ab6 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -219,7 +219,6 @@ static void rx_func(processingData_L1_t *info) gNB->if_inst->NR_UL_indication(&UL_INFO); stop_meas(&gNB->ul_indication_stats); -#ifndef OAI_FHI72 notifiedFIFO_elt_t *res = newNotifiedFIFO_elt(sizeof(processingData_L1_t), 0, &gNB->L1_rx_out, NULL); processingData_L1_t *syncMsg = NotifiedFifoData(res); syncMsg->gNB = gNB; @@ -228,7 +227,6 @@ static void rx_func(processingData_L1_t *info) res->key = slot_rx; LOG_D(NR_PHY, "Signaling completion for %d.%d (mod_slot %d) on L1_rx_out\n", frame_rx, slot_rx, slot_rx % RU_RX_SLOT_DEPTH); pushNotifiedFIFO(&gNB->L1_rx_out, res); -#endif } } diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 3921f6ca60..f3311ecb65 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1139,9 +1139,7 @@ void *ru_thread(void *param) char threadname[40]; int initial_wait = 0; -#ifndef OAI_FHI72 bool rx_tti_busy[RU_RX_SLOT_DEPTH] = {false}; -#endif // set default return value ru_thread_status = 0; // set default return value @@ -1287,13 +1285,12 @@ void *ru_thread(void *param) if (ru->idx != 0) proc->frame_tx = (proc->frame_tx + proc->frame_offset) & 1023; -#ifndef OAI_FHI72 // do RX front-end processing (frequency-shift, dft) if needed int slot_type = nr_slot_select(&ru->config, proc->frame_rx, proc->tti_rx); if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) { + if (!wait_free_rx_tti(&gNB->L1_rx_out, rx_tti_busy, proc->frame_rx, proc->tti_rx)) + break; // nothing to wait for: we have to stop if (ru->feprx) { - if (!wait_free_rx_tti(&gNB->L1_rx_out, rx_tti_busy, proc->frame_rx, proc->tti_rx)) - break; // nothing to wait for: we have to stop ru->feprx(ru,proc->tti_rx); LOG_D(NR_PHY, "Setting %d.%d (%d) to busy\n", proc->frame_rx, proc->tti_rx, proc->tti_rx % RU_RX_SLOT_DEPTH); //LOG_M("rxdata.m","rxs",ru->common.rxdata[0],1228800,1,1); @@ -1331,7 +1328,6 @@ void *ru_thread(void *param) } // end if (prach_id > 0) } // end if (ru->feprx) } // end if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) { -#endif notifiedFIFO_elt_t *resTx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t), 0, &gNB->L1_tx_out, NULL); processingData_L1tx_t *syncMsgTx = NotifiedFifoData(resTx); diff --git a/radio/fhi_72/CMakeLists.txt b/radio/fhi_72/CMakeLists.txt index 00f7ef97e0..4068b285d8 100644 --- a/radio/fhi_72/CMakeLists.txt +++ b/radio/fhi_72/CMakeLists.txt @@ -43,6 +43,3 @@ set_target_properties(oran_fhlib_5g PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_ add_custom_command(TARGET oran_fhlib_5g POST_BUILD COMMAND ${CMAKE_COMMAND} -E create_symlink liboran_fhlib_5g.so liboai_transpro.so WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) - -message(STATUS "Temporary added -DOAI_FHI72") -target_compile_definitions(nr-softmodem PUBLIC OAI_FHI72) From fd773068068821e0f3bcaef2cfdb8b82815d8ce8 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 13 Jan 2025 12:13:48 +0100 Subject: [PATCH 07/10] FHI72: make polling configurable in xran_fh_rx_read_slot(), default off xran_fh_rx_read_slot() uses polling (a loop over cnt++) to wait for the next frame/slot. The reasons I have been told is "it does not work differently", or "there are real-time problems". None of those seem to be true; by default disable polling, and use the queue instead. It is possible to enable polling with the cmake option OAI_FHI72_USE_POLLING=ON. Documentation has been updated to inform about this change. --- doc/ORAN_FHI7.2_Tutorial.md | 15 +++++++++++++++ radio/fhi_72/CMakeLists.txt | 2 ++ radio/fhi_72/oaioran.c | 5 ++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index 84ae6b2064..8e2058f5c1 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -475,6 +475,19 @@ cmake .. -GNinja -DOAI_FHI72=ON -Dxran_LOCATION=$HOME/phy/fhi_lib/lib ninja nr-softmodem oran_fhlib_5g params_libconfig ``` +Note that in tags 2025.w06 and prior, the FHI72 driver used polling to wait for +the next slot. This is inefficient as it burns CPU time, and has been replaced +with a more efficient mechanism. Nevertheless, if you experience problems that +did not occur previously, it is possible to re-enable polling, either with +`build_oai` like this + + ./build_oai --gNB --ninja -t oran_fhlib_5g --cmake-opt -Dxran_LOCATION=$HOME/phy/fhi_lib/lib --cmake-opt -DOAI_FHI72_USE_POLLING=ON + +or with `cmake` like so + + cmake .. -GNinja -DOAI_FHI72=ON -Dxran_LOCATION=$HOME/phy/fhi_lib/lib -DOAI_FHI72_USE_POLLING=ON + ninja oran_fhlib_5g + # Configuration RU and DU configurations have a circular dependency: you have to configure DU MAC address in the RU configuration and the RU MAC address, VLAN and Timing advance parameters in the DU configuration. @@ -1040,6 +1053,8 @@ In this case, you should reverify that `ptp4l` and `phc2sys` are working, e.g., do not do any jumps (during the last hour). While an occasional jump is not necessarily problematic for the gNB, many such messages mean that the system is not working, and UEs might not be able to attach or reach good performance. +Also, you can try to compile with polling (see [the build +section](.#build-oai-gnb)) to see if it resolves the problem. # Operation with multiple RUs diff --git a/radio/fhi_72/CMakeLists.txt b/radio/fhi_72/CMakeLists.txt index 4068b285d8..3fab4f5d47 100644 --- a/radio/fhi_72/CMakeLists.txt +++ b/radio/fhi_72/CMakeLists.txt @@ -39,6 +39,8 @@ target_link_libraries(oran_fhlib_5g PRIVATE ${T_LIB}) # TODO: can be removed? target_include_directories(oran_fhlib_5g PRIVATE ${xran_INCLUDE_DIRS}/../src/) +add_boolean_option(OAI_FHI72_USE_POLLING OFF "Enable polling in FHI72 driver" ON) + set_target_properties(oran_fhlib_5g PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) add_custom_command(TARGET oran_fhlib_5g POST_BUILD COMMAND ${CMAKE_COMMAND} -E create_symlink liboran_fhlib_5g.so liboai_transpro.so diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index 034035b4bc..f4368a481e 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -39,7 +39,10 @@ #include "common/utils/threadPool/notified_fifo.h" -#define USE_POLLING 1 +#if OAI_FHI72_USE_POLLING +#define USE_POLLING +#endif + // Declare variable useful for the send buffer function volatile uint8_t first_call_set = 0; volatile uint8_t first_rx_set = 0; From 042018451855000b171894334072f3d291d7f7a3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 31 Jan 2025 09:13:09 +0100 Subject: [PATCH 08/10] FHI72: cleanup: remove first_read_set first_read_set seems to have the function of making frame/slot time advance only if we started to read the samples in xran_fh_rx_read_slot(). I interpret that as "only advance the time if the gNB is reading from xran", which does not make sense to me, because xran advances the time anyway. Also, polling would not notice, and no-polling would simply warn about double messages. So the outcome is likely the same, whether first_read_set is set or not. I checked in multiple CI runs; it happens that first_read_set is always set already when oai_xran_fh_rx_callback() is called anyway. --- radio/fhi_72/oaioran.c | 60 ++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index f4368a481e..f7664df31a 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -46,7 +46,6 @@ // Declare variable useful for the send buffer function volatile uint8_t first_call_set = 0; volatile uint8_t first_rx_set = 0; -volatile int first_read_set = 0; int xran_is_prach_slot(uint8_t PortId, uint32_t subframe_id, uint32_t slot_id); #include "common/utils/LOG/log.h" @@ -116,42 +115,40 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) #endif if (first_call_set) { if (!first_rx_set) { - LOG_I(NR_PHY, "first_rx is set (num_ports %d), first_read_set %d\n", num_ports, first_read_set); + LOG_I(NR_PHY, "first_rx is set (num_ports %d)\n", num_ports); } first_rx_set = 1; - if (first_read_set == 1) { - slot2 = slot + (subframe * slots_per_subframe); - rx_RU[ru_id][slot2] = 1; - if (last_frame > 0 && frame > 0 - && ((slot2 > 0 && last_frame != frame) || (slot2 == 0 && last_frame != ((1024 + frame - 1) & 1023)))) - LOG_E(PHY, "Jump in frame counter last_frame %d => %d, slot %d\n", last_frame, frame, slot2); - for (int i = 0; i < num_ports; i++) { - if (rx_RU[i][slot2] == 0) - return; - } - for (int i = 0; i < num_ports; i++) - rx_RU[i][slot2] = 0; + slot2 = slot + (subframe * slots_per_subframe); + rx_RU[ru_id][slot2] = 1; + if (last_frame > 0 && frame > 0 + && ((slot2 > 0 && last_frame != frame) || (slot2 == 0 && last_frame != ((1024 + frame - 1) & 1023)))) + LOG_E(PHY, "Jump in frame counter last_frame %d => %d, slot %d\n", last_frame, frame, slot2); + for (int i = 0; i < num_ports; i++) { + if (rx_RU[i][slot2] == 0) + return; + } + for (int i = 0; i < num_ports; i++) + rx_RU[i][slot2] = 0; - if (last_slot == -1 || slot2 != last_slot) { + if (last_slot == -1 || slot2 != last_slot) { #ifndef USE_POLLING - notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(oran_sync_info_t), 0, &oran_sync_fifo, NULL); - oran_sync_info_t *info = NotifiedFifoData(req); - info->tti = tti; - info->sl = slot2; - info->f = frame; - LOG_D(PHY, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot); - pushNotifiedFIFO(&oran_sync_fifo, req); + notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(oran_sync_info_t), 0, &oran_sync_fifo, NULL); + oran_sync_info_t *info = NotifiedFifoData(req); + info->tti = tti; + info->sl = slot2; + info->f = frame; + LOG_D(PHY, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot); + pushNotifiedFIFO(&oran_sync_fifo, req); #else - LOG_D(PHY, "Writing %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); - oran_sync_info.tti = tti; - oran_sync_info.sl = slot2; - oran_sync_info.f = frame; + LOG_D(PHY, "Writing %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); + oran_sync_info.tti = tti; + oran_sync_info.sl = slot2; + oran_sync_info.f = frame; #endif - } else - LOG_E(PHY, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); - last_slot = slot2; - last_frame = frame; - } // first_read_set == 1 + } else + LOG_E(PHY, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); + last_slot = slot2; + last_frame = frame; } // first_call_set } // rx_sym == 7 } @@ -274,7 +271,6 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) void *ptr = NULL; int32_t *pos = NULL; int idx = 0; - first_read_set = 1; static int64_t old_rx_counter[XRAN_PORTS_NUM] = {0}; static int64_t old_tx_counter[XRAN_PORTS_NUM] = {0}; From 6706c9390d6a33d4bdfcfe5ac4950ca0f073897f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 31 Jan 2025 09:26:41 +0100 Subject: [PATCH 09/10] FHI72: Cleanup: Remove first_rx_set first_rx_set is polling-specific: it makes the polling loop wait to only check the frame/slot counter once we set it for the first time. However, that is equivalent to checking the frame/slot directly, which will also be 0 in the beginning. --- radio/fhi_72/oaioran.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index f7664df31a..cbcc7346bf 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -45,7 +45,6 @@ // Declare variable useful for the send buffer function volatile uint8_t first_call_set = 0; -volatile uint8_t first_rx_set = 0; int xran_is_prach_slot(uint8_t PortId, uint32_t subframe_id, uint32_t slot_id); #include "common/utils/LOG/log.h" @@ -53,7 +52,7 @@ int xran_is_prach_slot(uint8_t PortId, uint32_t subframe_id, uint32_t slot_id); #ifndef USE_POLLING extern notifiedFIFO_t oran_sync_fifo; #else -volatile oran_sync_info_t oran_sync_info; +volatile oran_sync_info_t oran_sync_info = {0}; #endif void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) { @@ -114,10 +113,6 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) } #endif if (first_call_set) { - if (!first_rx_set) { - LOG_I(NR_PHY, "first_rx is set (num_ports %d)\n", num_ports); - } - first_rx_set = 1; slot2 = slot + (subframe * slots_per_subframe); rx_RU[ru_id][slot2] = 1; if (last_frame > 0 && frame > 0 @@ -295,10 +290,6 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) *frame = info->f; delNotifiedFIFO_elt(res); #else - LOG_D(PHY, "In xran_fh_rx_read_slot, first_rx_set %d\n", first_rx_set); - while (first_rx_set == 0) { - } - *slot = oran_sync_info.sl; *frame = oran_sync_info.f; uint32_t tti_in = oran_sync_info.tti; From e1d7306a43d3ca53065a919e835c685fe603c8da Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Feb 2025 10:43:03 +0100 Subject: [PATCH 10/10] Reduce indentation, add comment Reduce one level of indentation, and explain why we wait for physide_dl_tti callback. --- radio/fhi_72/oaioran.c | 61 ++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index cbcc7346bf..65839fd5a0 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -112,39 +112,42 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) } } #endif - if (first_call_set) { - slot2 = slot + (subframe * slots_per_subframe); - rx_RU[ru_id][slot2] = 1; - if (last_frame > 0 && frame > 0 - && ((slot2 > 0 && last_frame != frame) || (slot2 == 0 && last_frame != ((1024 + frame - 1) & 1023)))) - LOG_E(PHY, "Jump in frame counter last_frame %d => %d, slot %d\n", last_frame, frame, slot2); - for (int i = 0; i < num_ports; i++) { - if (rx_RU[i][slot2] == 0) - return; - } - for (int i = 0; i < num_ports; i++) - rx_RU[i][slot2] = 0; + // if 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; + slot2 = slot + (subframe * slots_per_subframe); + rx_RU[ru_id][slot2] = 1; + if (last_frame > 0 && frame > 0 + && ((slot2 > 0 && last_frame != frame) || (slot2 == 0 && last_frame != ((1024 + frame - 1) & 1023)))) + LOG_E(PHY, "Jump in frame counter last_frame %d => %d, slot %d\n", last_frame, frame, slot2); + for (int i = 0; i < num_ports; i++) { + if (rx_RU[i][slot2] == 0) + return; + } + for (int i = 0; i < num_ports; i++) + rx_RU[i][slot2] = 0; - if (last_slot == -1 || slot2 != last_slot) { + if (last_slot == -1 || slot2 != last_slot) { #ifndef USE_POLLING - notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(oran_sync_info_t), 0, &oran_sync_fifo, NULL); - oran_sync_info_t *info = NotifiedFifoData(req); - info->tti = tti; - info->sl = slot2; - info->f = frame; - LOG_D(PHY, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot); - pushNotifiedFIFO(&oran_sync_fifo, req); + notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(oran_sync_info_t), 0, &oran_sync_fifo, NULL); + oran_sync_info_t *info = NotifiedFifoData(req); + info->tti = tti; + info->sl = slot2; + info->f = frame; + LOG_D(PHY, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot); + pushNotifiedFIFO(&oran_sync_fifo, req); #else - LOG_D(PHY, "Writing %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); - oran_sync_info.tti = tti; - oran_sync_info.sl = slot2; - oran_sync_info.f = frame; + LOG_D(PHY, "Writing %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); + oran_sync_info.tti = tti; + oran_sync_info.sl = slot2; + oran_sync_info.f = frame; #endif - } else - LOG_E(PHY, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); - last_slot = slot2; - last_frame = frame; - } // first_call_set + } else + LOG_E(PHY, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); + last_slot = slot2; + last_frame = frame; } // rx_sym == 7 } void oai_xran_fh_srs_callback(void *pCallbackTag, xran_status_t status)