From daeb110ae1e418996d41415c9785987779e1e750 Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Fri, 15 Nov 2024 14:14:17 -0500 Subject: [PATCH 01/83] Don't reset txdata buffer every slot This is not necessary becuase the buffer would be overwritten by OFDM modulator in the next frame. --- executables/nr-ue.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index bd64a9d361..530c2ba103 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -473,9 +473,6 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action) int tmp = openair0_write_reorder(&UE->rfdevice, proc->timestamp_tx, txp, rxtxD->writeBlockSize, fp->nb_antennas_tx, flags); AssertFatal(tmp == rxtxD->writeBlockSize, ""); - - for (int i = 0; i < fp->nb_antennas_tx; i++) - memset(txp[i], 0, rxtxD->writeBlockSize); } void processSlotTX(void *arg) From 3e3ef8cfd0cafcd11dd181d8b34d9b64422bffdb Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Fri, 15 Nov 2024 14:16:32 -0500 Subject: [PATCH 02/83] Enable usrp-tx-thread-config in UE Setting this option will start a separate thread for writing samples to USRP. --- executables/nr-ue.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 530c2ba103..e2aec679db 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -802,6 +802,8 @@ void *UE_thread(void *arg) UE->is_synchronized = 0; int tmp2 = UE->rfdevice.trx_start_func(&UE->rfdevice); AssertFatal(tmp2 == 0, "Could not start the device\n"); + if (usrp_tx_thread == 1) + UE->rfdevice.trx_write_init(&UE->rfdevice); notifiedFIFO_t nf; initNotifiedFIFO(&nf); From 9f03fde60295212c8b79d75c3d34648a3b61c418 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Fri, 6 Dec 2024 11:16:48 +0100 Subject: [PATCH 03/83] Fix several issues in ulsch_mmse_2layers Fix incorrect array type of determ_fin which was set to int32_t while the array holds the results of simde_mm_abs_epi32 which produces unsigned values. Remove assert on right-shifting negative integers as it is impossible for determ_fin to hold negative values. Change type of sum_det to uint32_t to prevent possible overflow. Fix the type cast (int -> uint32_t) to prevent casting before shift in nr_ulsch_comp_muli_sum which might have resulted in right shifting negative integers. --- .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 6a57c1eafe..1ab6a8200d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -351,7 +351,7 @@ static void nr_ulsch_det_HhH (int32_t *after_mf_00,//a int32_t *after_mf_01,//b int32_t *after_mf_10,//c int32_t *after_mf_11,//d - int32_t *det_fin,//1/ad-bc + uint32_t *det_fin,//1/ad-bc unsigned short nb_rb, unsigned char symbol, int32_t shift) @@ -493,11 +493,10 @@ static simde__m128i nr_ulsch_comp_muli_sum(simde__m128i input_x, //print_ints("rx_re:",(int32_t*)&xy_re_128[0]); //print_ints("rx_Img:",(int32_t*)&xy_im_128[0]); //divide by matrix det and convert back to Q15 before packing - int sum_det =0; - for (int k=0; k<4;k++) { - sum_det += ((((int *)&det)[k])>>2); - //printf("det_%d = %d log2 =%d \n",k,(((int *)&det[0])[k]),log2_approx(((int *)&det[0])[k])); - } + uint32_t sum_det = 0; + for (int k = 0; k < 4; k++) { + sum_det += (((uint32_t *)&det)[k]) >> 2; + } int b = log2_approx(sum_det) - 8; if (b > 0) { @@ -680,7 +679,7 @@ static uint8_t nr_ulsch_mmse_2layers(NR_DL_FRAME_PARMS *frame_parms, int32_t af_mf_01[12*nb_rb] __attribute__((aligned(32))); int32_t af_mf_10[12*nb_rb] __attribute__((aligned(32))); int32_t af_mf_11[12*nb_rb] __attribute__((aligned(32))); - int32_t determ_fin[12*nb_rb] __attribute__((aligned(32))); + uint32_t determ_fin[12*nb_rb] __attribute__((aligned(32))); switch (n_rx) { case 2:// @@ -945,11 +944,9 @@ static uint8_t nr_ulsch_mmse_2layers(NR_DL_FRAME_PARMS *frame_parms, // Magnitude computation if (mod_order > 2) { - - int sum_det = 0; + uint32_t sum_det = 0; for (int k = 0; k < 4; k++) { - AssertFatal(((int *)&determ_fin_128[0])[k] > 0 ,"Right shifting negative values is UB" ); - sum_det += ((((uint32_t *)&determ_fin_128[0])[k]) >> 2); + sum_det += (((uint32_t *)&determ_fin_128[0])[k]) >> 2; } int b = log2_approx(sum_det) - 8; From 01abee2bafb5e772011adde96e42ea782872012f Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 9 Dec 2024 11:29:25 +0100 Subject: [PATCH 04/83] Reduce rounding error in rshift of sum_det - Use a uint64_t - move shift after the sum - add bias before shifting to reduce rounding error --- openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 1ab6a8200d..fb367bc116 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -493,10 +493,12 @@ static simde__m128i nr_ulsch_comp_muli_sum(simde__m128i input_x, //print_ints("rx_re:",(int32_t*)&xy_re_128[0]); //print_ints("rx_Img:",(int32_t*)&xy_im_128[0]); //divide by matrix det and convert back to Q15 before packing - uint32_t sum_det = 0; + uint64_t sum_det = 0; for (int k = 0; k < 4; k++) { - sum_det += (((uint32_t *)&det)[k]) >> 2; + sum_det += (((uint32_t *)&det)[k]); } + // Add bias to reduce rounding error + sum_det = (sum_det + 2) >> 2; int b = log2_approx(sum_det) - 8; if (b > 0) { @@ -944,10 +946,12 @@ static uint8_t nr_ulsch_mmse_2layers(NR_DL_FRAME_PARMS *frame_parms, // Magnitude computation if (mod_order > 2) { - uint32_t sum_det = 0; + uint64_t sum_det = 0; for (int k = 0; k < 4; k++) { - sum_det += (((uint32_t *)&determ_fin_128[0])[k]) >> 2; + sum_det += (((uint32_t *)&determ_fin_128[0])[k]); } + // Add bias to reduce rounding error + sum_det = (sum_det + 2) >> 2; int b = log2_approx(sum_det) - 8; if (b > 0) { From 5ac703b58039661a62af076590f5394fb7d02edf Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Thu, 28 Nov 2024 15:01:14 -0500 Subject: [PATCH 05/83] Code cleanup Add const to function input pointer. --- executables/nr-ue.c | 7 ++++--- openair1/SCHED_NR_UE/phy_frame_config_nr.h | 2 +- openair1/SCHED_NR_UE/phy_frame_config_nr_ue.c | 12 ++++++------ openair2/LAYER2/NR_MAC_UE/mac_proto.h | 2 +- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index e2882b4224..e883170438 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -443,6 +443,7 @@ static void UE_synch(void *arg) { static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action) { PHY_VARS_NR_UE *UE = rxtxD->UE; + const fapi_nr_config_request_t *cfg = &UE->nrUE_config; const UE_nr_rxtx_proc_t *proc = &rxtxD->proc; NR_DL_FRAME_PARMS *fp = &UE->frame_parms; @@ -466,10 +467,10 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action) flags = TX_BURST_START_AND_END; } else { int slots_frame = fp->slots_per_frame; - int curr_slot = nr_ue_slot_select(&UE->nrUE_config, slot); + int curr_slot = nr_ue_slot_select(cfg, slot); if (curr_slot != NR_DOWNLINK_SLOT) { - int next_slot = nr_ue_slot_select(&UE->nrUE_config, (slot + 1) % slots_frame); - int prev_slot = nr_ue_slot_select(&UE->nrUE_config, (slot + slots_frame - 1) % slots_frame); + int next_slot = nr_ue_slot_select(cfg, (slot + 1) % slots_frame); + int prev_slot = nr_ue_slot_select(cfg, (slot + slots_frame - 1) % slots_frame); if (prev_slot == NR_DOWNLINK_SLOT) flags = TX_BURST_START; else if (next_slot == NR_DOWNLINK_SLOT) diff --git a/openair1/SCHED_NR_UE/phy_frame_config_nr.h b/openair1/SCHED_NR_UE/phy_frame_config_nr.h index 59df0ba959..359722a7be 100644 --- a/openair1/SCHED_NR_UE/phy_frame_config_nr.h +++ b/openair1/SCHED_NR_UE/phy_frame_config_nr.h @@ -72,7 +72,7 @@ int slot_select_nr(NR_DL_FRAME_PARMS *frame_parms, int nr_frame, int nr_slot); * @param nr_slot : slot number @returns int : downlink, uplink or mixed slot type */ -int nr_ue_slot_select(fapi_nr_config_request_t *cfg, int nr_slot); +int nr_ue_slot_select(const fapi_nr_config_request_t *cfg, int nr_slot); /** \brief This function frees tdd configuration for nr * @param frame_parms NR DL Frame parameters diff --git a/openair1/SCHED_NR_UE/phy_frame_config_nr_ue.c b/openair1/SCHED_NR_UE/phy_frame_config_nr_ue.c index f2541d21b3..4fbe241223 100644 --- a/openair1/SCHED_NR_UE/phy_frame_config_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_frame_config_nr_ue.c @@ -39,7 +39,7 @@ * *********************************************************************/ -int nr_ue_slot_select(fapi_nr_config_request_t *cfg, int nr_slot) +int nr_ue_slot_select(const fapi_nr_config_request_t *cfg, int nr_slot) { if (cfg->cell_config.frame_duplex_type == FDD) return NR_UPLINK_SLOT | NR_DOWNLINK_SLOT; @@ -47,7 +47,7 @@ int nr_ue_slot_select(fapi_nr_config_request_t *cfg, int nr_slot) int period = cfg->tdd_table_1.tdd_period_in_slots + (cfg->tdd_table_2 ? cfg->tdd_table_2->tdd_period_in_slots : 0); int rel_slot = nr_slot % period; - fapi_nr_tdd_table_t *tdd_table = &cfg->tdd_table_1; + const fapi_nr_tdd_table_t *tdd_table = &cfg->tdd_table_1; if (cfg->tdd_table_2 && rel_slot >= tdd_table->tdd_period_in_slots) { rel_slot -= tdd_table->tdd_period_in_slots; tdd_table = cfg->tdd_table_2; @@ -56,7 +56,7 @@ int nr_ue_slot_select(fapi_nr_config_request_t *cfg, int nr_slot) if (tdd_table->max_tdd_periodicity_list == NULL) // this happens before receiving TDD configuration return NR_DOWNLINK_SLOT; - fapi_nr_max_tdd_periodicity_t *current_slot = &tdd_table->max_tdd_periodicity_list[rel_slot]; + const fapi_nr_max_tdd_periodicity_t *current_slot = &tdd_table->max_tdd_periodicity_list[rel_slot]; // if the 1st symbol is UL the whole slot is UL if (current_slot->max_num_of_symbol_per_slot_list[0].slot_config == 1) @@ -109,7 +109,7 @@ uint8_t sl_determine_if_sidelink_slot(uint8_t sl_startsym, uint8_t sl_lensym, ui * Mixed Slot is a sidelink slot if the uplink symbols in Mixed slot * overlaps with Sidelink start symbol and number of symbols. */ -int sl_nr_ue_slot_select(sl_nr_phy_config_request_t *cfg, int slot, uint8_t frame_duplex_type) +int sl_nr_ue_slot_select(const sl_nr_phy_config_request_t *cfg, int slot, uint8_t frame_duplex_type) { int ul_sym = 0, slot_type = 0; @@ -122,9 +122,9 @@ int sl_nr_ue_slot_select(sl_nr_phy_config_request_t *cfg, int slot, uint8_t fram int period = cfg->tdd_table.tdd_period_in_slots; int rel_slot = slot % period; - fapi_nr_tdd_table_t *tdd_table = &cfg->tdd_table; + const fapi_nr_tdd_table_t *tdd_table = &cfg->tdd_table; - fapi_nr_max_tdd_periodicity_t *current_slot = &tdd_table->max_tdd_periodicity_list[rel_slot]; + const fapi_nr_max_tdd_periodicity_t *current_slot = &tdd_table->max_tdd_periodicity_list[rel_slot]; for (int symbol_count = 0; symbol_count < NR_NUMBER_OF_SYMBOLS_PER_SLOT; symbol_count++) { if (current_slot->max_num_of_symbol_per_slot_list[symbol_count].slot_config == 1) { diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 094d1e5965..2f3acadeca 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -447,7 +447,7 @@ uint8_t sl_determine_sci_1a_len(uint16_t *num_subchannels, * @param nr_slot : slot number * @param frame duplex type : Frame type @returns int : 0 or Sidelink slot type */ -int sl_nr_ue_slot_select(sl_nr_phy_config_request_t *cfg, int nr_slot, uint8_t frame_duplex_type); +int sl_nr_ue_slot_select(const sl_nr_phy_config_request_t *cfg, int nr_slot, uint8_t frame_duplex_type); void nr_ue_sidelink_scheduler(nr_sidelink_indication_t *sl_ind, NR_UE_MAC_INST_t *mac); From 4f56bf903a29f90a5c822e5964ea9a14e9ee93b8 Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Sat, 30 Nov 2024 16:56:48 -0500 Subject: [PATCH 06/83] Helper function to get center frequency from point A. --- executables/nr-ue.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index e883170438..cbeecb990a 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -558,6 +558,13 @@ void processSlotTX(void *arg) TracyCZoneEnd(ctx); } +static uint64_t get_carrier_frequency(const int N_RB, const int mu, const uint32_t pointA_freq_khz) +{ + const uint64_t bw = (NR_NB_SC_PER_RB * N_RB) * MU_SCS(mu); + const uint64_t carrier_freq = (pointA_freq_khz + bw / 2) * 1000; + return carrier_freq; +} + static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, const UE_nr_rxtx_proc_t *proc, int *tx_wait_for_dlsch, @@ -584,10 +591,9 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, UE->target_Nid_cell = UE->synch_request.synch_req.target_Nid_cell; UE->target_Nid_cell = synch_req->target_Nid_cell; - uint64_t dl_bw = (12 * fp->N_RB_DL) * (15000 << fp->numerology_index); - uint64_t dl_CarrierFreq = (dl_bw >> 1) + (uint64_t)UE->nrUE_config.carrier_config.dl_frequency * 1000; - uint64_t ul_bw = (12 * fp->N_RB_UL) * (15000 << fp->numerology_index); - uint64_t ul_CarrierFreq = (ul_bw >> 1) + (uint64_t)UE->nrUE_config.carrier_config.uplink_frequency * 1000; + const fapi_nr_ue_carrier_config_t *cfg = &UE->nrUE_config.carrier_config; + uint64_t dl_CarrierFreq = get_carrier_frequency(fp->N_RB_DL, fp->numerology_index, cfg->dl_frequency); + uint64_t ul_CarrierFreq = get_carrier_frequency(fp->N_RB_UL, fp->numerology_index, cfg->uplink_frequency); if (dl_CarrierFreq != fp->dl_CarrierFreq || ul_CarrierFreq != fp->ul_CarrierFreq) { fp->dl_CarrierFreq = dl_CarrierFreq; fp->ul_CarrierFreq = ul_CarrierFreq; From e5814cd62e66ade8bedea3686d94b7677862f758 Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Sat, 30 Nov 2024 17:12:38 -0500 Subject: [PATCH 07/83] Handle sync request out of UE_dl_preprocessing() Move handling of sync request from MAC from UE_dl_preprocessing(). This will process the sync request before receiving the samples of current slot from radio so we don't 'lose' the slot. --- executables/nr-ue.c | 64 +++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index cbeecb990a..1dd1836fa7 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -565,6 +565,38 @@ static uint64_t get_carrier_frequency(const int N_RB, const int mu, const uint32 return carrier_freq; } +static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE) +{ + NR_DL_FRAME_PARMS *fp = &UE->frame_parms; + // Start synchronization with a target gNB + if (UE->synch_request.received_synch_request == 1) { + UE->is_synchronized = 0; + // if upper layers signal BW scan we do as instructed by command line parameter + // if upper layers disable BW scan we set it to false + if (UE->synch_request.synch_req.ssb_bw_scan) + UE->UE_scan_carrier = get_nrUE_params()->UE_scan_carrier; + else + UE->UE_scan_carrier = false; + UE->target_Nid_cell = UE->synch_request.synch_req.target_Nid_cell; + + const fapi_nr_ue_carrier_config_t *cfg = &UE->nrUE_config.carrier_config; + uint64_t dl_CarrierFreq = get_carrier_frequency(fp->N_RB_DL, fp->numerology_index, cfg->dl_frequency); + uint64_t ul_CarrierFreq = get_carrier_frequency(fp->N_RB_UL, fp->numerology_index, cfg->uplink_frequency); + if (dl_CarrierFreq != fp->dl_CarrierFreq || ul_CarrierFreq != fp->ul_CarrierFreq) { + fp->dl_CarrierFreq = dl_CarrierFreq; + fp->ul_CarrierFreq = ul_CarrierFreq; + nr_rf_card_config_freq(&openair0_cfg[UE->rf_map.card], ul_CarrierFreq, dl_CarrierFreq, 0); + UE->rfdevice.trx_set_freq_func(&UE->rfdevice, &openair0_cfg[0]); + init_symbol_rotation(fp); + } + + clean_UE_harq(UE); + UE->synch_request.received_synch_request = 0; + return 0; + } + return 1; +} + static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, const UE_nr_rxtx_proc_t *proc, int *tx_wait_for_dlsch, @@ -578,34 +610,6 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params; if (IS_SOFTMODEM_NOS1 || IS_SA_MODE(get_softmodem_params())) { - // Start synchronization with a target gNB - if (UE->synch_request.received_synch_request == 1) { - fapi_nr_synch_request_t *synch_req = &UE->synch_request.synch_req; - UE->is_synchronized = 0; - // if upper layers signal BW scan we do as instructed by command line parameter - // if upper layers disable BW scan we set it to false - if (UE->synch_request.synch_req.ssb_bw_scan) - UE->UE_scan_carrier = get_nrUE_params()->UE_scan_carrier; - else - UE->UE_scan_carrier = false; - UE->target_Nid_cell = UE->synch_request.synch_req.target_Nid_cell; - UE->target_Nid_cell = synch_req->target_Nid_cell; - - const fapi_nr_ue_carrier_config_t *cfg = &UE->nrUE_config.carrier_config; - uint64_t dl_CarrierFreq = get_carrier_frequency(fp->N_RB_DL, fp->numerology_index, cfg->dl_frequency); - uint64_t ul_CarrierFreq = get_carrier_frequency(fp->N_RB_UL, fp->numerology_index, cfg->uplink_frequency); - if (dl_CarrierFreq != fp->dl_CarrierFreq || ul_CarrierFreq != fp->ul_CarrierFreq) { - fp->dl_CarrierFreq = dl_CarrierFreq; - fp->ul_CarrierFreq = ul_CarrierFreq; - nr_rf_card_config_freq(&openair0_cfg[UE->rf_map.card], ul_CarrierFreq, dl_CarrierFreq, 0); - UE->rfdevice.trx_set_freq_func(&UE->rfdevice, &openair0_cfg[0]); - init_symbol_rotation(fp); - } - - clean_UE_harq(UE); - UE->synch_request.received_synch_request = 0; - } - /* send tick to RLC and PDCP every ms */ if (proc->nr_slot_rx % fp->slots_per_subframe == 0) { void nr_rlc_tick(int frame, int subframe); @@ -936,6 +940,10 @@ void *UE_thread(void *arg) continue; } + /* check if MAC has sent sync request */ + if (handle_sync_req_from_mac(UE) == 0) + continue; + // start of normal case, the UE is in sync absolute_slot++; TracyCFrameMark; From 73921dfa10496df718d5924cfad1e768f799ed87 Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Tue, 3 Dec 2024 10:47:30 -0500 Subject: [PATCH 08/83] Prevent race condition when sync req received Added a flush mechanism to actor thread. This is used to wait for all waiting jobs in the queue to be completed. --- common/utils/actor/actor.c | 14 +++++++++++++- common/utils/actor/actor.h | 5 +++++ executables/nr-ue.c | 9 ++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/common/utils/actor/actor.c b/common/utils/actor/actor.c index 68661ddb6d..de4022e40b 100644 --- a/common/utils/actor/actor.c +++ b/common/utils/actor/actor.c @@ -50,7 +50,8 @@ void *actor_thread(void *arg) break; } - elt->processingFunc(NotifiedFifoData(elt)); + if (elt->processingFunc) // processing function can be NULL + elt->processingFunc(NotifiedFifoData(elt)); if (elt->reponseFifo) { pushNotifiedFIFO(elt->reponseFifo, elt); } else @@ -85,3 +86,14 @@ void shutdown_actor(Actor_t *actor) abortNotifiedFIFO(&response_fifo); pthread_join(actor->thread, NULL); } + +void flush_actor(Actor_t *actor) +{ + notifiedFIFO_t response_fifo; + initNotifiedFIFO(&response_fifo); + notifiedFIFO_elt_t *elt = newNotifiedFIFO_elt(0, 0, &response_fifo, NULL); + pushNotifiedFIFO(&actor->fifo, elt); + elt = pullNotifiedFIFO(&response_fifo); + delNotifiedFIFO_elt(elt); + abortNotifiedFIFO(&response_fifo); +} diff --git a/common/utils/actor/actor.h b/common/utils/actor/actor.h index 474554c667..023533d2d7 100644 --- a/common/utils/actor/actor.h +++ b/common/utils/actor/actor.h @@ -49,4 +49,9 @@ void destroy_actor(Actor_t *actor); /// @param actor void shutdown_actor(Actor_t *actor); +/// @brief This function will return when all current jobs in the queue are finished. +/// The caller should make sure no new jobs are added to the queue between this function call and return. +/// @param actor +void flush_actor(Actor_t *actor); + #endif diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 1dd1836fa7..1c4fc33344 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -570,7 +570,6 @@ static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE) NR_DL_FRAME_PARMS *fp = &UE->frame_parms; // Start synchronization with a target gNB if (UE->synch_request.received_synch_request == 1) { - UE->is_synchronized = 0; // if upper layers signal BW scan we do as instructed by command line parameter // if upper layers disable BW scan we set it to false if (UE->synch_request.synch_req.ssb_bw_scan) @@ -590,7 +589,15 @@ static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE) init_symbol_rotation(fp); } + /* Clearing UE harq while DL actors are active causes race condition. + So we let the current execution to complete here.*/ + for (int i = 0; i < NUM_DL_ACTORS; i++) { + flush_actor(UE->dl_actors + i); + } + /*TODO: Flush UL jobs */ + clean_UE_harq(UE); + UE->is_synchronized = 0; UE->synch_request.received_synch_request = 0; return 0; } From 06c0374ec809a4793c3db1c23d0f1186fa78d009 Mon Sep 17 00:00:00 2001 From: Roberto Rosca Date: Mon, 2 Sep 2024 16:59:22 +0300 Subject: [PATCH 09/83] Added UE support for position coordinates taken from conf files --- CMakeLists.txt | 1 + executables/nr-ue.c | 2 ++ executables/position_interface.c | 33 +++++++++++++++++ executables/position_interface.h | 38 ++++++++++++++++++++ openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 8 +++-- targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf | 6 ++++ 6 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 executables/position_interface.c create mode 100644 executables/position_interface.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e6147ce3fb..681c727dfc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2079,6 +2079,7 @@ add_executable(nr-uesoftmodem ${rrc_h} ${s1ap_h} ${OPENAIR_DIR}/executables/nr-uesoftmodem.c + ${OPENAIR_DIR}/executables/position_interface.c ${OPENAIR_DIR}/executables/nr-ue.c ${OPENAIR_DIR}/executables/softmodem-common.c ${OPENAIR_DIR}/radio/COMMON/common_lib.c diff --git a/executables/nr-ue.c b/executables/nr-ue.c index e2882b4224..49deb85456 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -41,6 +41,7 @@ #include "PHY/MODULATION/nr_modulation.h" #include "instrumentation.h" #include "common/utils/threadPool/notified_fifo.h" +#include "position_interface.h" /* * NR SLOT PROCESSING SEQUENCE @@ -157,6 +158,7 @@ void init_nr_ue_vars(PHY_VARS_NR_UE *ue, uint8_t UE_id) ue->target_Nid_cell = -1; ue->timing_advance = ue->frame_parms.samples_per_subframe * get_nrUE_params()->ntn_ta_common; + check_position(UE_id); // initialize all signal buffers init_nr_ue_signal(ue, nb_connected_gNB); diff --git a/executables/position_interface.c b/executables/position_interface.c new file mode 100644 index 0000000000..3d6bbe3094 --- /dev/null +++ b/executables/position_interface.c @@ -0,0 +1,33 @@ +#include "position_interface.h" + +extern uint16_t NB_UE_INST; +static position_t **positionArray = 0; + +position_t *check_position(int Mod_id) +{ + AssertFatal(Mod_id < NB_UE_INST, "Mod_id must be less than NB_UE_INST. Mod_id:%d NB_UE_INST:%d", Mod_id, NB_UE_INST); + if (positionArray == NULL) { + positionArray = (position_t **)calloc(1, sizeof(position_t *) * NB_UE_INST); + } + if (!positionArray[Mod_id]) { + char positionName[64]; + sprintf(positionName, "position%d", Mod_id); + positionArray[Mod_id] = (void *)init_position(positionName); + } + return (position_t *)positionArray[Mod_id]; +} + +position_t *init_position(char *sectionName) +{ + position_t *position = (position_t *)calloc(sizeof(position_t), 1); + paramdef_t position_params[] = POSITION_CONFIG_PARAMS_DEF; + int ret = config_get(config_get_if(), position_params, sizeofArray(position_params), sectionName); + AssertFatal(ret >= 0, "configuration couldn't be performed for position name: %s", sectionName); + + return position; +} + +position_t *get_position(int Mod_id) +{ + return positionArray[Mod_id]; +} \ No newline at end of file diff --git a/executables/position_interface.h b/executables/position_interface.h new file mode 100644 index 0000000000..a645961f7e --- /dev/null +++ b/executables/position_interface.h @@ -0,0 +1,38 @@ +#ifndef __POSITION_INTERFACE__H__ +#define __POSITION_INTERFACE__H__ + +#include +#include +#include "PHY/defs_nr_UE.h" +#include "executables/nr-uesoftmodem.h" + +/* position configuration parameters name */ +#define CONFIG_STRING_POSITION_X "x" +#define CONFIG_STRING_POSITION_Y "y" +#define CONFIG_STRING_POSITION_Z "z" + +#define HELP_STRING_POSITION "Postion coordinates (x, y, z) config params" + +// Position parameters config +/*----------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* position configuration parameters */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*----------------------------------------------------------------------------------------------------------------------------------------------------*/ +// clang-format off +#define POSITION_CONFIG_PARAMS_DEF { \ + {CONFIG_STRING_POSITION_X, HELP_STRING_POSITION, 0, .dblptr=&(position->positionX), .defuintval=0, TYPE_DOUBLE, 0}, \ + {CONFIG_STRING_POSITION_Y, HELP_STRING_POSITION, 0, .dblptr=&(position->positionY), .defuintval=0, TYPE_DOUBLE, 0}, \ + {CONFIG_STRING_POSITION_Z, HELP_STRING_POSITION, 0, .dblptr=&(position->positionZ), .defuintval=0, TYPE_DOUBLE, 0} \ +} +// clang-format on + +typedef struct { + double positionX; + double positionY; + double positionZ; +} position_t; + +position_t *check_position(int Mod_id); +position_t *init_position(char *sectionName); +position_t *get_position(int Mod_id); +#endif \ No newline at end of file diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index 3eabec0249..dd98495fe0 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -41,10 +41,14 @@ #include #include "openair2/LAYER2/RLC/rlc.h" +#include "nr-uesoftmodem.h" + static double get_ta_Common_ms(NR_NTN_Config_r17_t *ntn_Config_r17) { - if (ntn_Config_r17 && ntn_Config_r17->ta_Info_r17) - return ntn_Config_r17->ta_Info_r17->ta_Common_r17 * 4.072e-6; // ta_Common_r17 is in units of 4.072e-3 µs + if (ntn_Config_r17 && ntn_Config_r17->ta_Info_r17) { + // ta_Common_r17 is in units of 4.072e-3 µs + return (ntn_Config_r17->ta_Info_r17->ta_Common_r17 * 4.072e-6 + get_nrUE_params()->ntn_ta_common) * 2; + } return 0.0; } diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf index 545b44f888..955b7b1253 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf @@ -6,3 +6,9 @@ dnn= "oai"; nssai_sst=1; nssai_sd=1; } + +position0 = { + x = 0.0; + y = 0.0; + z = 6371400.0; +} \ No newline at end of file From 698ff73c7f2e8baa2aa6f746091365d2c9e478fb Mon Sep 17 00:00:00 2001 From: Roberto Rosca Date: Mon, 16 Sep 2024 14:51:55 +0300 Subject: [PATCH 10/83] Added SIB19 related calculations on UE --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 40 ++++++++++++++++++++++---- openair2/LAYER2/NR_MAC_UE/main_ue_nr.c | 23 --------------- openair2/RRC/NR_UE/rrc_UE.c | 7 +++-- 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index b430727955..fb027c2083 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -31,6 +31,7 @@ */ #define _GNU_SOURCE +#define SPEED_OF_LIGHT 299792458 //#include "mac_defs.h" #include @@ -41,6 +42,7 @@ #include "executables/softmodem-common.h" #include "SCHED_NR/phy_frame_config_nr.h" #include "oai_asn1.h" +#include "executables/position_interface.h" void set_tdd_config_nr_ue(fapi_nr_tdd_table_t *tdd_table, int mu, @@ -1746,15 +1748,43 @@ void nr_rrc_mac_config_req_sib1(module_id_t module_id, AssertFatal(!ret, "mutex failed %d\n", ret); } -void nr_rrc_mac_config_req_sib19_r17(module_id_t module_id, - NR_SIB19_r17_t *sib19_r17) +// computes delay between ue and sat based on SIB19 ephemeris data +static double calculate_ue_sat_ta(position_t *position_params, struct NR_PositionVelocity_r17 *sat_pos) +{ + // get UE position coordinates + double posx = position_params->positionX; + double posy = position_params->positionY; + double posz = position_params->positionZ; + + // get sat position coordinates + double posx_0 = (double)sat_pos->positionX_r17 * 1.3; + double posy_0 = (double)sat_pos->positionY_r17 * 1.3; + double posz_0 = (double)sat_pos->positionZ_r17 * 1.3; + + double distance = sqrt(pow(posx - posx_0, 2) + pow(posy - posy_0, 2) + pow(posz - posz_0, 2)); + // this computation will ensure 3 decimal precision + double ta_ms = round(((distance / SPEED_OF_LIGHT) * 1000) * 1000.0) / 1000.0; + + return ta_ms; +} + +void nr_rrc_mac_config_req_sib19_r17(module_id_t module_id, NR_SIB19_r17_t *sib19_r17) { NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); - // ntn-Config-r17 - UPDATE_IE(mac->sc_info.ntn_Config_r17, sib19_r17->ntn_Config_r17, NR_NTN_Config_r17_t); + // ntn-Config-r17 deep copy into mac + asn_copy(&asn_DEF_NR_NTN_Config_r17, (void **)&mac->sc_info.ntn_Config_r17, sib19_r17->ntn_Config_r17); - // TODO handle other SIB19 elements + // if ephemerisInfo_r17 present in SIB19 + if (mac->sc_info.ntn_Config_r17->ephemerisInfo_r17 && mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17 + && (mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionX_r17 != 0 + || mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionY_r17 != 0 + || mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionZ_r17 != 0)) { + get_nrUE_params()->ntn_ta_common = + calculate_ue_sat_ta(get_position(module_id), mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17); + } + + get_nrUE_params()->ntn_koffset = *mac->sc_info.ntn_Config_r17->cellSpecificKoffset_r17; } static void handle_reconfiguration_with_sync(NR_UE_MAC_INST_t *mac, diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index 76dd88d07d..064fcc4e78 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -86,29 +86,6 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac) mac->pucch_power_control_initialized = false; mac->pusch_power_control_initialized = false; - - // Fake SIB19 reception for NTN - // TODO: remove this and implement the actual SIB19 reception instead! - if (get_nrUE_params()->ntn_koffset || get_nrUE_params()->ntn_ta_common || get_nrUE_params()->ntn_ta_commondrift) { - NR_SIB19_r17_t *sib19_r17 = calloc(1, sizeof(*sib19_r17)); - sib19_r17->ntn_Config_r17 = calloc(1, sizeof(*sib19_r17->ntn_Config_r17)); - - // NTN cellSpecificKoffset-r17 - if (get_nrUE_params()->ntn_koffset) { - asn1cCallocOne(sib19_r17->ntn_Config_r17->cellSpecificKoffset_r17, get_nrUE_params()->ntn_koffset); - } - - // NTN ta-Common-r17 - if (get_nrUE_params()->ntn_ta_common || get_nrUE_params()->ntn_ta_commondrift) { - sib19_r17->ntn_Config_r17->ta_Info_r17 = calloc(1, sizeof(*sib19_r17->ntn_Config_r17->ta_Info_r17)); - sib19_r17->ntn_Config_r17->ta_Info_r17->ta_Common_r17 = get_nrUE_params()->ntn_ta_common / 4.072e-6; // ta-Common-r17 is in units of 4.072e-3 µs, ntn_ta_common is in ms - if (get_nrUE_params()->ntn_ta_commondrift) - asn1cCallocOne(sib19_r17->ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17, get_nrUE_params()->ntn_ta_commondrift / 0.2e-3); // is in units of 0.2e-3 µs/s, ntn_ta_commondrift is in µs/s - } - - nr_rrc_mac_config_req_sib19_r17(mac->ue_id, sib19_r17); - asn1cFreeStruc(asn_DEF_NR_SIB19_r17, sib19_r17); - } } void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index b46da32374..70708625f7 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -165,7 +165,7 @@ static void set_DRB_status(NR_UE_RRC_INST_t *rrc, NR_DRB_Identity_t drb_id, NR_R rrc->status_DRBs[drb_id - 1] = status; } -static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si) +static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si, instance_t ue_id) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SI, VCD_FUNCTION_IN); @@ -241,6 +241,7 @@ static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si) SI_info->SInfo_r17.sib19_validity = true; if (g_log->log_component[NR_RRC].level >= OAILOG_DEBUG) xer_fprint(stdout, &asn_DEF_NR_SIB19_r17, (const void *)typeandinfo->choice.sib19_v1700); + nr_rrc_mac_config_req_sib19_r17(ue_id, typeandinfo->choice.sib19_v1700); nr_timer_start(&SI_info->SInfo_r17.sib19_timer); break; default: @@ -386,7 +387,7 @@ static void nr_rrc_process_reconfiguration_v1530(NR_UE_RRC_INST_t *rrc, NR_RRCRe SEQUENCE_free(&asn_DEF_NR_SystemInformation, si, 1); } else { LOG_I(NR_RRC, "[UE %ld] Decoding dedicatedSystemInformationDelivery\n", rrc->ue_id); - nr_decode_SI(SI_info, si); + nr_decode_SI(SI_info, si, rrc->ue_id); } } if (rec_1530->otherConfig) { @@ -895,7 +896,7 @@ static int8_t nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(NR_UE_RRC_INST_t *rrc, case NR_BCCH_DL_SCH_MessageType__c1_PR_systemInformation: LOG_I(NR_RRC, "[UE %ld] Decoding SI\n", rrc->ue_id); NR_SystemInformation_t *si = bcch_message->message.choice.c1->choice.systemInformation; - nr_decode_SI(SI_info, si); + nr_decode_SI(SI_info, si, rrc->ue_id); break; case NR_BCCH_DL_SCH_MessageType__c1_PR_NOTHING: default: From f88c47ba3ec561b16c8d7b9a211cb31516105e03 Mon Sep 17 00:00:00 2001 From: Roberto Rosca Date: Wed, 25 Sep 2024 09:28:04 +0300 Subject: [PATCH 11/83] Adding first layer timing advance - Added new structure to hold timing advance parameters - Made SIB19 related calculation to save to this struct - Modified in ra to get ta struct values --- executables/nr-ue.c | 2 +- openair2/LAYER2/NR_MAC_UE/config_ue.c | 13 ++++++++++--- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 9 +++++++++ openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 11 ++++------- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 49deb85456..993701fb11 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -156,7 +156,7 @@ void init_nr_ue_vars(PHY_VARS_NR_UE *ue, uint8_t UE_id) ue->if_inst = nr_ue_if_module_init(UE_id); ue->dci_thres = 0; ue->target_Nid_cell = -1; - ue->timing_advance = ue->frame_parms.samples_per_subframe * get_nrUE_params()->ntn_ta_common; + ue->timing_advance = ue->frame_parms.samples_per_subframe * 2 * get_nrUE_params()->ntn_ta_common; check_position(UE_id); // initialize all signal buffers diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index fb027c2083..7d9a1a40a1 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -1775,16 +1775,23 @@ void nr_rrc_mac_config_req_sib19_r17(module_id_t module_id, NR_SIB19_r17_t *sib1 // ntn-Config-r17 deep copy into mac asn_copy(&asn_DEF_NR_NTN_Config_r17, (void **)&mac->sc_info.ntn_Config_r17, sib19_r17->ntn_Config_r17); + // populate ntn_ta structure from mac // if ephemerisInfo_r17 present in SIB19 if (mac->sc_info.ntn_Config_r17->ephemerisInfo_r17 && mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17 && (mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionX_r17 != 0 || mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionY_r17 != 0 || mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionZ_r17 != 0)) { - get_nrUE_params()->ntn_ta_common = + mac->ntn_ta.N_UE_TA_adj = calculate_ue_sat_ta(get_position(module_id), mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17); } - - get_nrUE_params()->ntn_koffset = *mac->sc_info.ntn_Config_r17->cellSpecificKoffset_r17; + // if cellSpecificKoffset_r17 is present + if (sib19_r17->ntn_Config_r17->cellSpecificKoffset_r17) { + mac->ntn_ta.cell_specific_k_offset = *sib19_r17->ntn_Config_r17->cellSpecificKoffset_r17; + } + // Check if ta_Info_r17 is present and convert directly ta_Common_r17 (is in units of 4.072e-3 µs) + if (sib19_r17->ntn_Config_r17->ta_Info_r17) { + mac->ntn_ta.N_common_ta_adj = sib19_r17->ntn_Config_r17->ta_Info_r17->ta_Common_r17 * 4.072e-6; + } } static void handle_reconfiguration_with_sync(NR_UE_MAC_INST_t *mac, diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 51b9c29058..7c8f37175f 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -554,6 +554,13 @@ typedef struct { A_SEQUENCE_OF(si_schedinfo_config_t) si_SchedInfo_list; } si_schedInfo_t; +typedef struct ntn_timing_advance_components { +// N_common_ta_adj and N_UE_TA_adj are in ms +double N_common_ta_adj; +double N_UE_TA_adj; +long cell_specific_k_offset; +} ntn_timing_advance_componets_t; + /*!\brief Top level UE MAC structure */ typedef struct NR_UE_MAC_INST_s { module_id_t ue_id; @@ -623,6 +630,8 @@ typedef struct NR_UE_MAC_INST_s { int p_Max_alt; int n_ta_offset; // -1 not present, otherwise value to be applied + ntn_timing_advance_componets_t ntn_ta; + long pdsch_HARQ_ACK_Codebook; NR_Type0_PDCCH_CSS_config_t type0_PDCCH_CSS_config; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index dd98495fe0..98f1d7a9e8 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -40,16 +40,13 @@ #include #include "openair2/LAYER2/RLC/rlc.h" +#include "openair2/LAYER2/NR_MAC_UE/mac_defs.h" #include "nr-uesoftmodem.h" -static double get_ta_Common_ms(NR_NTN_Config_r17_t *ntn_Config_r17) +static double get_ta_Common_ms(const ntn_timing_advance_componets_t* ntn_ta) { - if (ntn_Config_r17 && ntn_Config_r17->ta_Info_r17) { - // ta_Common_r17 is in units of 4.072e-3 µs - return (ntn_Config_r17->ta_Info_r17->ta_Common_r17 * 4.072e-6 + get_nrUE_params()->ntn_ta_common) * 2; - } - return 0.0; + return (ntn_ta->N_common_ta_adj + ntn_ta->N_UE_TA_adj) * 2; } int16_t get_prach_tx_power(NR_UE_MAC_INST_t *mac) @@ -625,7 +622,7 @@ void nr_Msg3_transmitted(NR_UE_MAC_INST_t *mac, uint8_t CC_id, frame_t frameP, s { RA_config_t *ra = &mac->ra; NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon; - const double ta_Common_ms = get_ta_Common_ms(mac->sc_info.ntn_Config_r17); + const double ta_Common_ms = get_ta_Common_ms(&mac->ntn_ta); const int mu = mac->current_UL_BWP->scs; const int slots_per_ms = nr_slots_per_frame[mu] / 10; From 486f4f5f966c59187a7000b2215af8fbb7fedf62 Mon Sep 17 00:00:00 2001 From: Roberto Rosca Date: Thu, 26 Sep 2024 15:47:54 +0300 Subject: [PATCH 12/83] Adding second layer timing advance - Renamed position coordinates function (better readability) - Introduced large timing advance compensation mechanism --- executables/nr-ue.c | 44 ++++++++++++++++---- executables/position_interface.c | 9 ++-- executables/position_interface.h | 4 +- openair1/PHY/defs_nr_UE.h | 5 ++- openair2/LAYER2/NR_MAC_UE/config_ue.c | 10 +++-- openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 2 +- 6 files changed, 54 insertions(+), 20 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 993701fb11..7704d59a7d 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -43,6 +43,8 @@ #include "common/utils/threadPool/notified_fifo.h" #include "position_interface.h" +extern unsigned int NTN_UE_Koffset; + /* * NR SLOT PROCESSING SEQUENCE * @@ -156,9 +158,8 @@ void init_nr_ue_vars(PHY_VARS_NR_UE *ue, uint8_t UE_id) ue->if_inst = nr_ue_if_module_init(UE_id); ue->dci_thres = 0; ue->target_Nid_cell = -1; - ue->timing_advance = ue->frame_parms.samples_per_subframe * 2 * get_nrUE_params()->ntn_ta_common; - check_position(UE_id); + config_position_coordinates(UE_id); // initialize all signal buffers init_nr_ue_signal(ue, nb_connected_gNB); @@ -552,7 +553,7 @@ void processSlotTX(void *arg) int slots_per_frame = (UE->sl_mode == 2) ? UE->SL_UE_PHY_PARAMS.sl_frame_params.slots_per_frame : UE->frame_parms.slots_per_frame; - int next_slot = (proc->nr_slot_tx + 1) % slots_per_frame; + int next_slot = (proc->nr_slot_tx + 1 + proc->nr_slot_tx_offset) % slots_per_frame; dynamic_barrier_join(&UE->process_slot_tx_barriers[next_slot]); RU_write(rxtxD, sl_tx_action); free(rxtxD); @@ -827,7 +828,15 @@ void *UE_thread(void *arg) readFrame(UE, &tmp, true); } + double ntn_ta_common = (mac->ntn_ta.N_common_ta_adj + mac->ntn_ta.N_UE_TA_adj) * 2; + int ntn_koffset = mac->ntn_ta.cell_specific_k_offset; + + int duration_rx_to_tx = DURATION_RX_TO_TX; + int nr_slot_tx_offset = 0; + bool update_ntn_system_information = false; + while (!oai_exit) { + nr_slot_tx_offset = 0; if (syncRunning) { notifiedFIFO_elt_t *res = pollNotifiedFIFO(&nf); @@ -935,14 +944,31 @@ void *UE_thread(void *arg) absolute_slot++; TracyCFrameMark; + if (update_ntn_system_information) { + update_ntn_system_information = false; + int ta_offset = + UE->frame_parms.samples_per_subframe * 2 * (mac->ntn_ta.N_common_ta_adj + mac->ntn_ta.N_UE_TA_adj - ntn_ta_common); + + UE->timing_advance += ta_offset; + timing_advance = ntn_koffset * 7680; + ntn_ta_common = mac->ntn_ta.N_common_ta_adj + mac->ntn_ta.N_UE_TA_adj; + } + + if (ntn_koffset != mac->ntn_ta.cell_specific_k_offset && ntn_ta_common != mac->ntn_ta.N_common_ta_adj) { + ntn_koffset = mac->ntn_ta.cell_specific_k_offset; + NTN_UE_Koffset = ntn_koffset; + update_ntn_system_information = true; + nr_slot_tx_offset = mac->ntn_ta.cell_specific_k_offset % nb_slot_frame; + } + int slot_nr = absolute_slot % nb_slot_frame; nr_rxtx_thread_data_t curMsg = {0}; curMsg.UE=UE; // update thread index for received subframe curMsg.proc.nr_slot_rx = slot_nr; - curMsg.proc.nr_slot_tx = (absolute_slot + DURATION_RX_TO_TX) % nb_slot_frame; + curMsg.proc.nr_slot_tx = (absolute_slot + duration_rx_to_tx) % nb_slot_frame; curMsg.proc.frame_rx = (absolute_slot / nb_slot_frame) % MAX_FRAME_NUMBER; - curMsg.proc.frame_tx = ((absolute_slot + DURATION_RX_TO_TX) / nb_slot_frame) % MAX_FRAME_NUMBER; + curMsg.proc.frame_tx = ((absolute_slot + duration_rx_to_tx) / nb_slot_frame) % MAX_FRAME_NUMBER; if (UE->received_config_request) { if (UE->sl_mode) { curMsg.proc.rx_slot_type = sl_nr_ue_slot_select(sl_cfg, curMsg.proc.nr_slot_rx, TDD); @@ -995,11 +1021,11 @@ void *UE_thread(void *arg) } // use previous timing_advance value to compute writeTimestamp - const openair0_timestamp writeTimestamp = rx_timestamp + fp->get_samples_slot_timestamp(slot_nr, fp, DURATION_RX_TO_TX) + const openair0_timestamp writeTimestamp = rx_timestamp + fp->get_samples_slot_timestamp(slot_nr, fp, duration_rx_to_tx) - firstSymSamp - UE->N_TA_offset - timing_advance; // but use current UE->timing_advance value to compute writeBlockSize - int writeBlockSize = fp->get_samples_per_slot((slot_nr + DURATION_RX_TO_TX) % nb_slot_frame, fp) - iq_shift_to_apply; + int writeBlockSize = fp->get_samples_per_slot((slot_nr + duration_rx_to_tx) % nb_slot_frame, fp) - iq_shift_to_apply; if (UE->timing_advance != timing_advance) { writeBlockSize -= UE->timing_advance - timing_advance; timing_advance = UE->timing_advance; @@ -1025,6 +1051,7 @@ void *UE_thread(void *arg) curMsgTx->proc.timestamp_tx = writeTimestamp; curMsgTx->UE = UE; curMsgTx->stream_status = stream_status; + curMsgTx->proc.nr_slot_tx_offset = nr_slot_tx_offset; int sync_to_previous_thread = stream_status == STREAM_STATUS_SYNCED ? 1 : 0; int slot = curMsgTx->proc.nr_slot_tx; @@ -1034,6 +1061,9 @@ void *UE_thread(void *arg) curMsgTx); stream_status = STREAM_STATUS_SYNCED; tx_wait_for_dlsch[slot] = 0; + if (duration_rx_to_tx != DURATION_RX_TO_TX) { + duration_rx_to_tx = DURATION_RX_TO_TX; + } } return NULL; diff --git a/executables/position_interface.c b/executables/position_interface.c index 3d6bbe3094..c2cd0b09ca 100644 --- a/executables/position_interface.c +++ b/executables/position_interface.c @@ -3,7 +3,7 @@ extern uint16_t NB_UE_INST; static position_t **positionArray = 0; -position_t *check_position(int Mod_id) +void config_position_coordinates(int Mod_id) { AssertFatal(Mod_id < NB_UE_INST, "Mod_id must be less than NB_UE_INST. Mod_id:%d NB_UE_INST:%d", Mod_id, NB_UE_INST); if (positionArray == NULL) { @@ -12,18 +12,17 @@ position_t *check_position(int Mod_id) if (!positionArray[Mod_id]) { char positionName[64]; sprintf(positionName, "position%d", Mod_id); - positionArray[Mod_id] = (void *)init_position(positionName); + positionArray[Mod_id] = (void *) init_position_coordinates(positionName); } - return (position_t *)positionArray[Mod_id]; } -position_t *init_position(char *sectionName) +position_t *init_position_coordinates(char *sectionName) { position_t *position = (position_t *)calloc(sizeof(position_t), 1); paramdef_t position_params[] = POSITION_CONFIG_PARAMS_DEF; int ret = config_get(config_get_if(), position_params, sizeofArray(position_params), sectionName); AssertFatal(ret >= 0, "configuration couldn't be performed for position name: %s", sectionName); - + return position; } diff --git a/executables/position_interface.h b/executables/position_interface.h index a645961f7e..7edda34970 100644 --- a/executables/position_interface.h +++ b/executables/position_interface.h @@ -32,7 +32,7 @@ typedef struct { double positionZ; } position_t; -position_t *check_position(int Mod_id); -position_t *init_position(char *sectionName); +void config_position_coordinates(int Mod_id); +position_t *init_position_coordinates(char *sectionName); position_t *get_position(int Mod_id); #endif \ No newline at end of file diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index 774309831c..b5ef2b4c85 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -394,7 +394,6 @@ typedef struct PHY_VARS_NR_UE_s { uint8_t prs_active_gNBs; NR_DL_UE_HARQ_t dl_harq_processes[2][NR_MAX_DLSCH_HARQ_PROCESSES]; NR_UL_UE_HARQ_t ul_harq_processes[NR_MAX_ULSCH_HARQ_PROCESSES]; - //Paging parameters uint32_t IMSImod1024; uint32_t PF; @@ -540,6 +539,10 @@ typedef struct { int gNB_id; /// NR slot index within frame_tx [0 .. slots_per_frame - 1] to act upon for transmission int nr_slot_tx; + /// NR slot index tx offset to resume + /// in case of NTN, tx_offset can be changed dynamically via SIB19 + /// we need to notify the right tx thread slot based on TX offset change + int nr_slot_tx_offset; int rx_slot_type; /// NR slot index within frame_rx [0 .. slots_per_frame - 1] to act upon for transmission int nr_slot_rx; diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 7d9a1a40a1..1400548665 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -1777,10 +1777,12 @@ void nr_rrc_mac_config_req_sib19_r17(module_id_t module_id, NR_SIB19_r17_t *sib1 // populate ntn_ta structure from mac // if ephemerisInfo_r17 present in SIB19 - if (mac->sc_info.ntn_Config_r17->ephemerisInfo_r17 && mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17 - && (mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionX_r17 != 0 - || mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionY_r17 != 0 - || mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionZ_r17 != 0)) { + struct NR_EphemerisInfo_r17 *ephemeris_info = mac->sc_info.ntn_Config_r17->ephemerisInfo_r17; + struct NR_PositionVelocity_r17 *position_velocity = mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17; + + if (ephemeris_info && position_velocity + && (position_velocity->positionX_r17 != 0 || position_velocity->positionY_r17 != 0 + || position_velocity->positionZ_r17 != 0)) { mac->ntn_ta.N_UE_TA_adj = calculate_ue_sat_ta(get_position(module_id), mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17); } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index 98f1d7a9e8..e30b69f6be 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -923,7 +923,7 @@ void nr_get_RA_window(NR_UE_MAC_INST_t *mac) NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon; AssertFatal(&setup->rach_ConfigGeneric != NULL, "In %s: FATAL! rach_ConfigGeneric is NULL...\n", __FUNCTION__); - const double ta_Common_ms = get_ta_Common_ms(mac->sc_info.ntn_Config_r17); + const double ta_Common_ms = get_ta_Common_ms(&mac->ntn_ta); const int mu = mac->current_DL_BWP->scs; const int slots_per_ms = nr_slots_per_frame[mu] / 10; From 21bf5c464c42bfd153ef397b9d6e91a9eb553609 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Dec 2024 08:46:23 +0100 Subject: [PATCH 13/83] GTPV1U_ENB_END_MARKER_REQ: use correct message struct --- openair3/ocp-gtpu/gtp_itf.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index b9ffea6531..8a595c8a88 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -403,9 +403,10 @@ static void gtpv1uSendDlDeliveryStatus(instance_t instance, gtpv1u_DU_buffer_rep compatInst(instance), tmp.outgoing_ip_addr, tmp.outgoing_port, GTP_GPDU, tmp.teid_outgoing, NULL, 0, false, false, 0, 0, NR_RAN_CONTAINER, extensionHeader->buffer, extensionHeader->length); } -static void gtpv1uEndTunnel(instance_t instance, gtpv1u_tunnel_data_req_t *req) { - ue_id_t ue_id=req->ue_id; - int bearer_id=req->bearer_id; +static void gtpv1uEndTunnel(instance_t instance, gtpv1u_enb_end_marker_req_t *req) +{ + ue_id_t ue_id=req->rnti; + int bearer_id=req->rab_id; pthread_mutex_lock(&globGtp.gtp_lock); getInstRetVoid(compatInst(instance)); getUeRetVoid(inst, ue_id); @@ -1305,8 +1306,8 @@ void *gtpv1uTask(void *args) { break; case GTPV1U_ENB_END_MARKER_REQ: - gtpv1uEndTunnel(compatInst(myInstance), >PV1U_TUNNEL_DATA_REQ(message_p)); - itti_free(TASK_GTPV1_U, GTPV1U_TUNNEL_DATA_REQ(message_p).buffer); + gtpv1uEndTunnel(compatInst(myInstance), >PV1U_ENB_END_MARKER_REQ(message_p)); + itti_free(TASK_GTPV1_U, GTPV1U_ENB_END_MARKER_REQ(message_p).buffer); break; case GTPV1U_ENB_DATA_FORWARDING_REQ: From cb726af80751fe57ed9a3e0d2a19deb48962d1a6 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Dec 2024 08:45:40 +0100 Subject: [PATCH 14/83] GTP: Fix function name in macro --- openair3/ocp-gtpu/gtp_itf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 8a595c8a88..68d9a0cc3d 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -193,7 +193,7 @@ instance_t legacyInstanceMapping=0; auto ptrUe=insT->ue2te_mapping.find(Ue); \ \ if ( ptrUe==insT->ue2te_mapping.end() ) { \ - LOG_E(GTPU, "[%ld] gtpv1uSend failed: while getting ue id %ld in hashtable ue_mapping\n", instance, ue_id); \ + LOG_E(GTPU, "[%ld] %s failed: while getting ue id %ld in hashtable ue_mapping\n", instance, __func__, ue_id); \ pthread_mutex_unlock(&globGtp.gtp_lock); \ return; \ } @@ -202,7 +202,7 @@ instance_t legacyInstanceMapping=0; auto ptrUe=insT->ue2te_mapping.find(Ue); \ \ if ( ptrUe==insT->ue2te_mapping.end() ) { \ - LOG_E(GTPU, "[%ld] gtpv1uSend failed: while getting ue id %ld in hashtable ue_mapping\n", instance, ue_id); \ + LOG_E(GTPU, "[%ld] %s failed: while getting ue id %ld in hashtable ue_mapping\n", instance, __func__, ue_id); \ pthread_mutex_unlock(&globGtp.gtp_lock); \ return GTPNOK; \ } From 789ee2335ea5fed6ad5044cdd924d9ae420f61b9 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Dec 2024 08:33:29 +0100 Subject: [PATCH 15/83] Correct documentation: PDCP passes to SDAP --- doc/SW_archi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/SW_archi.md b/doc/SW_archi.md index b186bea524..6ba78ad8f1 100644 --- a/doc/SW_archi.md +++ b/doc/SW_archi.md @@ -338,7 +338,7 @@ On the Tx side (downlink in gNB), the entry functions `nr_pdcp_data_req_drb()` a ## PDCP Rx flow -At the Rx side, `pdcp_data_ind()` serves as the entry point for receiving data from RLC. Within `pdcp_data_ind()`, the PDCP manager mutex protects access to the PDU receiving function of PDCP (`recv_pdu()` callback corresponding to `nr_pdcp_entity_recv_pdu()` for DRBs). Following this, the `deliver_sdu_drb()` function dispatches the received data to the GTP thread via an ITTI message (`GTPV1U_TUNNEL_DATA_REQ`). +At the Rx side, `pdcp_data_ind()` serves as the entry point for receiving data from RLC. Within `pdcp_data_ind()`, the PDCP manager mutex protects access to the PDU receiving function of PDCP (`recv_pdu()` callback corresponding to `nr_pdcp_entity_recv_pdu()` for DRBs). Following this, the `deliver_sdu_drb()` function dispatches the received data to the SDAP sublayer. ## PDCP security From f6238eddec8062cb21a761920deb57e77a781015 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Dec 2024 08:04:18 +0100 Subject: [PATCH 16/83] Reformat gtpv1uSend(), shorten buf/len variable names --- openair3/ocp-gtpu/gtp_itf.cpp | 57 ++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 68d9a0cc3d..f8fd6b0c5b 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -286,38 +286,47 @@ static int gtpv1uCreateAndSendMsg(int h, return !GTPNOK; } -static void gtpv1uSend(instance_t instance, gtpv1u_tunnel_data_req_t *req, bool seqNumFlag, bool npduNumFlag) { - uint8_t *buffer=req->buffer+req->offset; - size_t length=req->length; - ue_id_t ue_id=req->ue_id; - int bearer_id=req->bearer_id; +static void gtpv1uSend(instance_t instance, gtpv1u_tunnel_data_req_t *req, bool seqNumFlag, bool npduNumFlag) +{ + uint8_t *buf = req->buffer + req->offset; + size_t len = req->length; + ue_id_t ue_id = req->ue_id; + int bearer_id = req->bearer_id; + pthread_mutex_lock(&globGtp.gtp_lock); getInstRetVoid(compatInst(instance)); getUeRetVoid(inst, ue_id); - auto ptr2=ptrUe->second.bearers.find(bearer_id); + auto ptr2 = ptrUe->second.bearers.find(bearer_id); - if ( ptr2 == ptrUe->second.bearers.end() ) { - LOG_E(GTPU,"[%ld] GTP-U instance: sending a packet to a non existant UE:RAB: %lx/%x\n", instance, ue_id, bearer_id); + if (ptr2 == ptrUe->second.bearers.end()) { + LOG_E(GTPU, "[%ld] GTP-U instance: sending a packet to a non existant UE:RAB: %lx/%x\n", instance, ue_id, bearer_id); pthread_mutex_unlock(&globGtp.gtp_lock); return; } - LOG_D(GTPU,"[%ld] sending a packet to UE:RAB:teid %lx/%x/%x, len %lu, oldseq %d, oldnum %d\n", - instance, ue_id, bearer_id,ptr2->second.teid_outgoing,length, ptr2->second.seqNum,ptr2->second.npduNum ); + LOG_D(GTPU, + "[%ld] sending a packet to UE:RAB:teid %lx/%x/%x, len %lu, oldseq %d, oldnum %d\n", + instance, + ue_id, + bearer_id, + ptr2->second.teid_outgoing, + len, + ptr2->second.seqNum, + ptr2->second.npduNum); - if(seqNumFlag) + if (seqNumFlag) ptr2->second.seqNum++; - if(npduNumFlag) + if (npduNumFlag) ptr2->second.npduNum++; // copy to release the mutex - gtpv1u_bearer_t tmp=ptr2->second; + gtpv1u_bearer_t tmp = ptr2->second; pthread_mutex_unlock(&globGtp.gtp_lock); if (tmp.outgoing_qfi != -1) { - Gtpv1uExtHeaderT ext = { 0 }; + Gtpv1uExtHeaderT ext = {0}; ext.ExtHeaderLen = 1; // in quad bytes EXT_HDR_LNTH_OCTET_UNITS ext.pdusession_cntr.spare = 0; ext.pdusession_cntr.PDU_type = UL_PDU_SESSION_INFORMATION; @@ -331,8 +340,8 @@ static void gtpv1uSend(instance_t instance, gtpv1u_tunnel_data_req_t *req, bool tmp.outgoing_port, GTP_GPDU, tmp.teid_outgoing, - buffer, - length, + buf, + len, seqNumFlag, npduNumFlag, tmp.seqNum, @@ -341,8 +350,20 @@ static void gtpv1uSend(instance_t instance, gtpv1u_tunnel_data_req_t *req, bool (uint8_t *)&ext, sizeof(ext)); } else { - gtpv1uCreateAndSendMsg( - compatInst(instance), tmp.outgoing_ip_addr, tmp.outgoing_port, GTP_GPDU, tmp.teid_outgoing, buffer, length, seqNumFlag, npduNumFlag, tmp.seqNum, tmp.npduNum, NO_MORE_EXT_HDRS, NULL, 0); + gtpv1uCreateAndSendMsg(compatInst(instance), + tmp.outgoing_ip_addr, + tmp.outgoing_port, + GTP_GPDU, + tmp.teid_outgoing, + buf, + len, + seqNumFlag, + npduNumFlag, + tmp.seqNum, + tmp.npduNum, + NO_MORE_EXT_HDRS, + NULL, + 0); } } From 70fa7137124f257aa5aa5443bf8160c48cf351b9 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Dec 2024 08:06:02 +0100 Subject: [PATCH 17/83] Create direct API to send GTP-U msgs --- openair3/ocp-gtpu/gtp_itf.cpp | 23 +++++++++++++++++------ openair3/ocp-gtpu/gtp_itf.h | 3 +++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index f8fd6b0c5b..146828ba53 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -286,13 +286,14 @@ static int gtpv1uCreateAndSendMsg(int h, return !GTPNOK; } -static void gtpv1uSend(instance_t instance, gtpv1u_tunnel_data_req_t *req, bool seqNumFlag, bool npduNumFlag) +void gtpv1uSendDirect(instance_t instance, + ue_id_t ue_id, + int bearer_id, + uint8_t *buf, + size_t len, + bool seqNumFlag, + bool npduNumFlag) { - uint8_t *buf = req->buffer + req->offset; - size_t len = req->length; - ue_id_t ue_id = req->ue_id; - int bearer_id = req->bearer_id; - pthread_mutex_lock(&globGtp.gtp_lock); getInstRetVoid(compatInst(instance)); getUeRetVoid(inst, ue_id); @@ -367,6 +368,16 @@ static void gtpv1uSend(instance_t instance, gtpv1u_tunnel_data_req_t *req, bool } } +static void gtpv1uSend(instance_t instance, gtpv1u_tunnel_data_req_t *req, bool seqNumFlag, bool npduNumFlag) +{ + uint8_t *buf = req->buffer + req->offset; + size_t len = req->length; + ue_id_t ue_id = req->ue_id; + int bearer_id = req->bearer_id; + + gtpv1uSendDirect(instance, ue_id, bearer_id, buf, len, seqNumFlag, npduNumFlag); +} + static void fillDlDeliveryStatusReport(extensionHeader_t *extensionHeader, uint32_t RLC_buffer_availability, uint32_t NR_PDCP_PDU_SN){ extensionHeader->buffer[0] = (1+sizeof(DlDataDeliveryStatus_flagsT)+(NR_PDCP_PDU_SN>0?3:0)+(NR_PDCP_PDU_SN>0?1:0)+1)/4; diff --git a/openair3/ocp-gtpu/gtp_itf.h b/openair3/ocp-gtpu/gtp_itf.h index ce806f0bfc..f3f336dc2c 100644 --- a/openair3/ocp-gtpu/gtp_itf.h +++ b/openair3/ocp-gtpu/gtp_itf.h @@ -103,6 +103,9 @@ extern "C" { int newGtpuDeleteOneTunnel(instance_t instance, ue_id_t ue_id, int rb_id); int newGtpuDeleteAllTunnels(instance_t instance, ue_id_t ue_id); int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, pdusessionid_t *pdusession_id); + + void gtpv1uSendDirect(instance_t instance, ue_id_t ue_id, int bearer_id, uint8_t *buf, size_t len, bool seqNumFlag, bool npduNumFlag); + instance_t gtpv1Init(openAddr_t context); void *gtpv1uTask(void *args); From 3c5e999f6d55a88286ed074a03480dfa76bb2713 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Dec 2024 08:21:43 +0100 Subject: [PATCH 18/83] SDAP: Use GTP direct API instead of ITTI Using ITTI calls for user plane implies (1) a memory allocation, (2) mutexes, and (3) queueing messages for each user plane packet, which is heavy. Use a direct API call instead to reduce overhead. --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index bcc93c87dc..bf9eb97666 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -240,24 +240,14 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, } } + uint8_t *gtp_buf = (uint8_t *)(buf + offset); + size_t gtp_len = size - offset; + // Pushing SDAP SDU to GTP-U Layer - MessageDef *message_p = itti_alloc_new_message_sized(TASK_PDCP_ENB, - 0, - GTPV1U_TUNNEL_DATA_REQ, - sizeof(gtpv1u_tunnel_data_req_t) - + size + GTPU_HEADER_OVERHEAD_MAX - offset); - AssertFatal(message_p != NULL, "OUT OF MEMORY"); - gtpv1u_tunnel_data_req_t *req = >PV1U_TUNNEL_DATA_REQ(message_p); - uint8_t *gtpu_buffer_p = (uint8_t *) (req + 1); - memcpy(gtpu_buffer_p + GTPU_HEADER_OVERHEAD_MAX, buf + offset, size - offset); - req->buffer = gtpu_buffer_p; - req->length = size - offset; - req->offset = GTPU_HEADER_OVERHEAD_MAX; - req->ue_id = ue_id; - req->bearer_id = pdusession_id; - LOG_D(SDAP, "%s() sending message to gtp size %d\n", __func__, size-offset); + LOG_D(SDAP, "sending message to gtp size %ld\n", gtp_len); // very very dirty hack gloabl var N3GTPUInst - itti_send_msg_to_task(TASK_GTPV1_U, *N3GTPUInst, message_p); + instance_t inst = *N3GTPUInst; + gtpv1uSendDirect(inst, ue_id, pdusession_id, gtp_buf, gtp_len, false, false); } else { //nrUE /* * TS 37.324 5.2 Data transfer From 2ffb674d5842f9b65a94a5c513f46c153565a672 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Dec 2024 08:28:16 +0100 Subject: [PATCH 19/83] F1AP: Use GTP direct API instead of ITTI See parent commit for more information. --- doc/F1AP/F1-design.md | 8 ++++---- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 16 +--------------- openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c | 12 ++---------- 3 files changed, 7 insertions(+), 29 deletions(-) diff --git a/doc/F1AP/F1-design.md b/doc/F1AP/F1-design.md index 627e2b4fc2..65ea6b38cf 100644 --- a/doc/F1AP/F1-design.md +++ b/doc/F1AP/F1-design.md @@ -378,15 +378,15 @@ You might also want to consult TS 38.401 regarding the message exchange. ### General In the DU in UL, RLC checks in `deliver_sdu()` if we are operating in split -mode, and either (direct) calls `pdcp_data_ind` (DRB) or (f1ap) sends an -`GTPV1U_TUNNEL_DATA_REQ` ITTI message to the GTP task. +mode, and either (direct) calls `pdcp_data_ind` (DRB) or (f1ap) sends a GTP +message through the GTP API. In the CU in UL, assuming the tunnel is in place, GTP decapsulates the packet and calls the callback `cu_f1u_data_req()`, which calls `pdcp_data_ind()` in CU. In the CU in DL, the PDCP function `deliver_pdu_drb_gnb()` either (direct) calls -into the RLC via `enqueue_rlc_data_req()`, or (f1ap) sends a -`GTPV1U_TUNNEL_DATA_REQ` ITTI message to the GTP task. +into the RLC via `enqueue_rlc_data_req()`, or (f1ap) sends a GTP message +through the GTP API. In the DU in DL, assuming the GTP-U tunnel exists, GTP decapsulates the packet and calls the reception call back `du_rlc_data_req()`, which calls diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index cb80ec99ce..7691871b33 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -718,23 +718,9 @@ static void deliver_pdu_drb_gnb(void *deliver_pdu_data, ue_id_t ue_id, int rb_id protocol_ctxt_t ctxt = { .enb_flag = 1, .rntiMaybeUEid = ue_data.secondary_ue }; if (NODE_IS_CU(node_type)) { - MessageDef *message_p = itti_alloc_new_message_sized(TASK_PDCP_ENB, 0, - GTPV1U_TUNNEL_DATA_REQ, - sizeof(gtpv1u_tunnel_data_req_t) - + size - + GTPU_HEADER_OVERHEAD_MAX); - AssertFatal(message_p != NULL, "OUT OF MEMORY"); - gtpv1u_tunnel_data_req_t *req=>PV1U_TUNNEL_DATA_REQ(message_p); - uint8_t *gtpu_buffer_p = (uint8_t*)(req+1); - memcpy(gtpu_buffer_p + GTPU_HEADER_OVERHEAD_MAX, buf, size); - req->buffer = gtpu_buffer_p; - req->length = size; - req->offset = GTPU_HEADER_OVERHEAD_MAX; - req->ue_id = ue_id; // use CU UE ID as GTP will use that to look up TEID - req->bearer_id = rb_id; LOG_D(PDCP, "%s() (drb %d) sending message to gtp size %d\n", __func__, rb_id, size); extern instance_t CUuniqInstance; - itti_send_msg_to_task(TASK_GTPV1_U, CUuniqInstance, message_p); + gtpv1uSendDirect(CUuniqInstance, ue_id, rb_id, (uint8_t *)buf, size, false, false); } else { uint8_t *memblock = malloc16(size); memcpy(memblock, buf, size); diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index 2ebd18f5e7..64a152f847 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -40,6 +40,7 @@ #include "openair2/F1AP/f1ap_du_rrc_message_transfer.h" #include "openair2/F1AP/f1ap_ids.h" +#include "openair3/ocp-gtpu/gtp_itf.h" extern RAN_CONTEXT_t RC; @@ -525,18 +526,9 @@ rb_found: itti_send_msg_to_task(TASK_DU_F1, ENB_MODULE_ID_TO_INSTANCE(0 /*ctxt_pP->module_id*/), msg); return; } else { - MessageDef *msg = itti_alloc_new_message_sized(TASK_RLC_ENB, 0, GTPV1U_TUNNEL_DATA_REQ, - sizeof(gtpv1u_tunnel_data_req_t) + size); - gtpv1u_tunnel_data_req_t *req=>PV1U_TUNNEL_DATA_REQ(msg); - req->buffer=(uint8_t*)(req+1); - memcpy(req->buffer,buf,size); - req->length=size; - req->offset = 0; - req->ue_id = ue->ue_id; - req->bearer_id=rb_id; LOG_D(RLC, "Received uplink user-plane traffic at RLC-DU to be sent to the CU, size %d \n", size); extern instance_t DUuniqInstance; - itti_send_msg_to_task(TASK_GTPV1_U, DUuniqInstance, msg); + gtpv1uSendDirect(DUuniqInstance, ue->ue_id, rb_id, (uint8_t*) buf, size, false, false); return; } } From ad9645ffb980dc4ab22823ac6fefe29c44b97a23 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Dec 2024 08:43:38 +0100 Subject: [PATCH 20/83] LTE PDCP: Use GTP direct API instead of ITTI See parent commit for more information. LTE PDCP uses GTP, so need to link GTP into the corresponding library. --- CMakeLists.txt | 1 + openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 19 +++++-------------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e6147ce3fb..b80eb72986 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1474,6 +1474,7 @@ add_library(L2_UE ${MAC_SRC_UE} ) target_link_libraries(L2_UE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) +target_link_libraries(L2_UE PRIVATE GTPV1U) add_library(L2_UE_LTE_NR ${L2_RRC_SRC_UE} diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index 3356889bf7..e8042abd80 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -597,7 +597,6 @@ bool pdcp_data_ind(const protocol_ctxt_t *const ctxt_pP, uint8_t rb_offset= (srb_flagP == 0) ? DTCH -1 :0; uint16_t pdcp_uid=0; - MessageDef *message_p = NULL; uint32_t rx_hfn_for_count; int pdcp_sn_for_count; int security_ok; @@ -999,19 +998,11 @@ bool pdcp_data_ind(const protocol_ctxt_t *const ctxt_pP, if (LINK_ENB_PDCP_TO_GTPV1U) { if ((true == ctxt_pP->enb_flag) && (false == srb_flagP)) { - LOG_D(PDCP, "Sending packet to GTP, Calling GTPV1U_TUNNEL_DATA_REQ ue %lx rab %ld len %u\n", ctxt_pP->rntiMaybeUEid, rb_id + 4, sdu_buffer_sizeP - payload_offset); - message_p = itti_alloc_new_message_sized(TASK_PDCP_ENB, 0, GTPV1U_TUNNEL_DATA_REQ, - sizeof(gtpv1u_tunnel_data_req_t) + - sdu_buffer_sizeP - payload_offset + GTPU_HEADER_OVERHEAD_MAX ); - AssertFatal(message_p != NULL, "OUT OF MEMORY"); - gtpv1u_tunnel_data_req_t *req=>PV1U_TUNNEL_DATA_REQ(message_p); - req->buffer = (uint8_t*)(req+1); - memcpy(req->buffer + GTPU_HEADER_OVERHEAD_MAX, sdu_buffer_pP + payload_offset, sdu_buffer_sizeP - payload_offset); - req->length = sdu_buffer_sizeP - payload_offset; - req->offset = GTPU_HEADER_OVERHEAD_MAX; - req->ue_id = ctxt_pP->rntiMaybeUEid; - req->bearer_id = rb_id + 4; - itti_send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p); + ue_id_t ue_id = ctxt_pP->rntiMaybeUEid; + uint8_t *gtp_buf = sdu_buffer_pP + payload_offset; + size_t gtp_len = sdu_buffer_sizeP - payload_offset; + LOG_D(PDCP, "Sending packet to GTP ue %lx rab %ld len %ld\n", ue_id, rb_id + 4, gtp_len); + gtpv1uSendDirect(INSTANCE_DEFAULT, ue_id, rb_id + 4, gtp_buf, gtp_len, false, false); packet_forwarded = true; } } else { From 27f1c0db65792c6f6ecfd18729f84129f6e72f7c Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Dec 2024 08:45:03 +0100 Subject: [PATCH 21/83] Remove GTPV1U_TUNNEL_DATA_REQ ITTI message: it is not used --- openair2/COMMON/gtpv1_u_messages_def.h | 1 - openair2/COMMON/gtpv1_u_messages_types.h | 10 ---------- openair3/ocp-gtpu/gtp_itf.cpp | 15 --------------- 3 files changed, 26 deletions(-) diff --git a/openair2/COMMON/gtpv1_u_messages_def.h b/openair2/COMMON/gtpv1_u_messages_def.h index 35af0c04e7..19001b883e 100644 --- a/openair2/COMMON/gtpv1_u_messages_def.h +++ b/openair2/COMMON/gtpv1_u_messages_def.h @@ -20,7 +20,6 @@ */ -MESSAGE_DEF(GTPV1U_TUNNEL_DATA_REQ, MESSAGE_PRIORITY_MED, gtpv1u_tunnel_data_req_t, Gtpv1uTunnelDataReq) MESSAGE_DEF(GTPV1U_ENB_DATA_FORWARDING_REQ, MESSAGE_PRIORITY_MED, gtpv1u_enb_data_forwarding_req_t,Gtpv1uDataForwardingReq) MESSAGE_DEF(GTPV1U_ENB_DATA_FORWARDING_IND, MESSAGE_PRIORITY_MED, gtpv1u_enb_data_forwarding_ind_t,Gtpv1uDataForwardingInd) MESSAGE_DEF(GTPV1U_ENB_END_MARKER_REQ, MESSAGE_PRIORITY_MED, gtpv1u_enb_end_marker_req_t, Gtpv1uEndMarkerReq) diff --git a/openair2/COMMON/gtpv1_u_messages_types.h b/openair2/COMMON/gtpv1_u_messages_types.h index 0a2691e643..5f12d1e9a2 100644 --- a/openair2/COMMON/gtpv1_u_messages_types.h +++ b/openair2/COMMON/gtpv1_u_messages_types.h @@ -30,7 +30,6 @@ #define NR_GTPV1U_MAX_BEARERS_PER_UE max_val_NR_DRB_Identity #define GTPV1U_ENB_TUNNEL_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uTunnelDataInd -#define GTPV1U_TUNNEL_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uTunnelDataReq #define GTPV1U_ENB_DATA_FORWARDING_REQ(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uDataForwardingReq #define GTPV1U_ENB_DATA_FORWARDING_IND(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uDataForwardingInd #define GTPV1U_ENB_END_MARKER_REQ(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uEndMarkerReq @@ -107,15 +106,6 @@ typedef struct gtpv1u_enb_delete_tunnel_resp_s { teid_t enb_S1u_teid; ///< local S1U Tunnel Endpoint Identifier to be deleted } gtpv1u_enb_delete_tunnel_resp_t; - -typedef struct gtpv1u_tunnel_data_req_s { - uint8_t *buffer; - uint32_t length; - uint32_t offset; ///< start of message offset in buffer - ue_id_t ue_id; - rb_id_t bearer_id; -} gtpv1u_tunnel_data_req_t; - typedef struct gtpv1u_enb_data_forwarding_req_s { uint8_t *buffer; uint32_t length; diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 146828ba53..3036565fad 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -368,16 +368,6 @@ void gtpv1uSendDirect(instance_t instance, } } -static void gtpv1uSend(instance_t instance, gtpv1u_tunnel_data_req_t *req, bool seqNumFlag, bool npduNumFlag) -{ - uint8_t *buf = req->buffer + req->offset; - size_t len = req->length; - ue_id_t ue_id = req->ue_id; - int bearer_id = req->bearer_id; - - gtpv1uSendDirect(instance, ue_id, bearer_id, buf, len, seqNumFlag, npduNumFlag); -} - static void fillDlDeliveryStatusReport(extensionHeader_t *extensionHeader, uint32_t RLC_buffer_availability, uint32_t NR_PDCP_PDU_SN){ extensionHeader->buffer[0] = (1+sizeof(DlDataDeliveryStatus_flagsT)+(NR_PDCP_PDU_SN>0?3:0)+(NR_PDCP_PDU_SN>0?1:0)+1)/4; @@ -1320,11 +1310,6 @@ void *gtpv1uTask(void *args) { switch (msgType) { // DATA TO BE SENT TO UDP - case GTPV1U_TUNNEL_DATA_REQ: { - gtpv1uSend(compatInst(myInstance), >PV1U_TUNNEL_DATA_REQ(message_p), false, false); - } - break; - case GTPV1U_DU_BUFFER_REPORT_REQ:{ gtpv1uSendDlDeliveryStatus(compatInst(myInstance), >PV1U_DU_BUFFER_REPORT_REQ(message_p)); } From bd7fb492fd9b32eb3326cd660d5de94126051fd2 Mon Sep 17 00:00:00 2001 From: Roberto Rosca Date: Thu, 3 Oct 2024 12:36:26 +0300 Subject: [PATCH 22/83] Removed SIB19 related UE arguments - Removed ntn_koffset, ntn_ta_common, ntn_ta_commondrift arguments in order to be used directly from SIB19 - Removed global NTN_UE_Koffset variable and it's use - Introduced getter functions for ntn related parameters --- CMakeLists.txt | 4 +++ executables/nr-ue.c | 33 +++++++++-------- executables/nr-uesoftmodem.c | 6 ---- executables/nr-uesoftmodem.h | 9 ----- executables/position_interface.c | 2 +- executables/position_interface.h | 2 +- openair1/PHY/impl_defs_top.h | 18 ++-------- openair2/LAYER2/NR_MAC_UE/config_ue.c | 38 +++++++++++--------- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 11 ++++-- openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 10 ++---- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 31 +++++++--------- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 28 +++++++-------- targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf | 2 +- 13 files changed, 85 insertions(+), 109 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 681c727dfc..b7b245ab76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1942,6 +1942,7 @@ target_link_libraries(lte-softmodem PRIVATE target_link_libraries(lte-softmodem PRIVATE pthread m CONFIG_LIB rt sctp) target_link_libraries(lte-softmodem PRIVATE ${T_LIB}) target_link_libraries(lte-softmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) +target_link_libraries(lte-softmodem PRIVATE ${blas_LIBRARIES} ${cblas_LIBRARIES} ${lapacke_LIBRARIES} ${lapack_LIBRARIES}) if(E2_AGENT) target_compile_definitions(lte-softmodem PRIVATE ${E2AP_VERSION} ${KPM_VERSION} E2_AGENT) @@ -1997,6 +1998,7 @@ target_link_libraries(lte-uesoftmodem PRIVATE target_link_libraries(lte-uesoftmodem PRIVATE pthread m CONFIG_LIB rt sctp) target_link_libraries(lte-uesoftmodem PRIVATE ${T_LIB}) target_link_libraries(lte-uesoftmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) +target_link_libraries(lte-uesoftmodem PRIVATE ${blas_LIBRARIES} ${cblas_LIBRARIES} ${lapacke_LIBRARIES} ${lapack_LIBRARIES}) # force the generation of ASN.1 so that we don't need to wait during the build target_link_libraries(lte-uesoftmodem PRIVATE @@ -2217,6 +2219,7 @@ target_link_libraries(nr_pucchsim PRIVATE target_link_libraries(nr_pucchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) add_executable(nr_dlsim + ${OPENAIR_DIR}/executables/position_interface.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlsim.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c ${OPENAIR_DIR}/executables/softmodem-common.c @@ -2252,6 +2255,7 @@ target_link_libraries(nr_ulschsim PRIVATE target_link_libraries(nr_ulschsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) add_executable(nr_ulsim + ${OPENAIR_DIR}/executables/position_interface.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/ulsim.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c ${OPENAIR_DIR}/executables/softmodem-common.c diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 7704d59a7d..a70e9edd4e 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -43,8 +43,6 @@ #include "common/utils/threadPool/notified_fifo.h" #include "position_interface.h" -extern unsigned int NTN_UE_Koffset; - /* * NR SLOT PROCESSING SEQUENCE * @@ -828,12 +826,13 @@ void *UE_thread(void *arg) readFrame(UE, &tmp, true); } - double ntn_ta_common = (mac->ntn_ta.N_common_ta_adj + mac->ntn_ta.N_UE_TA_adj) * 2; - int ntn_koffset = mac->ntn_ta.cell_specific_k_offset; + double ntn_ta_common = GET_COMPLETE_TIME_ADVANCE_MS(mac); + int ntn_koffset = GET_NTN_UE_K_OFFSET(mac, 0); - int duration_rx_to_tx = DURATION_RX_TO_TX; + int duration_rx_to_tx = GET_DURATION_RX_TO_TX(mac); int nr_slot_tx_offset = 0; bool update_ntn_system_information = false; + bool apply_duration_next_run = false; while (!oai_exit) { nr_slot_tx_offset = 0; @@ -907,7 +906,7 @@ void *UE_thread(void *arg) openair0_write_reorder_clear_context(&UE->rfdevice); if (get_nrUE_params()->time_sync_I) // ntn_ta_commondrift is in µs/s, max_pos_acc * time_sync_I is in samples/frame - UE->max_pos_acc = get_nrUE_params()->ntn_ta_commondrift * 1e-6 * fp->samples_per_frame / get_nrUE_params()->time_sync_I; + UE->max_pos_acc = mac->ntn_ta.ntn_ta_commondrift * 1e-6 * fp->samples_per_frame / get_nrUE_params()->time_sync_I; else UE->max_pos_acc = 0; shiftForNextFrame = -(UE->init_sync_frame + trashed_frames + 2) * UE->max_pos_acc * get_nrUE_params()->time_sync_I; // compensate for the time drift that happened during initial sync @@ -946,17 +945,15 @@ void *UE_thread(void *arg) if (update_ntn_system_information) { update_ntn_system_information = false; - int ta_offset = - UE->frame_parms.samples_per_subframe * 2 * (mac->ntn_ta.N_common_ta_adj + mac->ntn_ta.N_UE_TA_adj - ntn_ta_common); + int ta_offset = UE->frame_parms.samples_per_subframe * (GET_COMPLETE_TIME_ADVANCE_MS(mac) - ntn_ta_common); UE->timing_advance += ta_offset; - timing_advance = ntn_koffset * 7680; - ntn_ta_common = mac->ntn_ta.N_common_ta_adj + mac->ntn_ta.N_UE_TA_adj; + ntn_ta_common = GET_COMPLETE_TIME_ADVANCE_MS(mac); + ntn_koffset = GET_NTN_UE_K_OFFSET(mac, 0); + timing_advance = ntn_koffset * (UE->frame_parms.samples_per_subframe >> mac->current_UL_BWP->scs); } - if (ntn_koffset != mac->ntn_ta.cell_specific_k_offset && ntn_ta_common != mac->ntn_ta.N_common_ta_adj) { - ntn_koffset = mac->ntn_ta.cell_specific_k_offset; - NTN_UE_Koffset = ntn_koffset; + if (ntn_koffset != (GET_NTN_UE_K_OFFSET(mac, 0)) && ntn_ta_common != GET_COMPLETE_TIME_ADVANCE_MS(mac)) { update_ntn_system_information = true; nr_slot_tx_offset = mac->ntn_ta.cell_specific_k_offset % nb_slot_frame; } @@ -1061,8 +1058,14 @@ void *UE_thread(void *arg) curMsgTx); stream_status = STREAM_STATUS_SYNCED; tx_wait_for_dlsch[slot] = 0; - if (duration_rx_to_tx != DURATION_RX_TO_TX) { - duration_rx_to_tx = DURATION_RX_TO_TX; + // apply new duration next run to avoid thread dead lock + if (apply_duration_next_run) { + duration_rx_to_tx = GET_DURATION_RX_TO_TX(mac); + apply_duration_next_run = false; + } + + if (duration_rx_to_tx != GET_DURATION_RX_TO_TX(mac)) { + apply_duration_next_run = true; } } diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index ff8a7f7fa8..3d6a4ae0a8 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -129,9 +129,6 @@ int otg_enabled; double cpuf; uint32_t N_RB_DL = 106; -// NTN cellSpecificKoffset-r17, but in slots for DL SCS -unsigned int NTN_UE_Koffset = 0; - int create_tasks_nrue(uint32_t ue_nb) { LOG_D(NR_RRC, "%s(ue_nb:%d)\n", __FUNCTION__, ue_nb); itti_wait_ready(1); @@ -518,9 +515,6 @@ int main(int argc, char **argv) } } - // NTN cellSpecificKoffset-r17, but in slots for DL SCS - NTN_UE_Koffset = nrUE_params.ntn_koffset << PHY_vars_UE_g[0][0]->frame_parms.numerology_index; - init_openair0(); lock_memory_to_ram(); diff --git a/executables/nr-uesoftmodem.h b/executables/nr-uesoftmodem.h index 40ff2075a5..74aa64affe 100644 --- a/executables/nr-uesoftmodem.h +++ b/executables/nr-uesoftmodem.h @@ -12,9 +12,6 @@ #define CONFIG_HLP_MAX_LDPC_ITERATIONS "Maximum LDPC decoder iterations\n" #define CONFIG_HLP_TIME_SYNC_P "coefficient for Proportional part of time sync PI controller\n" #define CONFIG_HLP_TIME_SYNC_I "coefficient for Integrating part of time sync PI controller\n" -#define CONFIG_HLP_NTN_KOFFSET "NTN cellSpecificKoffset-r17 (number of slots for a given subcarrier spacing of 15 kHz)\n" -#define CONFIG_HLP_NTN_TA_COMMON "NTN ta-Common, but given in ms\n" -#define CONFIG_HLP_NTN_TA_COMMONDRIFT "NTN ta-CommonDrift, but given in µs/s\n" #define CONFIG_HLP_AUTONOMOUS_TA "Autonomously update TA based on DL drift (useful if main contribution to DL drift is movement, e.g. LEO satellite)\n" #define CONFIG_HLP_AGC "Rx Gain control used for UE\n" @@ -67,9 +64,6 @@ {"num-ues", NULL, 0, .iptr=&(NB_UE_INST), .defuintval=1, TYPE_INT, 0}, \ {"time-sync-P", CONFIG_HLP_TIME_SYNC_P, 0, .dblptr=&(nrUE_params.time_sync_P), .defdblval=0.5, TYPE_DOUBLE, 0}, \ {"time-sync-I", CONFIG_HLP_TIME_SYNC_I, 0, .dblptr=&(nrUE_params.time_sync_I), .defdblval=0.0, TYPE_DOUBLE, 0}, \ - {"ntn-koffset", CONFIG_HLP_NTN_KOFFSET, 0, .uptr=&(nrUE_params.ntn_koffset), .defuintval=0, TYPE_UINT, 0}, \ - {"ntn-ta-common", CONFIG_HLP_NTN_TA_COMMON, 0, .dblptr=&(nrUE_params.ntn_ta_common), .defdblval=0.0, TYPE_DOUBLE, 0}, \ - {"ntn-ta-commondrift", CONFIG_HLP_NTN_TA_COMMONDRIFT, 0, .dblptr=&(nrUE_params.ntn_ta_commondrift), .defdblval=0.0, TYPE_DOUBLE, 0}, \ {"autonomous-ta", CONFIG_HLP_AUTONOMOUS_TA, PARAMFLAG_BOOL, .iptr=&(nrUE_params.autonomous_ta), .defintval=0, TYPE_INT, 0}, \ {"agc", CONFIG_HLP_AGC, PARAMFLAG_BOOL, .iptr=&(nrUE_params.agc), .defintval=0, TYPE_INT, 0}, \ } @@ -94,9 +88,6 @@ typedef struct { int ldpc_offload_flag; double time_sync_P; double time_sync_I; - unsigned int ntn_koffset; - double ntn_ta_common; - double ntn_ta_commondrift; int autonomous_ta; int agc; char *usrp_args; diff --git a/executables/position_interface.c b/executables/position_interface.c index c2cd0b09ca..885859014d 100644 --- a/executables/position_interface.c +++ b/executables/position_interface.c @@ -26,7 +26,7 @@ position_t *init_position_coordinates(char *sectionName) return position; } -position_t *get_position(int Mod_id) +position_t *get_position_coordinates(int Mod_id) { return positionArray[Mod_id]; } \ No newline at end of file diff --git a/executables/position_interface.h b/executables/position_interface.h index 7edda34970..dce6656689 100644 --- a/executables/position_interface.h +++ b/executables/position_interface.h @@ -34,5 +34,5 @@ typedef struct { void config_position_coordinates(int Mod_id); position_t *init_position_coordinates(char *sectionName); -position_t *get_position(int Mod_id); +position_t *get_position_coordinates(int Mod_id); #endif \ No newline at end of file diff --git a/openair1/PHY/impl_defs_top.h b/openair1/PHY/impl_defs_top.h index 24f1599873..27384532c5 100644 --- a/openair1/PHY/impl_defs_top.h +++ b/openair1/PHY/impl_defs_top.h @@ -276,20 +276,6 @@ /* - between reception of un uplink grant and its related transmission (k2) */ #define NR_UE_CAPABILITY_SLOT_RX_TO_TX (3) -/* When the OAI UE receives RX slot N, it starts sending TX slot N+DURATION_RX_TO_TX. - * Therefore DURATION_RX_TO_TX must not be larger than the minimum k1 and k2 values (NR_UE_CAPABILITY_SLOT_RX_TO_TX). - * In case of NTN, the propagation delay is so large, that the TX slot needs to be transmitted far in advance. - * Therefore, the NTN_UE_Koffset is added to DURATION_RX_TO_TX. - * - * Note: currently, the UE requires this to be a constant. - * But in case of NTN, Koffset is only known after receiving SIB19. - * Therefore, support should be added to allow changing DURATION_RX_TO_TX on reception of SIB19 (via FAPI-like interface). - * E.g. no transmission before successful reception of SIB19, and re-sync with disabled transmission if Koffset changes. - * When this has been implemented, the global variable NTN_UE_Koffset should be removed, too. - */ -extern unsigned int NTN_UE_Koffset; -#define DURATION_RX_TO_TX (NR_UE_CAPABILITY_SLOT_RX_TO_TX + NTN_UE_Koffset) - #define NR_MAX_ULSCH_HARQ_PROCESSES (NR_MAX_HARQ_PROCESSES) /* cf 38.214 6.1 UE procedure for receiving the physical uplink shared channel */ #define NR_MAX_DLSCH_HARQ_PROCESSES (NR_MAX_HARQ_PROCESSES) /* cf 38.214 5.1 UE procedure for receiving the physical downlink shared channel */ #endif @@ -317,6 +303,6 @@ typedef struct { #include "common/openairinterface5g_limits.h" #include "assertions.h" -#endif //__PHY_IMPLEMENTATION_DEFS_H__ -/**@} +#endif //__PHY_IMPLEMENTATION_DEFS_H__ +/**@} */ diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 1400548665..6edbb55914 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -33,7 +33,7 @@ #define _GNU_SOURCE #define SPEED_OF_LIGHT 299792458 -//#include "mac_defs.h" +#include "mac_defs.h" #include #include "NR_MAC_UE/mac_proto.h" #include "NR_MAC-CellGroupConfig.h" @@ -254,7 +254,7 @@ static void config_common_ue(NR_UE_MAC_INST_t *mac, mac->phy_config.Mod_id = mac->ue_id; mac->phy_config.CC_id = cc_idP; - + // carrier config LOG_D(MAC, "[UE %d] Entering UE Config Common\n", mac->ue_id); @@ -1771,28 +1771,32 @@ static double calculate_ue_sat_ta(position_t *position_params, struct NR_Positio void nr_rrc_mac_config_req_sib19_r17(module_id_t module_id, NR_SIB19_r17_t *sib19_r17) { NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); + struct NR_NTN_Config_r17 *ntn_Config_r17 = mac->sc_info.ntn_Config_r17; - // ntn-Config-r17 deep copy into mac - asn_copy(&asn_DEF_NR_NTN_Config_r17, (void **)&mac->sc_info.ntn_Config_r17, sib19_r17->ntn_Config_r17); + // update ntn_Config_r17 with received values + UPDATE_IE(ntn_Config_r17, sib19_r17->ntn_Config_r17, NR_NTN_Config_r17_t); // populate ntn_ta structure from mac // if ephemerisInfo_r17 present in SIB19 - struct NR_EphemerisInfo_r17 *ephemeris_info = mac->sc_info.ntn_Config_r17->ephemerisInfo_r17; - struct NR_PositionVelocity_r17 *position_velocity = mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17; - - if (ephemeris_info && position_velocity - && (position_velocity->positionX_r17 != 0 || position_velocity->positionY_r17 != 0 - || position_velocity->positionZ_r17 != 0)) { - mac->ntn_ta.N_UE_TA_adj = - calculate_ue_sat_ta(get_position(module_id), mac->sc_info.ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17); + struct NR_EphemerisInfo_r17 *ephemeris_info = ntn_Config_r17->ephemerisInfo_r17; + if (ephemeris_info) { + struct NR_PositionVelocity_r17 *position_velocity = ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17; + if (position_velocity + && (position_velocity->positionX_r17 != 0 || position_velocity->positionY_r17 != 0 + || position_velocity->positionZ_r17 != 0)) { + mac->ntn_ta.N_UE_TA_adj = calculate_ue_sat_ta(get_position_coordinates(module_id), position_velocity); + } } // if cellSpecificKoffset_r17 is present - if (sib19_r17->ntn_Config_r17->cellSpecificKoffset_r17) { - mac->ntn_ta.cell_specific_k_offset = *sib19_r17->ntn_Config_r17->cellSpecificKoffset_r17; + if (ntn_Config_r17->cellSpecificKoffset_r17) { + mac->ntn_ta.cell_specific_k_offset = *ntn_Config_r17->cellSpecificKoffset_r17; } // Check if ta_Info_r17 is present and convert directly ta_Common_r17 (is in units of 4.072e-3 µs) - if (sib19_r17->ntn_Config_r17->ta_Info_r17) { - mac->ntn_ta.N_common_ta_adj = sib19_r17->ntn_Config_r17->ta_Info_r17->ta_Common_r17 * 4.072e-6; + if (ntn_Config_r17->ta_Info_r17) { + mac->ntn_ta.N_common_ta_adj = ntn_Config_r17->ta_Info_r17->ta_Common_r17 * 4.072e-6; + // ta_CommonDrift_r17 (is in units of 0.2e-3 µs/s) + if (ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17) + mac->ntn_ta.ntn_ta_commondrift = *ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17 * 0.2e-3; } } @@ -2638,4 +2642,4 @@ void nr_rrc_mac_config_req_cg(module_id_t module_id, ue_init_config_request(mac, mac->current_DL_BWP->scs); ret = pthread_mutex_unlock(&mac->if_mutex); AssertFatal(!ret, "mutex failed %d\n", ret); -} +} \ No newline at end of file diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 7c8f37175f..8f211e2215 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -485,7 +485,6 @@ typedef struct nr_lcordered_info_s { bool lc_SRMask; } nr_lcordered_info_t; - typedef struct { uint8_t payload[NR_CCCH_PAYLOAD_SIZE_MAX]; } __attribute__ ((__packed__)) NR_CCCH_PDU; @@ -555,9 +554,13 @@ typedef struct { } si_schedInfo_t; typedef struct ntn_timing_advance_components { -// N_common_ta_adj and N_UE_TA_adj are in ms +// N_common_ta_adj represents common propagation delay received in SIB19 (ms) double N_common_ta_adj; +// N_UE_TA_adj calculated propagation delay from UE and SAT (ms) double N_UE_TA_adj; +// drift rate of common ta in µs/s +double ntn_ta_commondrift; +// cell scheduling offset expressed in terms of 15kHz SCS long cell_specific_k_offset; } ntn_timing_advance_componets_t; @@ -670,5 +673,9 @@ typedef struct NR_UE_MAC_INST_s { ue_mac_stats_t stats; } NR_UE_MAC_INST_t; +#define GET_NTN_UE_K_OFFSET(mac, scs) (mac->ntn_ta.cell_specific_k_offset << scs) +#define GET_COMPLETE_TIME_ADVANCE_MS(mac) ((mac)->ntn_ta.N_common_ta_adj + (mac)->ntn_ta.N_UE_TA_adj * 2) +#define GET_DURATION_RX_TO_TX(mac) (NR_UE_CAPABILITY_SLOT_RX_TO_TX + (mac)->ntn_ta.cell_specific_k_offset) + /*@}*/ #endif /*__LAYER2_MAC_DEFS_H__ */ diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index e30b69f6be..45b1cf6320 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -42,12 +42,6 @@ #include "openair2/LAYER2/RLC/rlc.h" #include "openair2/LAYER2/NR_MAC_UE/mac_defs.h" -#include "nr-uesoftmodem.h" - -static double get_ta_Common_ms(const ntn_timing_advance_componets_t* ntn_ta) -{ - return (ntn_ta->N_common_ta_adj + ntn_ta->N_UE_TA_adj) * 2; -} int16_t get_prach_tx_power(NR_UE_MAC_INST_t *mac) { @@ -622,7 +616,7 @@ void nr_Msg3_transmitted(NR_UE_MAC_INST_t *mac, uint8_t CC_id, frame_t frameP, s { RA_config_t *ra = &mac->ra; NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon; - const double ta_Common_ms = get_ta_Common_ms(&mac->ntn_ta); + const double ta_Common_ms = GET_COMPLETE_TIME_ADVANCE_MS(mac); const int mu = mac->current_UL_BWP->scs; const int slots_per_ms = nr_slots_per_frame[mu] / 10; @@ -923,7 +917,7 @@ void nr_get_RA_window(NR_UE_MAC_INST_t *mac) NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon; AssertFatal(&setup->rach_ConfigGeneric != NULL, "In %s: FATAL! rach_ConfigGeneric is NULL...\n", __FUNCTION__); - const double ta_Common_ms = get_ta_Common_ms(&mac->ntn_ta); + const double ta_Common_ms = GET_COMPLETE_TIME_ADVANCE_MS(mac); const int mu = mac->current_DL_BWP->scs; const int slots_per_ms = nr_slots_per_frame[mu] / 10; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 5808cf3dcb..3f1077bb9a 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -147,13 +147,6 @@ static nr_dci_format_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, const uint8_t *dci_pdu, const int slot); -static int get_NTN_UE_Koffset(NR_NTN_Config_r17_t *ntn_Config_r17, int scs) -{ - if (ntn_Config_r17 && ntn_Config_r17->cellSpecificKoffset_r17) - return *ntn_Config_r17->cellSpecificKoffset_r17 << scs; - return 0; -} - int get_rnti_type(const NR_UE_MAC_INST_t *mac, const uint16_t rnti) { const RA_config_t *ra = &mac->ra; @@ -506,7 +499,7 @@ static int nr_ue_process_dci_ul_00(NR_UE_MAC_INST_t *mac, frame_t frame_tx; int slot_tx; - const int ntn_ue_koffset = get_NTN_UE_Koffset(mac->sc_info.ntn_Config_r17, mac->current_UL_BWP->scs); + const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(mac, mac->current_UL_BWP->scs); if (-1 == nr_ue_pusch_scheduler(mac, 0, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset)) { LOG_E(MAC, "Cannot schedule PUSCH\n"); return -1; @@ -604,7 +597,7 @@ static int nr_ue_process_dci_ul_01(NR_UE_MAC_INST_t *mac, tda_info.k2 = csi_K2; } - const int ntn_ue_koffset = get_NTN_UE_Koffset(mac->sc_info.ntn_Config_r17, mac->current_UL_BWP->scs); + const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(mac, mac->current_UL_BWP->scs); if (-1 == nr_ue_pusch_scheduler(mac, 0, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset)) { LOG_E(MAC, "Cannot schedule PUSCH\n"); return -1; @@ -921,14 +914,14 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac, /* PDSCH_TO_HARQ_FEEDBACK_TIME_IND */ // according to TS 38.213 9.2.3 - const int ntn_ue_koffset = get_NTN_UE_Koffset(mac->sc_info.ntn_Config_r17, dlsch_pdu->SubcarrierSpacing); + const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(mac, dlsch_pdu->SubcarrierSpacing); const uint16_t feedback_ti = 1 + dci->pdsch_to_harq_feedback_timing_indicator.val + ntn_ue_koffset; if (rnti_type != TYPE_RA_RNTI_ && rnti_type != TYPE_SI_RNTI_) { - AssertFatal(feedback_ti > DURATION_RX_TO_TX, - "PDSCH to HARQ feedback time (%d) needs to be higher than DURATION_RX_TO_TX (%d).\n", + AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(mac), + "PDSCH to HARQ feedback time (%d) needs to be higher than DURATION_RX_TO_TX (%ld).\n", feedback_ti, - DURATION_RX_TO_TX); + GET_DURATION_RX_TO_TX(mac)); // set the harq status at MAC for feedback const int tpc[] = {-1, 0, 1, 3}; set_harq_status(mac, @@ -1266,14 +1259,14 @@ static int nr_ue_process_dci_dl_11(NR_UE_MAC_INST_t *mac, /* PDSCH_TO_HARQ_FEEDBACK_TIME_IND */ // according to TS 38.213 Table 9.2.3-1 - const int ntn_ue_koffset = get_NTN_UE_Koffset(mac->sc_info.ntn_Config_r17, dlsch_pdu->SubcarrierSpacing); + const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(mac, dlsch_pdu->SubcarrierSpacing); const uint16_t feedback_ti = pucch_Config->dl_DataToUL_ACK->list.array[dci->pdsch_to_harq_feedback_timing_indicator.val][0] + ntn_ue_koffset; - AssertFatal(feedback_ti > DURATION_RX_TO_TX, - "PDSCH to HARQ feedback time (%d) needs to be higher than DURATION_RX_TO_TX (%d). Min feedback time set in config " + AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(mac), + "PDSCH to HARQ feedback time (%d) needs to be higher than DURATION_RX_TO_TX (%ld). Min feedback time set in config " "file (min_rxtxtime).\n", feedback_ti, - DURATION_RX_TO_TX); + GET_DURATION_RX_TO_TX(mac)); // set the harq status at MAC for feedback const int tpc[] = {-1, 0, 1, 3}; @@ -3453,7 +3446,7 @@ static void set_time_alignment(NR_UE_MAC_INST_t *mac, int ta, ta_type_t type, in ul_time_alignment->ta_command = ta; ul_time_alignment->ta_apply = type; - const int ntn_ue_koffset = get_NTN_UE_Koffset(mac->sc_info.ntn_Config_r17, mac->current_UL_BWP->scs); + const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(mac, mac->current_UL_BWP->scs); const int n_slots_frame = nr_slots_per_frame[mac->current_UL_BWP->scs]; ul_time_alignment->frame = (frame + (slot + ntn_ue_koffset) / n_slots_frame) % MAX_FRAME_NUMBER; ul_time_alignment->slot = (slot + ntn_ue_koffset) % n_slots_frame; @@ -4108,7 +4101,7 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d LOG_E(MAC, "Cannot schedule Msg3. Something wrong in TDA information\n"); return; } - const int ntn_ue_koffset = get_NTN_UE_Koffset(mac->sc_info.ntn_Config_r17, mac->current_UL_BWP->scs); + const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(mac, mac->current_UL_BWP->scs); ret = nr_ue_pusch_scheduler(mac, is_Msg3, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset); // TA command diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 0e9b26c773..44bcedc435 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -1266,9 +1266,9 @@ void nr_ue_aperiodic_srs_scheduling(NR_UE_MAC_INST_t *mac, long resource_trigger return; } - AssertFatal(slot_offset > DURATION_RX_TO_TX, - "Slot offset between DCI and aperiodic SRS (%d) needs to be higher than DURATION_RX_TO_TX (%d)\n", - slot_offset, DURATION_RX_TO_TX); + AssertFatal(slot_offset > GET_DURATION_RX_TO_TX(mac), + "Slot offset between DCI and aperiodic SRS (%d) needs to be higher than DURATION_RX_TO_TX (%ld)\n", + slot_offset, GET_DURATION_RX_TO_TX(mac)); int n_slots_frame = nr_slots_per_frame[current_UL_BWP->scs]; int sched_slot = (slot + slot_offset) % n_slots_frame; NR_TDD_UL_DL_ConfigCommon_t *tdd_config = mac->tdd_UL_DL_ConfigurationCommon; @@ -1732,7 +1732,7 @@ static uint8_t nr_locate_BsrIndexByBufferSize(const uint32_t *table, int size, i // PUSCH scheduler: // - Calculate the slot in which ULSCH should be scheduled. This is current slot + K2, // - where K2 is the offset between the slot in which UL DCI is received and the slot -// - in which ULSCH should be scheduled. K2 is configured in RRC configuration. +// - in which ULSCH should be scheduled. K2 is configured in RRC configuration. // PUSCH Msg3 scheduler: // - scheduled by RAR UL grant according to 8.3 of TS 38.213 // Note: Msg3 tx in the uplink symbols of mixed slot @@ -1772,24 +1772,24 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac, AssertFatal(1 == 0, "Invalid numerology %i\n", mu); } - AssertFatal((k2 + delta) > DURATION_RX_TO_TX, - "Slot offset (%ld) for Msg3 needs to be higher than DURATION_RX_TO_TX (%d). Please set min_rxtxtime at least to %d in gNB config file or gNBs.[0].min_rxtxtime=%d via command line.\n", + AssertFatal((k2 + delta) > GET_DURATION_RX_TO_TX(mac), + "Slot offset (%ld) for Msg3 needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n", k2, - DURATION_RX_TO_TX, - DURATION_RX_TO_TX, - DURATION_RX_TO_TX); + GET_DURATION_RX_TO_TX(mac), + GET_DURATION_RX_TO_TX(mac), + GET_DURATION_RX_TO_TX(mac)); *slot_tx = (current_slot + k2 + delta) % nr_slots_per_frame[mu]; *frame_tx = (current_frame + (current_slot + k2 + delta) / nr_slots_per_frame[mu]) % MAX_FRAME_NUMBER; } else { - AssertFatal(k2 > DURATION_RX_TO_TX, - "Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%d). Please set min_rxtxtime at least to %d in gNB config file or gNBs.[0].min_rxtxtime=%d via command line.\n", + AssertFatal(k2 > GET_DURATION_RX_TO_TX(mac), + "Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n", k2, - DURATION_RX_TO_TX, - DURATION_RX_TO_TX, - DURATION_RX_TO_TX); + GET_DURATION_RX_TO_TX(mac), + GET_DURATION_RX_TO_TX(mac), + GET_DURATION_RX_TO_TX(mac)); if (k2 < 0) { // This can happen when a false DCI is received LOG_W(PHY, "%d.%d. Received k2 %ld\n", current_frame, current_slot, k2); diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf index 955b7b1253..115104e8f1 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf @@ -10,5 +10,5 @@ nssai_sd=1; position0 = { x = 0.0; y = 0.0; - z = 6371400.0; + z = 6377900.0; } \ No newline at end of file From be618b069ed09fe7ccc19aebc9738dc4dd68bf74 Mon Sep 17 00:00:00 2001 From: Roberto Rosca Date: Mon, 18 Nov 2024 16:23:28 +0200 Subject: [PATCH 23/83] Added message-based communication between L2 and L1 regarding NTN configuration parameters --- executables/nr-ue.c | 30 +++++++-------- executables/position_interface.c | 21 ++++++++++ executables/position_interface.h | 21 ++++++++++ .../nfapi/public_inc/fapi_nr_ue_constants.h | 4 +- .../nfapi/public_inc/fapi_nr_ue_interface.h | 14 +++++++ openair1/PHY/INIT/nr_init_ue.c | 2 + openair1/PHY/defs_nr_UE.h | 8 ++++ openair1/SCHED_NR_UE/fapi_nr_ue_l1.c | 16 ++++++++ openair2/LAYER2/NR_MAC_UE/config_ue.c | 11 ++++-- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 35 +++++++++++------ openair2/LAYER2/NR_MAC_UE/main_ue_nr.c | 1 + openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 4 +- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 20 +++++----- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 38 ++++++++++++++----- .../gnb.sa.band66.fr1.25PRB.usrpx300.conf | 2 +- 15 files changed, 173 insertions(+), 54 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index a70e9edd4e..2536e90060 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -157,6 +157,9 @@ void init_nr_ue_vars(PHY_VARS_NR_UE *ue, uint8_t UE_id) ue->dci_thres = 0; ue->target_Nid_cell = -1; + ue->ntn_config_message = CALLOC(1, sizeof(*ue->ntn_config_message)); + ue->ntn_config_message->update = false; + config_position_coordinates(UE_id); // initialize all signal buffers init_nr_ue_signal(ue, nb_connected_gNB); @@ -826,13 +829,12 @@ void *UE_thread(void *arg) readFrame(UE, &tmp, true); } - double ntn_ta_common = GET_COMPLETE_TIME_ADVANCE_MS(mac); - int ntn_koffset = GET_NTN_UE_K_OFFSET(mac, 0); + double ntn_ta_common = 0; + int ntn_koffset = 0; - int duration_rx_to_tx = GET_DURATION_RX_TO_TX(mac); + int duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX; int nr_slot_tx_offset = 0; bool update_ntn_system_information = false; - bool apply_duration_next_run = false; while (!oai_exit) { nr_slot_tx_offset = 0; @@ -945,17 +947,18 @@ void *UE_thread(void *arg) if (update_ntn_system_information) { update_ntn_system_information = false; - int ta_offset = UE->frame_parms.samples_per_subframe * (GET_COMPLETE_TIME_ADVANCE_MS(mac) - ntn_ta_common); + int ta_offset = UE->frame_parms.samples_per_subframe * (UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms - ntn_ta_common); UE->timing_advance += ta_offset; - ntn_ta_common = GET_COMPLETE_TIME_ADVANCE_MS(mac); - ntn_koffset = GET_NTN_UE_K_OFFSET(mac, 0); + ntn_ta_common = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms; + ntn_koffset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset; timing_advance = ntn_koffset * (UE->frame_parms.samples_per_subframe >> mac->current_UL_BWP->scs); } - if (ntn_koffset != (GET_NTN_UE_K_OFFSET(mac, 0)) && ntn_ta_common != GET_COMPLETE_TIME_ADVANCE_MS(mac)) { + if (UE->ntn_config_message->update) { + UE->ntn_config_message->update = false; update_ntn_system_information = true; - nr_slot_tx_offset = mac->ntn_ta.cell_specific_k_offset % nb_slot_frame; + nr_slot_tx_offset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset % nb_slot_frame; } int slot_nr = absolute_slot % nb_slot_frame; @@ -1059,13 +1062,8 @@ void *UE_thread(void *arg) stream_status = STREAM_STATUS_SYNCED; tx_wait_for_dlsch[slot] = 0; // apply new duration next run to avoid thread dead lock - if (apply_duration_next_run) { - duration_rx_to_tx = GET_DURATION_RX_TO_TX(mac); - apply_duration_next_run = false; - } - - if (duration_rx_to_tx != GET_DURATION_RX_TO_TX(mac)) { - apply_duration_next_run = true; + if (update_ntn_system_information) { + duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + UE->ntn_config_message->ntn_config_params.cell_specific_k_offset; } } diff --git a/executables/position_interface.c b/executables/position_interface.c index 885859014d..4aecf16604 100644 --- a/executables/position_interface.c +++ b/executables/position_interface.c @@ -1,3 +1,24 @@ +/* + * 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 "position_interface.h" extern uint16_t NB_UE_INST; diff --git a/executables/position_interface.h b/executables/position_interface.h index dce6656689..6fd80819e4 100644 --- a/executables/position_interface.h +++ b/executables/position_interface.h @@ -1,3 +1,24 @@ +/* + * 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 __POSITION_INTERFACE__H__ #define __POSITION_INTERFACE__H__ diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h index 1094e82fa7..37b661afb9 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h @@ -51,7 +51,9 @@ #define FAPI_NR_DL_CONFIG_TYPE_CSI_RS 0x06 #define FAPI_NR_DL_CONFIG_TYPE_CSI_IM 0x07 #define FAPI_NR_CONFIG_TA_COMMAND 0x08 -#define FAPI_NR_DL_CONFIG_TYPES 0x08 +#define FAPI_NR_DL_NTN_CONFIG_PARAMS 0x09 +#define FAPI_NR_DL_CONFIG_TYPES 0x09 + #define FAPI_NR_CCE_REG_MAPPING_TYPE_INTERLEAVED 0x01 #define FAPI_NR_CCE_REG_MAPPING_TYPE_NON_INTERLEAVED 0x02 diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index d0d9fc9093..b8228778b6 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -555,6 +555,19 @@ typedef struct { bool is_rar; } fapi_nr_ta_command_pdu; +typedef struct { + // N_common_ta_adj represents common propagation delay received in SIB19 (ms) + double N_common_ta_adj; + // N_UE_TA_adj calculated propagation delay from UE and SAT (ms) + double N_UE_TA_adj; + // drift rate of common ta in µs/s + double ntn_ta_commondrift; + // cell scheduling offset expressed in terms of 15kHz SCS + long cell_specific_k_offset; + + double ntn_total_time_advance_ms; +} fapi_nr_dl_ntn_config_command_pdu; + typedef struct { uint8_t pdu_type; union { @@ -563,6 +576,7 @@ typedef struct { fapi_nr_dl_config_csirs_pdu csirs_config_pdu; fapi_nr_dl_config_csiim_pdu csiim_config_pdu; fapi_nr_ta_command_pdu ta_command_pdu; + fapi_nr_dl_ntn_config_command_pdu ntn_config_command_pdu; }; } fapi_nr_dl_config_request_pdu_t; diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 677401ae47..1c5be50f3f 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -338,6 +338,8 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) free_and_zero(ue->prs_vars[idx]); } + free_and_zero(ue->ntn_config_message); + sl_ue_free(ue); } diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index b5ef2b4c85..2db8530a99 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -322,6 +322,11 @@ typedef struct UE_NR_SCAN_INFO_s { int32_t freq_offset_Hz[3][10]; } UE_NR_SCAN_INFO_t; +typedef struct { + bool update; + fapi_nr_dl_ntn_config_command_pdu ntn_config_params; +} ntn_config_message_t; + /// Top-level PHY Data Structure for UE typedef struct PHY_VARS_NR_UE_s { /// \brief Module ID indicator for this instance @@ -532,6 +537,9 @@ typedef struct PHY_VARS_NR_UE_s { sl_nr_ue_phy_params_t SL_UE_PHY_PARAMS; Actor_t sync_actor; Actor_t dl_actors[NUM_DL_ACTORS]; + + ntn_config_message_t* ntn_config_message; + } PHY_VARS_NR_UE; typedef struct { diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index dc2db2d2ea..4ab9167c0a 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -326,6 +326,19 @@ static void configure_dlsch(NR_UE_DLSCH_t *dlsch0, } } +static void configure_ntn_params(PHY_VARS_NR_UE *ue, fapi_nr_dl_ntn_config_command_pdu* ntn_params_message) +{ + if (!ue->ntn_config_message) { + ue->ntn_config_message = CALLOC(1, sizeof(*ue->ntn_config_message)); + } + + ue->ntn_config_message->ntn_config_params.cell_specific_k_offset = ntn_params_message->cell_specific_k_offset; + ue->ntn_config_message->ntn_config_params.N_common_ta_adj = ntn_params_message->N_common_ta_adj; + ue->ntn_config_message->ntn_config_params.ntn_ta_commondrift = ntn_params_message->ntn_ta_commondrift; + ue->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms = ntn_params_message->ntn_total_time_advance_ms; + ue->ntn_config_message->update = true; +} + static void configure_ta_command(PHY_VARS_NR_UE *ue, fapi_nr_ta_command_pdu *ta_command_pdu) { /* Time Alignment procedure @@ -451,6 +464,9 @@ static void nr_ue_scheduled_response_dl(NR_UE_MAC_INST_t *mac, case FAPI_NR_CONFIG_TA_COMMAND: configure_ta_command(phy, &pdu->ta_command_pdu); break; + case FAPI_NR_DL_NTN_CONFIG_PARAMS: + configure_ntn_params(phy, &pdu->ntn_config_command_pdu); + break; default: LOG_W(PHY, "unhandled dl pdu type %d \n", pdu->pdu_type); } diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 6edbb55914..95a08b113c 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -1771,16 +1771,18 @@ static double calculate_ue_sat_ta(position_t *position_params, struct NR_Positio void nr_rrc_mac_config_req_sib19_r17(module_id_t module_id, NR_SIB19_r17_t *sib19_r17) { NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); - struct NR_NTN_Config_r17 *ntn_Config_r17 = mac->sc_info.ntn_Config_r17; - + int ret = pthread_mutex_lock(&mac->if_mutex); + AssertFatal(!ret, "mutex failed %d\n", ret); + // update ntn_Config_r17 with received values + struct NR_NTN_Config_r17 *ntn_Config_r17 = mac->sc_info.ntn_Config_r17; UPDATE_IE(ntn_Config_r17, sib19_r17->ntn_Config_r17, NR_NTN_Config_r17_t); // populate ntn_ta structure from mac // if ephemerisInfo_r17 present in SIB19 struct NR_EphemerisInfo_r17 *ephemeris_info = ntn_Config_r17->ephemerisInfo_r17; if (ephemeris_info) { - struct NR_PositionVelocity_r17 *position_velocity = ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17; + struct NR_PositionVelocity_r17 *position_velocity = ephemeris_info->choice.positionVelocity_r17; if (position_velocity && (position_velocity->positionX_r17 != 0 || position_velocity->positionY_r17 != 0 || position_velocity->positionZ_r17 != 0)) { @@ -1798,6 +1800,9 @@ void nr_rrc_mac_config_req_sib19_r17(module_id_t module_id, NR_SIB19_r17_t *sib1 if (ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17) mac->ntn_ta.ntn_ta_commondrift = *ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17 * 0.2e-3; } + mac->ntn_ta.ntn_params_changed = true; + ret = pthread_mutex_unlock(&mac->if_mutex); + AssertFatal(!ret, "mutex failed %d\n", ret); } static void handle_reconfiguration_with_sync(NR_UE_MAC_INST_t *mac, diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 8f211e2215..55120dca96 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -554,14 +554,16 @@ typedef struct { } si_schedInfo_t; typedef struct ntn_timing_advance_components { -// N_common_ta_adj represents common propagation delay received in SIB19 (ms) -double N_common_ta_adj; -// N_UE_TA_adj calculated propagation delay from UE and SAT (ms) -double N_UE_TA_adj; -// drift rate of common ta in µs/s -double ntn_ta_commondrift; -// cell scheduling offset expressed in terms of 15kHz SCS -long cell_specific_k_offset; + // N_common_ta_adj represents common propagation delay received in SIB19 (ms) + double N_common_ta_adj; + // N_UE_TA_adj calculated propagation delay from UE and SAT (ms) + double N_UE_TA_adj; + // drift rate of common ta in µs/s + double ntn_ta_commondrift; + // cell scheduling offset expressed in terms of 15kHz SCS + long cell_specific_k_offset; + + bool ntn_params_changed; } ntn_timing_advance_componets_t; /*!\brief Top level UE MAC structure */ @@ -673,9 +675,20 @@ typedef struct NR_UE_MAC_INST_s { ue_mac_stats_t stats; } NR_UE_MAC_INST_t; -#define GET_NTN_UE_K_OFFSET(mac, scs) (mac->ntn_ta.cell_specific_k_offset << scs) -#define GET_COMPLETE_TIME_ADVANCE_MS(mac) ((mac)->ntn_ta.N_common_ta_adj + (mac)->ntn_ta.N_UE_TA_adj * 2) -#define GET_DURATION_RX_TO_TX(mac) (NR_UE_CAPABILITY_SLOT_RX_TO_TX + (mac)->ntn_ta.cell_specific_k_offset) +static inline int GET_NTN_UE_K_OFFSET(const ntn_timing_advance_componets_t *ntn_ta, int scs) +{ + return (int)ntn_ta->cell_specific_k_offset << scs; +} + +static inline double GET_COMPLETE_TIME_ADVANCE_MS(const ntn_timing_advance_componets_t *ntn_ta) +{ + return (ntn_ta->N_common_ta_adj + ntn_ta->N_UE_TA_adj) * 2; +} + +static inline long GET_DURATION_RX_TO_TX(const ntn_timing_advance_componets_t *ntn_ta) +{ + return NR_UE_CAPABILITY_SLOT_RX_TO_TX + ntn_ta->cell_specific_k_offset; +} /*@}*/ #endif /*__LAYER2_MAC_DEFS_H__ */ diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index 064fcc4e78..10d982442f 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -70,6 +70,7 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac) mac->p_Max = INT_MIN; mac->p_Max_alt = INT_MIN; mac->n_ta_offset = -1; + mac->ntn_ta.ntn_params_changed = false; pthread_mutex_init(&mac->if_mutex, NULL); reset_mac_inst(mac); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index 45b1cf6320..70e3019701 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -616,7 +616,7 @@ void nr_Msg3_transmitted(NR_UE_MAC_INST_t *mac, uint8_t CC_id, frame_t frameP, s { RA_config_t *ra = &mac->ra; NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon; - const double ta_Common_ms = GET_COMPLETE_TIME_ADVANCE_MS(mac); + const double ta_Common_ms = GET_COMPLETE_TIME_ADVANCE_MS(&mac->ntn_ta); const int mu = mac->current_UL_BWP->scs; const int slots_per_ms = nr_slots_per_frame[mu] / 10; @@ -917,7 +917,7 @@ void nr_get_RA_window(NR_UE_MAC_INST_t *mac) NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon; AssertFatal(&setup->rach_ConfigGeneric != NULL, "In %s: FATAL! rach_ConfigGeneric is NULL...\n", __FUNCTION__); - const double ta_Common_ms = GET_COMPLETE_TIME_ADVANCE_MS(mac); + const double ta_Common_ms = GET_COMPLETE_TIME_ADVANCE_MS(&mac->ntn_ta); const int mu = mac->current_DL_BWP->scs; const int slots_per_ms = nr_slots_per_frame[mu] / 10; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 3f1077bb9a..8a46ad9a25 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -499,7 +499,7 @@ static int nr_ue_process_dci_ul_00(NR_UE_MAC_INST_t *mac, frame_t frame_tx; int slot_tx; - const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(mac, mac->current_UL_BWP->scs); + const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, mac->current_UL_BWP->scs); if (-1 == nr_ue_pusch_scheduler(mac, 0, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset)) { LOG_E(MAC, "Cannot schedule PUSCH\n"); return -1; @@ -597,7 +597,7 @@ static int nr_ue_process_dci_ul_01(NR_UE_MAC_INST_t *mac, tda_info.k2 = csi_K2; } - const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(mac, mac->current_UL_BWP->scs); + const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, mac->current_UL_BWP->scs); if (-1 == nr_ue_pusch_scheduler(mac, 0, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset)) { LOG_E(MAC, "Cannot schedule PUSCH\n"); return -1; @@ -914,14 +914,14 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac, /* PDSCH_TO_HARQ_FEEDBACK_TIME_IND */ // according to TS 38.213 9.2.3 - const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(mac, dlsch_pdu->SubcarrierSpacing); + const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing); const uint16_t feedback_ti = 1 + dci->pdsch_to_harq_feedback_timing_indicator.val + ntn_ue_koffset; if (rnti_type != TYPE_RA_RNTI_ && rnti_type != TYPE_SI_RNTI_) { - AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(mac), + AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(&mac->ntn_ta), "PDSCH to HARQ feedback time (%d) needs to be higher than DURATION_RX_TO_TX (%ld).\n", feedback_ti, - GET_DURATION_RX_TO_TX(mac)); + GET_DURATION_RX_TO_TX(&mac->ntn_ta)); // set the harq status at MAC for feedback const int tpc[] = {-1, 0, 1, 3}; set_harq_status(mac, @@ -1259,14 +1259,14 @@ static int nr_ue_process_dci_dl_11(NR_UE_MAC_INST_t *mac, /* PDSCH_TO_HARQ_FEEDBACK_TIME_IND */ // according to TS 38.213 Table 9.2.3-1 - const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(mac, dlsch_pdu->SubcarrierSpacing); + const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing); const uint16_t feedback_ti = pucch_Config->dl_DataToUL_ACK->list.array[dci->pdsch_to_harq_feedback_timing_indicator.val][0] + ntn_ue_koffset; - AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(mac), + AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(&mac->ntn_ta), "PDSCH to HARQ feedback time (%d) needs to be higher than DURATION_RX_TO_TX (%ld). Min feedback time set in config " "file (min_rxtxtime).\n", feedback_ti, - GET_DURATION_RX_TO_TX(mac)); + GET_DURATION_RX_TO_TX(&mac->ntn_ta)); // set the harq status at MAC for feedback const int tpc[] = {-1, 0, 1, 3}; @@ -3446,7 +3446,7 @@ static void set_time_alignment(NR_UE_MAC_INST_t *mac, int ta, ta_type_t type, in ul_time_alignment->ta_command = ta; ul_time_alignment->ta_apply = type; - const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(mac, mac->current_UL_BWP->scs); + const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, mac->current_UL_BWP->scs); const int n_slots_frame = nr_slots_per_frame[mac->current_UL_BWP->scs]; ul_time_alignment->frame = (frame + (slot + ntn_ue_koffset) / n_slots_frame) % MAX_FRAME_NUMBER; ul_time_alignment->slot = (slot + ntn_ue_koffset) % n_slots_frame; @@ -4101,7 +4101,7 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d LOG_E(MAC, "Cannot schedule Msg3. Something wrong in TDA information\n"); return; } - const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(mac, mac->current_UL_BWP->scs); + const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, mac->current_UL_BWP->scs); ret = nr_ue_pusch_scheduler(mac, is_Msg3, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset); // TA command diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 44bcedc435..8e4fbf7154 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -62,6 +62,8 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, sub_frame_t slotP); static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UE_MAC_INST_t *mac); +static void schedule_ntn_config_command(fapi_nr_dl_config_request_t *dl_config, NR_UE_MAC_INST_t *mac); + static void nr_ue_fill_phr(NR_UE_MAC_INST_t *mac, NR_SINGLE_ENTRY_PHR_MAC_CE *phr, float P_CMAX, @@ -1266,9 +1268,9 @@ void nr_ue_aperiodic_srs_scheduling(NR_UE_MAC_INST_t *mac, long resource_trigger return; } - AssertFatal(slot_offset > GET_DURATION_RX_TO_TX(mac), + AssertFatal(slot_offset > GET_DURATION_RX_TO_TX(&mac->ntn_ta), "Slot offset between DCI and aperiodic SRS (%d) needs to be higher than DURATION_RX_TO_TX (%ld)\n", - slot_offset, GET_DURATION_RX_TO_TX(mac)); + slot_offset, GET_DURATION_RX_TO_TX(&mac->ntn_ta)); int n_slots_frame = nr_slots_per_frame[current_UL_BWP->scs]; int sched_slot = (slot + slot_offset) % n_slots_frame; NR_TDD_UL_DL_ConfigCommon_t *tdd_config = mac->tdd_UL_DL_ConfigurationCommon; @@ -1368,6 +1370,11 @@ void nr_ue_dl_scheduler(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info if (mac->ul_time_alignment.ta_apply != no_ta) schedule_ta_command(dl_config, mac); + + if (mac->ntn_ta.ntn_params_changed) { + mac->ntn_ta.ntn_params_changed = false; + schedule_ntn_config_command(dl_config, mac); + } nr_scheduled_response_t scheduled_response = {.dl_config = dl_config, .module_id = mac->ue_id, @@ -1772,24 +1779,24 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac, AssertFatal(1 == 0, "Invalid numerology %i\n", mu); } - AssertFatal((k2 + delta) > GET_DURATION_RX_TO_TX(mac), + AssertFatal((k2 + delta) > GET_DURATION_RX_TO_TX(&mac->ntn_ta), "Slot offset (%ld) for Msg3 needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n", k2, - GET_DURATION_RX_TO_TX(mac), - GET_DURATION_RX_TO_TX(mac), - GET_DURATION_RX_TO_TX(mac)); + GET_DURATION_RX_TO_TX(&mac->ntn_ta), + GET_DURATION_RX_TO_TX(&mac->ntn_ta), + GET_DURATION_RX_TO_TX(&mac->ntn_ta)); *slot_tx = (current_slot + k2 + delta) % nr_slots_per_frame[mu]; *frame_tx = (current_frame + (current_slot + k2 + delta) / nr_slots_per_frame[mu]) % MAX_FRAME_NUMBER; } else { - AssertFatal(k2 > GET_DURATION_RX_TO_TX(mac), + AssertFatal(k2 > GET_DURATION_RX_TO_TX(&mac->ntn_ta), "Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n", k2, - GET_DURATION_RX_TO_TX(mac), - GET_DURATION_RX_TO_TX(mac), - GET_DURATION_RX_TO_TX(mac)); + GET_DURATION_RX_TO_TX(&mac->ntn_ta), + GET_DURATION_RX_TO_TX(&mac->ntn_ta), + GET_DURATION_RX_TO_TX(&mac->ntn_ta)); if (k2 < 0) { // This can happen when a false DCI is received LOG_W(PHY, "%d.%d. Received k2 %ld\n", current_frame, current_slot, k2); @@ -3591,6 +3598,17 @@ static uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, return mac_ce_info.num_sdus > 0; // success if we got at least one sdu } +static void schedule_ntn_config_command(fapi_nr_dl_config_request_t *dl_config, NR_UE_MAC_INST_t *mac) +{ + fapi_nr_dl_ntn_config_command_pdu *ntn_config_command_pdu = &dl_config->dl_config_list[dl_config->number_pdus].ntn_config_command_pdu; + ntn_config_command_pdu->cell_specific_k_offset = mac->ntn_ta.cell_specific_k_offset; + ntn_config_command_pdu->N_common_ta_adj = mac->ntn_ta.N_common_ta_adj; + ntn_config_command_pdu->N_UE_TA_adj = mac->ntn_ta.N_UE_TA_adj; + ntn_config_command_pdu->ntn_total_time_advance_ms = (mac->ntn_ta.N_common_ta_adj + mac->ntn_ta.N_UE_TA_adj) * 2; + dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_NTN_CONFIG_PARAMS; + dl_config->number_pdus += 1; +} + static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UE_MAC_INST_t *mac) { NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &mac->ul_time_alignment; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.25PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.25PRB.usrpx300.conf index ebf9279bbd..c8f0c31489 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.25PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.25PRB.usrpx300.conf @@ -165,7 +165,7 @@ gNBs = #ntn_Config_r17 # cellSpecificKoffset_r17 = 478; # GEO satellite # cellSpecificKoffset_r17 = 40; # LEO satellite -# ta-Common-r17 = 29319745; +# ta-Common-r17 = 29314900; # positionX-r17 = 0; # positionY-r17 = 0; # positionZ-r17 = 32433846; From 2989bb592bb78a6b65ff66cc46d43cbdf7022f61 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 29 Nov 2024 18:56:59 +0100 Subject: [PATCH 24/83] handle position from RRC --- CMakeLists.txt | 2 -- executables/position_interface.h | 4 ++-- openair2/LAYER2/NR_MAC_UE/config_ue.c | 8 ++++---- openair2/LAYER2/NR_MAC_UE/mac_proto.h | 4 ++-- openair2/RRC/NR_UE/rrc_UE.c | 4 +++- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b7b245ab76..0eb1128159 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2219,7 +2219,6 @@ target_link_libraries(nr_pucchsim PRIVATE target_link_libraries(nr_pucchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) add_executable(nr_dlsim - ${OPENAIR_DIR}/executables/position_interface.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlsim.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c ${OPENAIR_DIR}/executables/softmodem-common.c @@ -2255,7 +2254,6 @@ target_link_libraries(nr_ulschsim PRIVATE target_link_libraries(nr_ulschsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) add_executable(nr_ulsim - ${OPENAIR_DIR}/executables/position_interface.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/ulsim.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c ${OPENAIR_DIR}/executables/softmodem-common.c diff --git a/executables/position_interface.h b/executables/position_interface.h index 6fd80819e4..8d8ad70d91 100644 --- a/executables/position_interface.h +++ b/executables/position_interface.h @@ -47,7 +47,7 @@ } // clang-format on -typedef struct { +typedef struct position { double positionX; double positionY; double positionZ; @@ -56,4 +56,4 @@ typedef struct { void config_position_coordinates(int Mod_id); position_t *init_position_coordinates(char *sectionName); position_t *get_position_coordinates(int Mod_id); -#endif \ No newline at end of file +#endif diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 95a08b113c..a4161dbd61 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -1749,7 +1749,7 @@ void nr_rrc_mac_config_req_sib1(module_id_t module_id, } // computes delay between ue and sat based on SIB19 ephemeris data -static double calculate_ue_sat_ta(position_t *position_params, struct NR_PositionVelocity_r17 *sat_pos) +static double calculate_ue_sat_ta(const position_t *position_params, struct NR_PositionVelocity_r17 *sat_pos) { // get UE position coordinates double posx = position_params->positionX; @@ -1768,7 +1768,7 @@ static double calculate_ue_sat_ta(position_t *position_params, struct NR_Positio return ta_ms; } -void nr_rrc_mac_config_req_sib19_r17(module_id_t module_id, NR_SIB19_r17_t *sib19_r17) +void nr_rrc_mac_config_req_sib19_r17(module_id_t module_id, const position_t *pos, NR_SIB19_r17_t *sib19_r17) { NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); int ret = pthread_mutex_lock(&mac->if_mutex); @@ -1786,7 +1786,7 @@ void nr_rrc_mac_config_req_sib19_r17(module_id_t module_id, NR_SIB19_r17_t *sib1 if (position_velocity && (position_velocity->positionX_r17 != 0 || position_velocity->positionY_r17 != 0 || position_velocity->positionZ_r17 != 0)) { - mac->ntn_ta.N_UE_TA_adj = calculate_ue_sat_ta(get_position_coordinates(module_id), position_velocity); + mac->ntn_ta.N_UE_TA_adj = calculate_ue_sat_ta(pos, position_velocity); } } // if cellSpecificKoffset_r17 is present @@ -2647,4 +2647,4 @@ void nr_rrc_mac_config_req_cg(module_id_t module_id, ue_init_config_request(mac, mac->current_DL_BWP->scs); ret = pthread_mutex_unlock(&mac->if_mutex); AssertFatal(!ret, "mutex failed %d\n", ret); -} \ No newline at end of file +} diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 094d1e5965..d4e3dbe493 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -91,8 +91,8 @@ void nr_rrc_mac_config_req_sib1(module_id_t module_id, NR_SI_SchedulingInfo_v1700_t *si_SchedulingInfo_v1700, NR_ServingCellConfigCommonSIB_t *scc); -void nr_rrc_mac_config_req_sib19_r17(module_id_t module_id, - NR_SIB19_r17_t *sib19_r17); +struct position; /* forward declaration */ +void nr_rrc_mac_config_req_sib19_r17(module_id_t module_id, const struct position *pos, NR_SIB19_r17_t *sib19_r17); void nr_rrc_mac_config_req_reset(module_id_t module_id, NR_UE_MAC_reset_cause_t cause); diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 70708625f7..44534a5cb0 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -62,6 +62,7 @@ #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" +#include "executables/position_interface.h" #ifndef CELLULAR #include "RRC/NR/MESSAGES/asn1_msg.h" @@ -241,7 +242,8 @@ static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si, SI_info->SInfo_r17.sib19_validity = true; if (g_log->log_component[NR_RRC].level >= OAILOG_DEBUG) xer_fprint(stdout, &asn_DEF_NR_SIB19_r17, (const void *)typeandinfo->choice.sib19_v1700); - nr_rrc_mac_config_req_sib19_r17(ue_id, typeandinfo->choice.sib19_v1700); + position_t *p = get_position_coordinates(0); + nr_rrc_mac_config_req_sib19_r17(ue_id, p, typeandinfo->choice.sib19_v1700); nr_timer_start(&SI_info->SInfo_r17.sib19_timer); break; default: From 3f74749aa69bf88a6cd57635d0b005f8df15affb Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 29 Nov 2024 19:02:41 +0100 Subject: [PATCH 25/83] Simplify position reading --- executables/nr-ue.c | 1 - executables/position_interface.c | 30 ++++++++++-------------------- executables/position_interface.h | 4 +--- openair2/RRC/NR_UE/rrc_UE.c | 4 ++-- 4 files changed, 13 insertions(+), 26 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 2536e90060..27f9654aa4 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -160,7 +160,6 @@ void init_nr_ue_vars(PHY_VARS_NR_UE *ue, uint8_t UE_id) ue->ntn_config_message = CALLOC(1, sizeof(*ue->ntn_config_message)); ue->ntn_config_message->update = false; - config_position_coordinates(UE_id); // initialize all signal buffers init_nr_ue_signal(ue, nb_connected_gNB); diff --git a/executables/position_interface.c b/executables/position_interface.c index 4aecf16604..73ce2f4cd7 100644 --- a/executables/position_interface.c +++ b/executables/position_interface.c @@ -22,32 +22,22 @@ #include "position_interface.h" extern uint16_t NB_UE_INST; -static position_t **positionArray = 0; -void config_position_coordinates(int Mod_id) +static position_t read_position_coordinates(char *sectionName) { - AssertFatal(Mod_id < NB_UE_INST, "Mod_id must be less than NB_UE_INST. Mod_id:%d NB_UE_INST:%d", Mod_id, NB_UE_INST); - if (positionArray == NULL) { - positionArray = (position_t **)calloc(1, sizeof(position_t *) * NB_UE_INST); - } - if (!positionArray[Mod_id]) { - char positionName[64]; - sprintf(positionName, "position%d", Mod_id); - positionArray[Mod_id] = (void *) init_position_coordinates(positionName); - } -} - -position_t *init_position_coordinates(char *sectionName) -{ - position_t *position = (position_t *)calloc(sizeof(position_t), 1); + position_t p; + position_t *position = &p; paramdef_t position_params[] = POSITION_CONFIG_PARAMS_DEF; int ret = config_get(config_get_if(), position_params, sizeofArray(position_params), sectionName); AssertFatal(ret >= 0, "configuration couldn't be performed for position name: %s", sectionName); - return position; + return p; } -position_t *get_position_coordinates(int Mod_id) +position_t get_position_coordinates(int Mod_id) { - return positionArray[Mod_id]; -} \ No newline at end of file + AssertFatal(Mod_id < NB_UE_INST, "Mod_id must be less than NB_UE_INST. Mod_id:%d NB_UE_INST:%d", Mod_id, NB_UE_INST); + char positionName[64]; + snprintf(positionName, sizeof(positionName), "position%d", Mod_id); + return read_position_coordinates(positionName); +} diff --git a/executables/position_interface.h b/executables/position_interface.h index 8d8ad70d91..058d94173a 100644 --- a/executables/position_interface.h +++ b/executables/position_interface.h @@ -53,7 +53,5 @@ typedef struct position { double positionZ; } position_t; -void config_position_coordinates(int Mod_id); -position_t *init_position_coordinates(char *sectionName); -position_t *get_position_coordinates(int Mod_id); +position_t get_position_coordinates(int Mod_id); #endif diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 44534a5cb0..8c12e47739 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -242,8 +242,8 @@ static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si, SI_info->SInfo_r17.sib19_validity = true; if (g_log->log_component[NR_RRC].level >= OAILOG_DEBUG) xer_fprint(stdout, &asn_DEF_NR_SIB19_r17, (const void *)typeandinfo->choice.sib19_v1700); - position_t *p = get_position_coordinates(0); - nr_rrc_mac_config_req_sib19_r17(ue_id, p, typeandinfo->choice.sib19_v1700); + position_t p = get_position_coordinates(0); + nr_rrc_mac_config_req_sib19_r17(ue_id, &p, typeandinfo->choice.sib19_v1700); nr_timer_start(&SI_info->SInfo_r17.sib19_timer); break; default: From ef55aaa7c9c572b121b839a463ee64e140e3a5ff Mon Sep 17 00:00:00 2001 From: Roberto Rosca Date: Mon, 2 Dec 2024 16:03:09 +0200 Subject: [PATCH 26/83] Store position coordinates in NR_UE_RRC_INST_t position_coordinates will be allocated and populated upon receiving SIB19 Co-authored-by: Robert Schmidt --- executables/position_interface.c | 12 ++++-------- executables/position_interface.h | 3 ++- openair2/RRC/NR_UE/rrc_UE.c | 16 +++++++++++----- openair2/RRC/NR_UE/rrc_defs.h | 4 ++++ 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/executables/position_interface.c b/executables/position_interface.c index 73ce2f4cd7..84509fbb8e 100644 --- a/executables/position_interface.c +++ b/executables/position_interface.c @@ -23,21 +23,17 @@ extern uint16_t NB_UE_INST; -static position_t read_position_coordinates(char *sectionName) +static void read_position_coordinates(char *sectionName, position_t *position) { - position_t p; - position_t *position = &p; paramdef_t position_params[] = POSITION_CONFIG_PARAMS_DEF; int ret = config_get(config_get_if(), position_params, sizeofArray(position_params), sectionName); AssertFatal(ret >= 0, "configuration couldn't be performed for position name: %s", sectionName); - - return p; } -position_t get_position_coordinates(int Mod_id) +void get_position_coordinates(int Mod_id, position_t *position) { AssertFatal(Mod_id < NB_UE_INST, "Mod_id must be less than NB_UE_INST. Mod_id:%d NB_UE_INST:%d", Mod_id, NB_UE_INST); char positionName[64]; snprintf(positionName, sizeof(positionName), "position%d", Mod_id); - return read_position_coordinates(positionName); -} + read_position_coordinates(positionName, position); +} \ No newline at end of file diff --git a/executables/position_interface.h b/executables/position_interface.h index 058d94173a..0324bceb15 100644 --- a/executables/position_interface.h +++ b/executables/position_interface.h @@ -53,5 +53,6 @@ typedef struct position { double positionZ; } position_t; -position_t get_position_coordinates(int Mod_id); +void get_position_coordinates(int Mod_id, position_t *position); + #endif diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 8c12e47739..b59067430d 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -166,7 +166,7 @@ static void set_DRB_status(NR_UE_RRC_INST_t *rrc, NR_DRB_Identity_t drb_id, NR_R rrc->status_DRBs[drb_id - 1] = status; } -static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si, instance_t ue_id) +static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si, instance_t ue_id, position_t *position) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SI, VCD_FUNCTION_IN); @@ -242,8 +242,14 @@ static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si, SI_info->SInfo_r17.sib19_validity = true; if (g_log->log_component[NR_RRC].level >= OAILOG_DEBUG) xer_fprint(stdout, &asn_DEF_NR_SIB19_r17, (const void *)typeandinfo->choice.sib19_v1700); - position_t p = get_position_coordinates(0); - nr_rrc_mac_config_req_sib19_r17(ue_id, &p, typeandinfo->choice.sib19_v1700); + + // allocate memory for position coordinates + if (!position) + position = CALLOC(1, sizeof(*position)); + // populate position with position from config file + get_position_coordinates(ue_id, position); + + nr_rrc_mac_config_req_sib19_r17(ue_id, position, typeandinfo->choice.sib19_v1700); nr_timer_start(&SI_info->SInfo_r17.sib19_timer); break; default: @@ -389,7 +395,7 @@ static void nr_rrc_process_reconfiguration_v1530(NR_UE_RRC_INST_t *rrc, NR_RRCRe SEQUENCE_free(&asn_DEF_NR_SystemInformation, si, 1); } else { LOG_I(NR_RRC, "[UE %ld] Decoding dedicatedSystemInformationDelivery\n", rrc->ue_id); - nr_decode_SI(SI_info, si, rrc->ue_id); + nr_decode_SI(SI_info, si, rrc->ue_id, rrc->position_coordinates); } } if (rec_1530->otherConfig) { @@ -898,7 +904,7 @@ static int8_t nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(NR_UE_RRC_INST_t *rrc, case NR_BCCH_DL_SCH_MessageType__c1_PR_systemInformation: LOG_I(NR_RRC, "[UE %ld] Decoding SI\n", rrc->ue_id); NR_SystemInformation_t *si = bcch_message->message.choice.c1->choice.systemInformation; - nr_decode_SI(SI_info, si, rrc->ue_id); + nr_decode_SI(SI_info, si, rrc->ue_id, rrc->position_coordinates); break; case NR_BCCH_DL_SCH_MessageType__c1_PR_NOTHING: default: diff --git a/openair2/RRC/NR_UE/rrc_defs.h b/openair2/RRC/NR_UE/rrc_defs.h index a4cd52ee23..6d22e4ad6c 100644 --- a/openair2/RRC/NR_UE/rrc_defs.h +++ b/openair2/RRC/NR_UE/rrc_defs.h @@ -196,6 +196,8 @@ typedef struct rrcPerNB { NR_RSRP_Range_t s_measure; } rrcPerNB_t; +/* forward declaration */ +struct position; typedef struct NR_UE_RRC_INST_s { instance_t ue_id; rrcPerNB_t perNB[NB_CNX_UE]; @@ -236,6 +238,8 @@ typedef struct NR_UE_RRC_INST_s { //Sidelink params NR_SL_PreconfigurationNR_r16_t *sl_preconfig; + struct position *position_coordinates; + } NR_UE_RRC_INST_t; #endif From 0b1dd3ed501ea00f09660555c70f6de6d633aa6c Mon Sep 17 00:00:00 2001 From: Roberto Rosca Date: Fri, 6 Dec 2024 12:02:40 +0200 Subject: [PATCH 27/83] Update 5g_rfsimulator_ntn_geo docker file and configs used for test to exclude unused parameters and add ntn related values. --- ci-scripts/conf_files/gnb.sa.band66.ntn.25prb.rfsim.conf | 7 +++++++ ci-scripts/conf_files/nrue.uicc.conf | 8 +++++++- .../yaml_files/5g_rfsimulator_ntn_geo/docker-compose.yaml | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/ci-scripts/conf_files/gnb.sa.band66.ntn.25prb.rfsim.conf b/ci-scripts/conf_files/gnb.sa.band66.ntn.25prb.rfsim.conf index 8731d00eb0..14b8650060 100644 --- a/ci-scripts/conf_files/gnb.sa.band66.ntn.25prb.rfsim.conf +++ b/ci-scripts/conf_files/gnb.sa.band66.ntn.25prb.rfsim.conf @@ -148,6 +148,13 @@ gNBs = #ext2 #ntn_Config_r17 cellSpecificKoffset_r17 = 478; + ta-Common-r17 = 29314900; + positionX-r17 = 0; + positionY-r17 = 0; + positionZ-r17 = 32433846; + velocityVX-r17 = 0; + velocityVY-r17 = 0; + velocityVZ-r17 = 0; } ); diff --git a/ci-scripts/conf_files/nrue.uicc.conf b/ci-scripts/conf_files/nrue.uicc.conf index d97a271ff6..5424abe30f 100644 --- a/ci-scripts/conf_files/nrue.uicc.conf +++ b/ci-scripts/conf_files/nrue.uicc.conf @@ -6,6 +6,12 @@ uicc0 = { nssai_sst=1; } +position0 = { + x = 0.0; + y = 0.0; + z = 6377900.0; +} + thread-pool = "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1" #/* configuration for channel modelisation */ @@ -34,4 +40,4 @@ channelmod = { ds_tdl = 0; } ); -}; +}; \ No newline at end of file diff --git a/ci-scripts/yaml_files/5g_rfsimulator_ntn_geo/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_ntn_geo/docker-compose.yaml index 5876f5683c..6017a69ed9 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_ntn_geo/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_ntn_geo/docker-compose.yaml @@ -110,7 +110,7 @@ services: - NET_ADMIN # for interface bringup - NET_RAW # for ping environment: - USE_ADDITIONAL_OPTIONS: --band 66 -C 2152680000 --CO -400000000 -r 25 --numerology 0 --ssb 48 --rfsim --rfsimulator.prop_delay 238.74 --ntn-koffset 478 --ntn-ta-common 477.48 --rfsimulator.serveraddr 192.168.71.140 --log_config.global_log_options level,nocolor,time + USE_ADDITIONAL_OPTIONS: --band 66 -C 2152680000 --CO -400000000 -r 25 --numerology 0 --ssb 48 --rfsim --rfsimulator.prop_delay 238.74 --rfsimulator.serveraddr 192.168.71.140 --log_config.global_log_options level,nocolor,time depends_on: - oai-gnb networks: From fc26b8c053a991f3a429916d15ee55775c1592dc Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Tue, 10 Dec 2024 10:53:01 +0100 Subject: [PATCH 28/83] Fix process_slot_tx_barriers for high rx-to-tx values Set the number of barriers to 512 and implement proper slot and frame based selection. Now the dynamic barriers should not be overwritten in case the rx-to-tx offset is high. The maximum offset supported is 512. --- executables/nr-ue.c | 17 +++++++++-------- openair1/PHY/defs_nr_UE.h | 11 ++++++++++- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 15 +++++++++------ 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 27f9654aa4..d892bff9e5 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -553,8 +553,8 @@ void processSlotTX(void *arg) int slots_per_frame = (UE->sl_mode == 2) ? UE->SL_UE_PHY_PARAMS.sl_frame_params.slots_per_frame : UE->frame_parms.slots_per_frame; - int next_slot = (proc->nr_slot_tx + 1 + proc->nr_slot_tx_offset) % slots_per_frame; - dynamic_barrier_join(&UE->process_slot_tx_barriers[next_slot]); + int next_slot_and_frame = proc->nr_slot_tx + 1 + proc->nr_slot_tx_offset + proc->frame_tx * slots_per_frame; + dynamic_barrier_join(&UE->process_slot_tx_barriers[next_slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS]); RU_write(rxtxD, sl_tx_action); free(rxtxD); TracyCZoneEnd(ctx); @@ -810,8 +810,7 @@ void *UE_thread(void *arg) int absolute_slot = 0, decoded_frame_rx = MAX_FRAME_NUMBER - 1, trashed_frames = 0; int tx_wait_for_dlsch[NR_MAX_SLOTS_PER_FRAME]; - int num_ind_fifo = nb_slot_frame; - for(int i = 0; i < num_ind_fifo; i++) { + for(int i = 0; i < NUM_PROCESS_SLOT_TX_BARRIERS; i++) { dynamic_barrier_init(&UE->process_slot_tx_barriers[i]); } int shiftForNextFrame = 0; @@ -822,7 +821,7 @@ void *UE_thread(void *arg) if (get_softmodem_params()->sync_ref && UE->sl_mode == 2) { UE->is_synchronized = 1; } else { - //warm up the RF board + //warm up the RF board int64_t tmp; for (int i = 0; i < 50; i++) readFrame(UE, &tmp, true); @@ -934,7 +933,7 @@ void *UE_thread(void *arg) } // We have resynchronized, maybe after RF loss so we need to purge any existing context memset(tx_wait_for_dlsch, 0, sizeof(tx_wait_for_dlsch)); - for (int i = 0; i < num_ind_fifo; i++) { + for (int i = 0; i < NUM_PROCESS_SLOT_TX_BARRIERS; i++) { dynamic_barrier_reset(&UE->process_slot_tx_barriers[i]); } continue; @@ -957,7 +956,7 @@ void *UE_thread(void *arg) if (UE->ntn_config_message->update) { UE->ntn_config_message->update = false; update_ntn_system_information = true; - nr_slot_tx_offset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset % nb_slot_frame; + nr_slot_tx_offset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset; } int slot_nr = absolute_slot % nb_slot_frame; @@ -1054,7 +1053,9 @@ void *UE_thread(void *arg) int sync_to_previous_thread = stream_status == STREAM_STATUS_SYNCED ? 1 : 0; int slot = curMsgTx->proc.nr_slot_tx; - dynamic_barrier_update(&UE->process_slot_tx_barriers[slot], + int slot_and_frame = slot + curMsgTx->proc.frame_tx * UE->frame_parms.slots_per_frame; + + dynamic_barrier_update(&UE->process_slot_tx_barriers[slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS], tx_wait_for_dlsch[slot] + sync_to_previous_thread, start_process_slot_tx, curMsgTx); diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index 2db8530a99..729acc84ca 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -85,6 +85,15 @@ #define UNUSED(x) (void)x; #define NUM_DL_ACTORS 4 +// Set the number of barriers for processSlotTX to 512. This value has to be at least 483 for NTN where +// DL-to-UL offset is up to 483. The selected value is also half of the frame range so that +// (slot + frame * slots_per_frame) % NUM_PROCESS_SLOT_TX_BARRIERS is contiguous between the last slot of +// frame 1023 and first slot of frame 0 +// e.g. in numerology 1: +// (19 + 1023 * 20) % 512 = 511 +// (0 + 0 * 20) % 512 = 0 +#define NUM_PROCESS_SLOT_TX_BARRIERS 512 + #include "impl_defs_top.h" #include "impl_defs_nr.h" #include "time_meas.h" @@ -527,7 +536,7 @@ typedef struct PHY_VARS_NR_UE_s { void *phy_sim_pdsch_dl_ch_estimates_ext; uint8_t *phy_sim_dlsch_b; - dynamic_barrier_t process_slot_tx_barriers[NR_MAX_SLOTS_PER_FRAME]; + dynamic_barrier_t process_slot_tx_barriers[NUM_PROCESS_SLOT_TX_BARRIERS]; // Gain change required for automation RX gain change int adjust_rxgain; diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 664a293a96..ab92b17711 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -729,8 +729,9 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, if (is_cw0_active != ACTIVE && is_cw1_active != ACTIVE) { // don't wait anymore LOG_E(NR_PHY, "Internal error nr_ue_dlsch_procedure() called but no active cw on slot %d, harq %d\n", nr_slot_rx, harq_pid); - const int ack_nack_slot = (proc->nr_slot_rx + dlsch[0].dlsch_config.k1_feedback) % ue->frame_parms.slots_per_frame; - dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot]); + const int ack_nack_slot_and_frame = + (proc->nr_slot_rx + dlsch[0].dlsch_config.k1_feedback) + proc->frame_rx * ue->frame_parms.slots_per_frame; + dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS]); return false; } @@ -865,8 +866,9 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, // DLSCH decoding finished! don't wait anymore in Tx process, we know if we should answer ACK/NACK PUCCH if (dlsch[0].rnti_type == TYPE_C_RNTI_) { - const int ack_nack_slot = (proc->nr_slot_rx + dlsch[0].dlsch_config.k1_feedback) % ue->frame_parms.slots_per_frame; - dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot]); + const int ack_nack_slot_and_frame = + (proc->nr_slot_rx + dlsch[0].dlsch_config.k1_feedback) + proc->frame_rx * ue->frame_parms.slots_per_frame; + dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS]); } if (ue->phy_sim_dlsch_b) @@ -1148,8 +1150,9 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_ nr_ue_dlsch_procedures(ue, proc, dlsch, llr, G); else { LOG_E(NR_PHY, "Demodulation impossible, internal error\n"); - int ack_nack_slot = (proc->nr_slot_rx + dlsch_config->k1_feedback) % ue->frame_parms.slots_per_frame; - dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot]); + const int ack_nack_slot_and_frame = + proc->nr_slot_rx + dlsch_config->k1_feedback + proc->frame_rx * ue->frame_parms.slots_per_frame; + dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS]); LOG_W(NR_PHY, "nr_ue_pdsch_procedures failed in slot %d\n", proc->nr_slot_rx); } From a049c53e99df1bd4714423f2b693937dcca012b2 Mon Sep 17 00:00:00 2001 From: "Badescu, Ciprian" Date: Wed, 11 Dec 2024 03:56:16 +0200 Subject: [PATCH 29/83] better handling of writeBlockSize greater than samples/slot fix the case when writeBlockSize is greater than samples/slot by sending samples from the same buffer instead of out-of-bounds memory read --- executables/nr-ue.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index d892bff9e5..9e5347e957 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -483,11 +483,23 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action) } } - int tmp = openair0_write_reorder(&UE->rfdevice, proc->timestamp_tx, txp, rxtxD->writeBlockSize, fp->nb_antennas_tx, flags); - AssertFatal(tmp == rxtxD->writeBlockSize, ""); + openair0_timestamp writeTimestamp = proc->timestamp_tx; + int writeBlockSize = rxtxD->writeBlockSize; + if ( writeBlockSize > fp->get_samples_per_slot(proc->nr_slot_tx, fp)) { + // if writeBlockSize gets longer that slot size, fill with dummy + const int dummyBlockSize = writeBlockSize - fp->get_samples_per_slot(proc->nr_slot_tx, fp); + int tmp = openair0_write_reorder(&UE->rfdevice, writeTimestamp, txp, dummyBlockSize, fp->nb_antennas_tx, flags); + AssertFatal(tmp == dummyBlockSize, ""); + + writeTimestamp += dummyBlockSize; + writeBlockSize -= dummyBlockSize; + } + + int tmp = openair0_write_reorder(&UE->rfdevice, writeTimestamp, txp, writeBlockSize, fp->nb_antennas_tx, flags); + AssertFatal(tmp == writeBlockSize, ""); for (int i = 0; i < fp->nb_antennas_tx; i++) - memset(txp[i], 0, rxtxD->writeBlockSize); + memset(txp[i], 0, writeBlockSize); } void processSlotTX(void *arg) From 42a10e4700973fa95f82c7a1b21700ac43195e28 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Dec 2024 16:15:05 +0100 Subject: [PATCH 30/83] Correctly initialize u64 mask 1 needs to be marked as long long, to allow shifting numbers >= 32. Otherwise, 1 is an int, limited to 32 bits. --- radio/fhi_72/oran-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/fhi_72/oran-config.c b/radio/fhi_72/oran-config.c index f165044429..ea6d158f86 100644 --- a/radio/fhi_72/oran-config.c +++ b/radio/fhi_72/oran-config.c @@ -452,7 +452,7 @@ static uint64_t get_u64_mask(const paramdef_t *pd) for (int i = 0; i < pd->numelt; ++i) { int num = pd->iptr[i]; AssertFatal(num >= 0 && num < 64, "cannot put element of %d in 64-bit mask\n", num); - mask |= 1 << num; + mask |= 1LL << num; } return mask; } From 3f01ec0e71d8116b191388cb246ca240d75d46ab Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Wed, 11 Dec 2024 12:32:18 -0500 Subject: [PATCH 31/83] Fix iqrecord to work on AVX512 machine --- radio/COMMON/record_player.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/radio/COMMON/record_player.h b/radio/COMMON/record_player.h index 7869fe4cf3..4e6640b561 100644 --- a/radio/COMMON/record_player.h +++ b/radio/COMMON/record_player.h @@ -62,7 +62,10 @@ typedef struct { int64_t nbBytes; int64_t tv_sec; // nb of secs since EPOCH int64_t tv_usec; // nb of µsecs since EPOCH - int64_t rfu2; // pad for 256 bits alignement required by AVX2 + // pad for 512 bits alignement required by AVX512 + int64_t rfu2; + int64_t rfu3; + int64_t rfu4; } iqrec_t; #define DEF_NB_SF 120000 // default nb of sf or ms to capture (2 minutes at 5MHz) #define DEF_SF_FILE "/tmp/iqfile" // default subframes file name From 4c42a20eaa9f5dae02cba67145dcb111229cf980 Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Wed, 11 Dec 2024 12:34:43 -0500 Subject: [PATCH 32/83] Cmd line option for sync in frames for iqrecorder B200 with high clock drift will go out of sync within 280ms which was the default duration to sync in with iqrecorder. Now this value can be specified via cmd line so the user can change it according to needs. --- executables/nr-ue.c | 7 +++++-- radio/COMMON/record_player.h | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index e2882b4224..f72a63d33b 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -851,8 +851,11 @@ void *UE_thread(void *arg) stream_status = STREAM_STATUS_UNSYNC; } else { if (IS_SOFTMODEM_IQPLAYER || IS_SOFTMODEM_IQRECORDER) { - // For IQ recorder-player we force synchronization to happen in 280 ms - while (trashed_frames != 28) { + /* For IQ recorder-player we force synchronization to happen in a fixed duration so that + the replay runs in sync with recorded samples. + */ + const unsigned int sync_in_frames = UE->rfdevice.openair0_cfg->recplay_conf->u_f_sync; + while (trashed_frames != sync_in_frames) { readFrame(UE, &sync_timestamp, true); trashed_frames += 2; } diff --git a/radio/COMMON/record_player.h b/radio/COMMON/record_player.h index 4e6640b561..686fe83d31 100644 --- a/radio/COMMON/record_player.h +++ b/radio/COMMON/record_player.h @@ -72,6 +72,7 @@ typedef struct { #define DEF_SF_DELAY_READ 700 // default read delay µs (860=real) #define DEF_SF_DELAY_WRITE 15 // default write delay µs (15=real) #define DEF_SF_NB_LOOP 5 // default nb loops +#define DEF_F_SYNC 28 // default frames to sync in (280ms) /* help strings definition for config options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */ @@ -83,6 +84,9 @@ typedef struct { #define CONFIG_HLP_SF_RDELAY "Delay in microseconds to read a subframe in replay mode" #define CONFIG_HLP_SF_WDELAY "Delay in microseconds to write a subframe in replay mode" #define CONFIG_HLP_USE_MMAP "In replay mode, map iq file in memory before replaying" +#define CONFIG_HLP_F_SYNC "Number of frames the synchronization is forced to complete. Some b200 with worser \ + internal clock drift will not be able to stay synchronized and will require value \ + lesser than 28. Lesser values will require faster machine." /* keyword strings for config options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */ #define CONFIG_OPT_SF_FILE "subframes-file" #define CONFIG_OPT_SF_REC "subframes-record" @@ -93,6 +97,7 @@ typedef struct { #define CONFIG_OPT_SF_WDELAY "subframes-write-delay" #define CONFIG_OPT_USE_MMAP "use-mmap" #define DEVICE_RECPLAY_SECTION "device.recplay" +#define CONFIG_OPT_F_SYNC "sync-in-frames" /* For information only - the macro is not usable in C++ */ /*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* command line parameters for USRP record/playback */ @@ -107,6 +112,7 @@ typedef struct { {CONFIG_OPT_SF_RDELAY, CONFIG_HLP_SF_RDELAY, 0, .uptr=&((*recplay_conf)->u_sf_read_delay), .defintval=DEF_SF_DELAY_READ, TYPE_UINT, 0}, \ {CONFIG_OPT_SF_WDELAY, CONFIG_HLP_SF_WDELAY, 0, .uptr=&((*recplay_conf)->u_sf_write_delay), .defintval=DEF_SF_DELAY_WRITE, TYPE_UINT, 0}, \ {CONFIG_OPT_USE_MMAP, CONFIG_HLP_USE_MMAP, PARAMFLAG_BOOL, .uptr=&((*recplay_conf)->use_mmap), .defuintval=1, TYPE_UINT, 0}, \ + {CONFIG_OPT_F_SYNC, CONFIG_HLP_F_SYNC, 0, .uptr=&((*recplay_conf)->u_f_sync), .defuintval=DEF_F_SYNC, TYPE_UINT, 0}, \ }/*! \brief Record Player Configuration and state */ typedef struct { char *u_sf_filename; // subframes file path @@ -117,6 +123,7 @@ typedef struct { unsigned int use_mmap; // default is to use mmap unsigned int u_sf_replay; // replay mode (if 1) unsigned int u_sf_record; // record mode (if 1) + unsigned int u_f_sync; // number of frames sync will complete } recplay_conf_t; typedef struct { From 02679ca07cd7b4dcf7c754c8f5fd0ee21bee3803 Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Mon, 28 Oct 2024 10:25:24 +0100 Subject: [PATCH 33/83] CI: Create FHI7.2 test with Metanoia RU, 2 layers in DL --- ...a.band77.273prb.fhi72.4x4.2L-metanoia.conf | 254 ++++++++++++++++++ .../container_sa_fhi72_metanoia_up2_2x2.xml | 172 ++++++++++++ .../sa_fhi_7.2_metanoia_2x2_gnb/README.md | 87 ++++++ .../docker-compose.yml | 40 +++ .../setup_cleanup.sh | 5 + .../setup_sriov_metanoia.sh | 20 ++ doc/TESTBenches.md | 2 +- 7 files changed, 579 insertions(+), 1 deletion(-) create mode 100644 ci-scripts/conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf create mode 100644 ci-scripts/xml_files/container_sa_fhi72_metanoia_up2_2x2.xml create mode 100644 ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/README.md create mode 100644 ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/docker-compose.yml create mode 100644 ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/setup_cleanup.sh create mode 100644 ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/setup_sriov_metanoia.sh diff --git a/ci-scripts/conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf b/ci-scripts/conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf new file mode 100644 index 0000000000..b2f0c2ac14 --- /dev/null +++ b/ci-scripts/conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf @@ -0,0 +1,254 @@ +Active_gNBs = ( "oai-du"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_name = "oai-du"; + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 208; mnc = 97; mnc_length = 2; snssaiList = ( { sst = 1; }); }); + nr_cellid = 1; + + ////////// Physical parameters: + pdsch_AntennaPorts_XP = 2; + pusch_AntennaPorts = 4; + pdsch_AntennaPorts_N1 = 2; + maxMIMO_layers = 2; + do_CSIRS = 1; + do_SRS = 0; + force_UL256qam_off = 1; + + servingCellConfigCommon = ( + { +#spCellConfigCommon + physCellId = 0; +# downlinkConfigCommon + #frequencyInfoDL + # this is 3300.24 + 134*12*30e3 = 3348.48 MHz (5G NR GSCN: 7741) + absoluteFrequencySSB = 649920; #JF maybe we should adjust a bit + dl_frequencyBand = 78; + # this is 3300.24 MHz + dl_absoluteFrequencyPointA = 646724; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 273; + #initialDownlinkBWP + #genericParameters + # this is RBstart=0,L=162 (275*(275-L+1))+(274-RBstart)) + initialDLBWPlocationAndBandwidth = 1099; + # +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPsearchSpaceZero = 0; + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 273; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 1099; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 148; # JF check this and other PRACH related params +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 12; + preambleReceivedTargetPower = -96; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 5; +#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, + msg3_DeltaPreamble = 1; + p0_NominalWithGrant = -90; +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; +# ssb_PositionsInBurs_BitmapPR +# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_Bitmap = 1; +# 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; #6; + nrofDownlinkSlots = 3; #7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 1; #2; + nrofUplinkSymbols = 4; + ssPBCH_BlockPower = -10; + } + ); + # ------- 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.103"; }); + + NETWORK_INTERFACES : + { + GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.18.20"; + GNB_IPV4_ADDRESS_FOR_NGU = "172.21.18.20"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + } +); +MACRLCs = ( +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 220; + pucch_TargetSNRx10 = 220; + ul_bler_target_upper=.35; + ul_bler_target_lower=.15; + pusch_FailureThres = 100; + ul_max_mcs = 28; +} +); +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 130; + pucch0_dtx_threshold = 80; + pusch_dtx_threshold = 10; + max_ldpc_iterations = 10; + tx_amp_backoff_dB = 12; #9; needs to match O-RU configuration # JF important to check + L1_rx_thread_core = 3; + L1_tx_thread_core = 4; # relevant after merge of l1_tx_thread + phase_compensation = 0; # needs to match O-RU configuration # JF to be tested +} +); +RUs = ( +{ + local_rf = "no"; + nb_tx = 4; + nb_rx = 4; + att_tx = 0 + att_rx = 0; + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 75; + sf_extension = 0; + eNB_instances = [0]; + ru_thread_core = 6; + sl_ahead = 10; #5; + ##beamforming 1x2 matrix: 1 layer x 2 antennas + bf_weights = [0x00007fff, 0x0000,0x00007fff, 0x0000]; + 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:c3:11.0", "0000:c3:11.1"); + system_core = 0; + io_core = 1; + worker_cores = (2); + ru_addr = ("00:E0:0C:00:AE:06", "00:E0:0C:00:AE:06"); + mtu = 9000; + fh_config = ({ + T1a_cp_dl = (285, 470); + T1a_cp_ul = (285, 429); + T1a_up = (125, 350); + Ta4 = (110, 180); + ru_config = { + iq_width = 9; + iq_width_prach = 9; + }; + }); +}; + diff --git a/ci-scripts/xml_files/container_sa_fhi72_metanoia_up2_2x2.xml b/ci-scripts/xml_files/container_sa_fhi72_metanoia_up2_2x2.xml new file mode 100644 index 0000000000..d75aa25120 --- /dev/null +++ b/ci-scripts/xml_files/container_sa_fhi72_metanoia_up2_2x2.xml @@ -0,0 +1,172 @@ + + + test-5g-fhi72-metanoia-2x2 + 100 MHz TDD SA METANOIA + tasks + + 200000 + 110000 + 800813 + 120000 + 102000 + 102001 + 100100 + 100010 + 100020 + 100030 + 100040 + 103000 + 100002 + 130000 + 777777 + 888888 + + + + + Custom_Script + Setup sriov and network interfaces Metanoia + cacofonix + + yes + + + + Pull_Cluster_Image + Pull Images from Cluster + oaicicd-ran + oai-gnb-fhi72 + cacofonix + + + + Create_Workspace + Create new Workspace for server 0 + 0 + 0 + + + + Deploy_Object + Deploy gNB (TDD/Band78/100MHz/Metanoia) in a container + ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb + 0 + 0 + + + + Attach_UE + Attach UE + up2-fhi72 + + + + Ping + Ping: 100 pings in 10 sec + up2-fhi72 + -c 100 -i 0.1 172.21.6.104 + 1 + 15 + + + + Iperf + iperf (DL/570Mbps/UDP)(30 sec)(multi-ue profile) + -u -b 570M -t 30 -R + up2-fhi72 + 20 + 80 + balanced + oc-cn5g-20897 + + + + Iperf + iperf (DL/TCP)(30 sec)(multi-ue profile) + -t 30 -R + up2-fhi72 + 80 + oc-cn5g-20897 + + + + Iperf + iperf (UL/100Mbps/UDP)(30 sec)(multi-ue profile) + -u -b 100M -t 30 + up2-fhi72 + 20 + 80 + balanced + oc-cn5g-20897 + + + + Iperf + iperf (UL/TCP)(30 sec)(multi-ue profile) + -t 30 + up2-fhi72 + 80 + oc-cn5g-20897 + + + + Detach_UE + true + Detach UE + up2-fhi72 + + + + IdleSleep + Sleep + 5 + + + + Undeploy_Object + true + Undeploy gNB + ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb + 0 + 0 + + + + Clean_Test_Server_Images + true + Clean Test Images on Test Server + 0 + oai-gnb-fhi72 + + + + Custom_Script + true + Set CPU to idle state, set kernel parameters to default values + cacofonix + + yes + + + diff --git a/ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/README.md b/ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/README.md new file mode 100644 index 0000000000..53d4312787 --- /dev/null +++ b/ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/README.md @@ -0,0 +1,87 @@ + + + + + +
+ + + + + + OAI O-RAN 7.2 Front-haul Docker Compose +
+ +![Docker deploy 7.2](../../../doc/images/docker-deploy-oai-7-2.png) + +This docker-compose is designed to use `OAI-gNB` with a 7.2 compatible Radio Unit. Before using this docker compose you have to configure +the host machine as per the [ORAN_FHI7.2_Tutorial](../../../doc/ORAN_FHI7.2_Tutorial.md). The container image used by the docker compose file is tested only on `Ubuntu 22.04` and `RHEL 9.4` docker host. + +## Build Image (Optional) + +Refer to [OAI Docker/Podman Build and Usage Procedures](../../../docker/README.md) + +## Configure Networking + +### SR-IOV Virtual Functions (VFs) + +In docker-compose environment there is no automated method +to configure the VFs on the fly. The user will have to manually configure +C/U plane VFs before starting the container `OAI-gNB`. + +You can follow the step +[configure-network-interfaces-and-dpdk-vfs](../../../doc/ORAN_FHI7.2_Tutorial.md#configure-network-interfaces-and-dpdk-vfs). + +### Interface towards AMF (N2) + +For `N2` interface we are using `macvlan` driver of docker. + +You can use the `bridge` driver, in situation + +- When the core network is running on the same machine +- or different machine but you have configured +needed `ip route` and forwarding to access the core network from RAN host. + +To configure docker `macvlan` network +you need to choose `ipam.config` and `driver_opts.parent` are per your environment + +``` + oai-net: + driver: macvlan + name: oai-net + ipam: + config: + - subnet: "172.21.16.0/22" + ip_range: "172.21.18.20/32" + gateway: "172.21.19.254" + driver_opts: + com.docker.network.bridge.name: "oai-net" + parent: ens7f0 +``` + +To configure `bridge` network you need to choose `ipam.config.subnet` as per your environment. + +``` + oai-net: + driver: bridge + name: oai-net + ipam: + config: + - subnet: 192.168.72.128/26 + driver_opts: + com.docker.network.bridge.name: "oai-net" +``` + +## Deploy OAI-gNB Container + +The [configuration file](../../conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf) used by docker compose is configured for Metanoia RU. + +```bash +docker-compose up -d +``` + +To check the logs + +```bash +docker logs oai-gnb -f +``` diff --git a/ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/docker-compose.yml b/ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/docker-compose.yml new file mode 100644 index 0000000000..f0f6cb7691 --- /dev/null +++ b/ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/docker-compose.yml @@ -0,0 +1,40 @@ +services: + oai-gnb: + image: ${REGISTRY:-oaisoftwarealliance}/oai-gnb-fhi72:${TAG:-develop} + cap_add: + - SYS_ADMIN + - IPC_LOCK + - SYS_NICE + cap_drop: + - ALL + container_name: oai-gnb + environment: + TZ: Europe/Paris + USE_ADDITIONAL_OPTIONS: --sa --thread-pool 7,8,9,10,11,12 + devices: + - /dev/vfio:/dev/vfio/ + volumes: + - ../../conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf:/opt/oai-gnb/etc/gnb.conf + - /dev/hugepages:/dev/hugepages + # Please change these values based on your system + cpuset: "0,1,2,3,4,5,6,7,8,9,10,11,12" + networks: + oai-net: + ipv4_address: 172.21.18.20 + healthcheck: + test: /bin/bash -c "pgrep nr-softmodem" + interval: 10s + timeout: 5s + retries: 5 +networks: + oai-net: + driver: macvlan + name: oai-net + ipam: + config: + - subnet: "172.21.16.0/22" + ip_range: "172.21.18.20/32" + gateway: "172.21.19.254" + driver_opts: + com.docker.network.bridge.name: "oai-net" + parent: ens7f0 diff --git a/ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/setup_cleanup.sh b/ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/setup_cleanup.sh new file mode 100644 index 0000000000..9a06336acc --- /dev/null +++ b/ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/setup_cleanup.sh @@ -0,0 +1,5 @@ +set -e +sudo cpupower idle-set -E > /dev/null +sudo sysctl kernel.sched_rt_runtime_us=950000 +sudo sysctl kernel.timer_migration=1 +exit 0 diff --git a/ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/setup_sriov_metanoia.sh b/ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/setup_sriov_metanoia.sh new file mode 100644 index 0000000000..1d7215b70a --- /dev/null +++ b/ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/setup_sriov_metanoia.sh @@ -0,0 +1,20 @@ +set -e +sudo cpupower idle-set -D 0 > /dev/null +sudo sysctl kernel.sched_rt_runtime_us=-1 +sudo sysctl kernel.timer_migration=0 +sudo ethtool -G ens7f1 rx 8160 tx 8160 +sudo sh -c 'echo 0 > /sys/class/net/ens7f1/device/sriov_numvfs' +sudo sh -c 'echo 3 > /sys/class/net/ens7f1/device/sriov_numvfs' +sudo modprobe -r iavf +sudo modprobe iavf +# this next 2 lines is for C/U planes +sudo ip link set ens7f1 vf 0 mac 00:11:22:33:44:55 vlan 3 spoofchk off mtu 9000 +sudo ip link set ens7f1 vf 1 mac 00:11:22:33:44:54 vlan 3 spoofchk off mtu 9000 +sleep 1 +# These are the DPDK bindings for C/U-planes on vlan 1 +sudo /usr/local/bin/dpdk-devbind.py --unbind c3:11.0 +sudo /usr/local/bin/dpdk-devbind.py --unbind c3:11.1 +sudo modprobe vfio-pci +sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci c3:11.0 +sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci c3:11.1 +exit 0 diff --git a/doc/TESTBenches.md b/doc/TESTBenches.md index 57606548e7..9a137ddd1a 100644 --- a/doc/TESTBenches.md +++ b/doc/TESTBenches.md @@ -195,7 +195,7 @@ information on how the images are built. - NR performance tests: 2x2 configuration, 60 MHz and 100 MHz bandwidth - [RAN-SA-FHI72-CN5G](https://jenkins-oai.eurecom.fr/view/RAN/job/RAN-SA-FHI72-CN5G/) ~5G-NR - - cacofonix + FHI72 + VVDN (gNB), up2 (Quectel RM520N UE), OAI CN5G + - cacofonix + FHI72 + Metanoia (gNB), up2 (Quectel RM520N UE), OAI CN5G - OpenShift cluster for CN deployment - FHI 7.2 testing with 100 MHz bandwidth, 2 layers in DL From f8d7e1fd1b7c5aaffdcf25c810d8d66fcea674f5 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Dec 2024 17:05:02 +0100 Subject: [PATCH 34/83] Findxran: exclude default paths, use hints Some users copy libxran.so to a system directory (e.g., /usr/local/lib). At the same time, we require xran_LOCATION to be set to find the build directory. Use HINTS to prefer the location passed through xran_LOCATION. Also, use NO_DEFAULT_PATH to outright disallow global scope, to prevent "accidentally" finding libxran.so in global scope (this is for multi-user systems that are used in development, and where people have different version of libxran for testing purposes). To still use packages in e.g., /usr/local/, it would be possible to set xran_LOCATION to this directory. (there is a problem that the version information will likely not be read correctly, so this might not be enough) --- cmake_targets/tools/MODULES/Findxran.cmake | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cmake_targets/tools/MODULES/Findxran.cmake b/cmake_targets/tools/MODULES/Findxran.cmake index 39f0ffeb75..290a782350 100644 --- a/cmake_targets/tools/MODULES/Findxran.cmake +++ b/cmake_targets/tools/MODULES/Findxran.cmake @@ -83,12 +83,15 @@ find_path(xran_INCLUDE_DIR xran_pkt.h xran_pkt_up.h xran_sync_api.h - PATHS ${xran_LOCATION} - PATH_SUFFIXES api + HINTS ${xran_LOCATION} + PATH_SUFFIXES api include + NO_DEFAULT_PATH ) find_library(xran_LIBRARY NAMES xran - PATHS ${xran_LOCATION}/build + HINTS ${xran_LOCATION} + PATH_SUFFIXES build api + NO_DEFAULT_PATH ) if (NOT xran_LIBRARY) message(FATAL_ERROR "could not detect xran build artifacts at ${xran_LOCATION}/build") From 13a1d863c7b72e8627ee4ed914c1c5cb9d8dd9ef Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 12 Dec 2024 08:34:44 +0100 Subject: [PATCH 35/83] Add Rocky 9.5 to list of distributions --- cmake_targets/tools/build_helper | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 13c8e4efde..45357d2277 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -131,6 +131,7 @@ check_supported_distribution() { "rocky9.2") return 0 ;; "rocky9.3") return 0 ;; "rocky9.4") return 0 ;; + "rocky9.5") return 0 ;; esac return 1 } From 5f22b056957dc972b8a400c4cb593355b9be3af5 Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Wed, 9 Oct 2024 14:06:03 +0200 Subject: [PATCH 36/83] feat(nrLDPC_coding_interface): Add reworked interface definition and loader --- CMakeLists.txt | 6 + .../nrLDPC_coding/nrLDPC_coding_interface.h | 261 ++++++++++++++++++ .../nrLDPC_coding_interface_load.c | 74 +++++ 3 files changed, 341 insertions(+) create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface_load.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e6147ce3fb..d9a226aed4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -849,6 +849,10 @@ set(PHY_NR_CODINGIF ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c ) +set(PHY_NRLDPC_CODINGIF + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface_load.c +) + ############################################## # Base CUDA setting ############################################## @@ -1058,6 +1062,7 @@ set(PHY_SRC_UE ${PHY_POLARSRC} ${PHY_SMALLBLOCKSRC} ${PHY_NR_CODINGIF} + ${PHY_NRLDPC_CODINGIF} ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/pucch_rx.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/srs_rx.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_uci_tools_common.c @@ -1113,6 +1118,7 @@ set(PHY_SRC_UE ${PHY_POLARSRC} ${PHY_SMALLBLOCKSRC} ${PHY_NR_CODINGIF} + ${PHY_NRLDPC_CODINGIF} ) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h new file mode 100644 index 0000000000..6492131df3 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h @@ -0,0 +1,261 @@ +/* + * 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 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h + * \brief interface for libraries implementing coding/decoding algorithms + */ + +#include "PHY/defs_gNB.h" + +#ifndef __NRLDPC_CODING_INTERFACE__H__ +#define __NRLDPC_CODING_INTERFACE__H__ + +/** + * \typedef nrLDPC_segment_decoding_parameters_t + * \struct nrLDPC_segment_decoding_parameters_s + * \brief decoding parameter of segments + * \var E input llr segment size + * \var R code rate indication + * \var llr segment input llr array + * \var d Pointers to code blocks before LDPC decoding (38.212 V15.4.0 section 5.3.2) + * \var d_to_be_cleared + * pointer to the flag used to clear d properly + * when true, clear d after rate dematching + * \var c Pointers to code blocks after LDPC decoding (38.212 V15.4.0 section 5.2.2) + * \var decodeSuccess + * flag indicating that the decoding of the segment was successful + * IT MUST BE FILLED BY THE IMPLEMENTATION + * \var ts_deinterleave deinterleaving time stats + * \var ts_rate_unmatch rate unmatching time stats + * \var ts_ldpc_decode decoding time stats + */ +typedef struct nrLDPC_segment_decoding_parameters_s{ + int E; + uint8_t R; + short *llr; + int16_t *d; + bool *d_to_be_cleared; + uint8_t *c; + bool decodeSuccess; + time_stats_t ts_deinterleave; + time_stats_t ts_rate_unmatch; + time_stats_t ts_ldpc_decode; +} nrLDPC_segment_decoding_parameters_t; + +/** + * \typedef nrLDPC_TB_decoding_parameters_t + * \struct nrLDPC_TB_decoding_parameters_s + * \brief decoding parameter of transport blocks + * \var harq_unique_pid unique id of the HARQ process + * WARNING This id should be unique in the whole instance + * among the active HARQ processes for the duration of the process + * \var processedSegments + * pointer to the number of succesfully decoded segments + * it initially holds the total number of segments decoded after the previous HARQ round + * it finally holds the total number of segments decoded after the current HARQ round + * \var nb_rb number of resource blocks + * \var Qm modulation order + * \var mcs MCS + * \var nb_layers number of layers + * \var BG LDPC base graph id + * \var rv_index redundancy version of the current HARQ round + * \var max_ldpc_iterations maximum number of LDPC iterations + * \var abort_decode pointer to decode abort flag + * \var G Available radio resource bits + * \var tbslbrm Transport block size LBRM + * \var A Transport block size (This is A from 38.212 V15.4.0 section 5.1) + * \var K Code block size at decoder output + * \var Z lifting size + * \var F filler bits size + * \var C number of segments + * \var segments array of segments parameters + */ +typedef struct nrLDPC_TB_decoding_parameters_s{ + + uint32_t harq_unique_pid; + uint32_t *processedSegments; + + uint16_t nb_rb; + uint8_t Qm; + uint8_t mcs; + uint8_t nb_layers; + + uint8_t BG; + uint8_t rv_index; + uint8_t max_ldpc_iterations; + decode_abort_t *abort_decode; + + uint32_t G; + uint32_t tbslbrm; + uint32_t A; + uint32_t K; + uint32_t Z; + uint32_t F; + + uint32_t C; + nrLDPC_segment_decoding_parameters_t *segments; +} nrLDPC_TB_decoding_parameters_t; + +/** + * \typedef nrLDPC_slot_decoding_parameters_t + * \struct nrLDPC_slot_decoding_parameters_s + * \brief decoding parameter of slot + * \var frame frame index + * \var slot slot index + * \var nb_TBs number of transport blocks + * \var threadPool pointer to the thread pool + * The thread pool can be used by the implementation + * in order to launch jobs internally + * DEQUEUING THE JOBS IS DONE WITHIN THE IMPLEMENTATION + * \var TBs array of TBs decoding parameters + */ +typedef struct nrLDPC_slot_decoding_parameters_s{ + int frame; + int slot; + int nb_TBs; + tpool_t *threadPool; + nrLDPC_TB_decoding_parameters_t *TBs; +} nrLDPC_slot_decoding_parameters_t; + +/** + * \typedef nrLDPC_segment_encoding_parameters_t + * \struct nrLDPC_segment_encoding_parameters_s + * \brief encoding parameter of segments + * \var E input llr segment size + * \var output input llr segment array + * \var c Pointers to code blocks before LDPC encoding (38.212 V15.4.0 section 5.2.2) + * flag indicating that the decoding of the segment was successful + * IT MUST BE FILLED BY THE IMPLEMENTATION + * \var ts_interleave interleaving time stats + * \var ts_rate_match rate matching time stats + * \var ts_ldpc_encode encoding time stats + */ +typedef struct nrLDPC_segment_encoding_parameters_s{ + int E; + unsigned char *output; + uint8_t *c; + time_stats_t ts_interleave; + time_stats_t ts_rate_match; + time_stats_t ts_ldpc_encode; +} nrLDPC_segment_encoding_parameters_t; + +/** + * \typedef nrLDPC_TB_encoding_parameters_t + * \struct nrLDPC_TB_encoding_parameters_s + * \brief encoding parameter of transport blocks + * \var harq_unique_pid unique id of the HARQ process + * WARNING This id should be unique in the whole instance + * among the active HARQ processes for the duration of the process + * \var nb_rb number of resource blocks + * \var Qm modulation order + * \var mcs MCS + * \var nb_layers number of layers + * \var BG LDPC base graph id + * \var rv_index + * \var G Available radio resource bits + * \var tbslbrm Transport block size LBRM + * \var A Transport block size (This is A from 38.212 V15.4.0 section 5.1) + * \var Kb Code block size divided by lifting size + * \var K Code block size at input of encoder + * \var Z lifting size + * \var F filler bits size + * \var C number of segments + * \var segments array of segments parameters + */ +typedef struct nrLDPC_TB_encoding_parameters_s{ + + uint32_t harq_unique_pid; + + uint16_t nb_rb; + uint8_t Qm; + uint8_t mcs; + uint8_t nb_layers; + + uint8_t BG; + uint8_t rv_index; + + uint32_t G; + uint32_t tbslbrm; + uint32_t A; + uint32_t Kb; + uint32_t K; + uint32_t Z; + uint32_t F; + + uint32_t C; + nrLDPC_segment_encoding_parameters_t *segments; +} nrLDPC_TB_encoding_parameters_t; + +/** + * \typedef nrLDPC_slot_encoding_parameters_t + * \struct nrLDPC_slot_encoding_parameters_s + * \brief encoding parameter of slot + * \var frame frame index + * \var slot slot index + * \var nb_TBs number of transport blocks + * \var threadPool pointer to the thread pool + * The thread pool can be used by the implementation + * in order to launch jobs internally + * DEQUEUING THE JOBS IS DONE WITHIN THE IMPLEMENTATION + * \var tinput pointer to the input timer struct + * \var tprep pointer to the preparation timer struct + * \var tparity pointer to the parity timer struct + * \var toutput pointer to the output timer struct + * \var TBs array of TBs decoding parameters + */ +typedef struct nrLDPC_slot_encoding_parameters_s{ + int frame; + int slot; + int nb_TBs; + tpool_t *threadPool; + time_stats_t *tinput; + time_stats_t *tprep; + time_stats_t *tparity; + time_stats_t *toutput; + nrLDPC_TB_encoding_parameters_t *TBs; +} nrLDPC_slot_encoding_parameters_t; + +typedef int32_t(nrLDPC_coding_init_t)(void); +typedef int32_t(nrLDPC_coding_shutdown_t)(void); + +/** + * \brief slot decoding function interface + * \param nrLDPC_slot_decoding_parameters pointer to the structure holding the parameters necessary for decoding + */ +typedef int32_t(nrLDPC_coding_decoder_t)(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters); + +/** + * \brief slot encoding function interface + * \param nrLDPC_slot_encoding_parameters pointer to the structure holding the parameters necessary for encoding + */ +typedef int32_t(nrLDPC_coding_encoder_t)(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters); + +typedef struct nrLDPC_coding_interface_s { + nrLDPC_coding_init_t *nrLDPC_coding_init; + nrLDPC_coding_shutdown_t *nrLDPC_coding_shutdown; + nrLDPC_coding_decoder_t *nrLDPC_coding_decoder; + nrLDPC_coding_encoder_t *nrLDPC_coding_encoder; +} nrLDPC_coding_interface_t; + +int load_nrLDPC_coding_interface(char *version, nrLDPC_coding_interface_t *interface); +int free_nrLDPC_coding_interface(nrLDPC_coding_interface_t *interface); + +#endif diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface_load.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface_load.c new file mode 100644 index 0000000000..4819b68598 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface_load.c @@ -0,0 +1,74 @@ +/* + * 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 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface_load.c + * \brief load library implementing coding/decoding algorithms + */ + +#define _GNU_SOURCE +#include +#include +#include +#include "assertions.h" +#include "common/utils/LOG/log.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" +#include "PHY/CODING/nrLDPC_extern.h" +#include "common/config/config_userapi.h" +#include "common/utils/load_module_shlib.h" + +/* arguments used when called from phy simulators exec's which do not use the config module */ +/* arg is used to initialize the config module so that the loader works as expected */ +char *arguments_phy_simulators[64]={"ldpctest",NULL}; + +int load_nrLDPC_coding_interface(char *version, nrLDPC_coding_interface_t *itf) +{ + char *ptr = (char *)config_get_if(); + char libname[64] = "ldpc"; + + if (ptr == NULL) { // phy simulators, config module possibly not loaded + uniqCfg = load_configmodule(1, arguments_phy_simulators, CONFIG_ENABLECMDLINEONLY); + logInit(); + } + /* function description array, to be used when loading the encoding/decoding shared lib */ + loader_shlibfunc_t shlib_fdesc[] = {{.fname = "nrLDPC_coding_init"}, + {.fname = "nrLDPC_coding_shutdown"}, + {.fname = "nrLDPC_coding_decoder"}, + {.fname = "nrLDPC_coding_encoder"}}; + int ret; + ret = load_module_version_shlib(libname, version, shlib_fdesc, sizeofArray(shlib_fdesc), NULL); + if(ret < 0){ + LOG_D(PHY, "NR ULSCH decoding module unavailable"); + return ret; + } + itf->nrLDPC_coding_init = (nrLDPC_coding_init_t *)shlib_fdesc[0].fptr; + itf->nrLDPC_coding_shutdown = (nrLDPC_coding_shutdown_t *)shlib_fdesc[1].fptr; + itf->nrLDPC_coding_decoder = (nrLDPC_coding_decoder_t *)shlib_fdesc[2].fptr; + itf->nrLDPC_coding_encoder = (nrLDPC_coding_encoder_t *)shlib_fdesc[3].fptr; + + AssertFatal(itf->nrLDPC_coding_init() == 0, "error starting LDPC library %s %s\n", libname, version); + + return 0; +} + +int free_nrLDPC_coding_interface(nrLDPC_coding_interface_t *interface) +{ + return interface->nrLDPC_coding_shutdown(); +} From 7cfa4821077df77ff956bdb4b9e0989c2f79d230 Mon Sep 17 00:00:00 2001 From: "Madhuri.G" Date: Tue, 10 Dec 2024 17:33:19 +0530 Subject: [PATCH 37/83] Initial Context Setup Failure NGAP Failure message - Initial Context Setup Failure. When an Initial Context Setup Request is received with the UE context as null, it triggers Initial Context Setup failure. --- openair2/COMMON/ngap_messages_types.h | 7 +- openair2/RRC/NR/rrc_gNB_NGAP.c | 23 +++-- openair2/RRC/NR/rrc_gNB_NGAP.h | 5 ++ openair3/NGAP/ngap_gNB.c | 4 + openair3/NGAP/ngap_gNB_nas_procedures.c | 109 ++++++++++++++++++++++++ openair3/NGAP/ngap_gNB_nas_procedures.h | 2 + 6 files changed, 143 insertions(+), 7 deletions(-) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index 2ac5652a9f..c4d2cd011a 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -553,9 +553,12 @@ typedef struct ngap_initial_context_setup_resp_s { } ngap_initial_context_setup_resp_t; typedef struct ngap_initial_context_setup_fail_s { - uint32_t gNB_ue_ngap_id; + uint32_t gNB_ue_ngap_id; - /* TODO add cause */ + uint64_t amf_ue_ngap_id; + + ngap_Cause_t cause; + long cause_value; } ngap_initial_context_setup_fail_t, ngap_ue_ctxt_modification_fail_t, ngap_pdusession_setup_req_fail_t; typedef struct ngap_nas_non_delivery_ind_s { diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index bf71357aed..2d5ff73446 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -432,12 +432,11 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t if (ue_context_p == NULL) { /* Can not associate this message to an UE index, send a failure to NGAP and discard it! */ - MessageDef *msg_fail_p = NULL; LOG_W(NR_RRC, "[gNB %ld] In NGAP_INITIAL_CONTEXT_SETUP_REQ: unknown UE from NGAP ids (%u)\n", instance, req->gNB_ue_ngap_id); - msg_fail_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_INITIAL_CONTEXT_SETUP_FAIL); - NGAP_INITIAL_CONTEXT_SETUP_FAIL(msg_fail_p).gNB_ue_ngap_id = req->gNB_ue_ngap_id; - // TODO add failure cause when defined! - itti_send_msg_to_task(TASK_NGAP, instance, msg_fail_p); + rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_FAIL(req->gNB_ue_ngap_id, + NULL, + NGAP_CAUSE_RADIO_NETWORK, + NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_LOCAL_UE_NGAP_ID); return (-1); } gNB_RRC_INST *rrc = RC.nrrrc[instance]; @@ -542,6 +541,20 @@ void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_ itti_send_msg_to_task (TASK_NGAP, rrc->module_id, msg_p); } +void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_FAIL(uint32_t gnb, + const rrc_gNB_ue_context_t *const ue_context_pP, + const ngap_Cause_t causeP, + const long cause_valueP) +{ + MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_INITIAL_CONTEXT_SETUP_FAIL); + ngap_initial_context_setup_fail_t *fail = &NGAP_INITIAL_CONTEXT_SETUP_FAIL(msg_p); + memset(fail, 0, sizeof(*fail)); + fail->gNB_ue_ngap_id = gnb; + fail->cause = causeP; + fail->cause_value = cause_valueP; + itti_send_msg_to_task(TASK_NGAP, 0, msg_p); +} + static NR_CipheringAlgorithm_t rrc_gNB_select_ciphering(const gNB_RRC_INST *rrc, uint16_t algorithms) { int i; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.h b/openair2/RRC/NR/rrc_gNB_NGAP.h index 235a175954..0a0c976549 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.h +++ b/openair2/RRC/NR/rrc_gNB_NGAP.h @@ -46,6 +46,11 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE); +void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_FAIL(uint32_t gnb, + const rrc_gNB_ue_context_t *const ue_context_pP, + const ngap_Cause_t causeP, + const long cause_valueP); + int rrc_gNB_process_NGAP_DOWNLINK_NAS(MessageDef *msg_p, instance_t instance, mui_t *rrc_gNB_mui); void rrc_gNB_send_NGAP_UPLINK_NAS(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const NR_UL_DCCH_Message_t *const ul_dcch_msg); diff --git a/openair3/NGAP/ngap_gNB.c b/openair3/NGAP/ngap_gNB.c index 9c328c37c7..b60ac1c13c 100644 --- a/openair3/NGAP/ngap_gNB.c +++ b/openair3/NGAP/ngap_gNB.c @@ -328,6 +328,10 @@ void *ngap_gNB_process_itti_msg(void *notUsed) { ngap_gNB_initial_ctxt_resp(instance, &NGAP_INITIAL_CONTEXT_SETUP_RESP(received_msg)); break; + case NGAP_INITIAL_CONTEXT_SETUP_FAIL: + ngap_gNB_initial_ctxt_fail(instance, &NGAP_INITIAL_CONTEXT_SETUP_FAIL(received_msg)); + break; + case NGAP_PDUSESSION_SETUP_RESP: ngap_gNB_pdusession_setup_resp(instance, &NGAP_PDUSESSION_SETUP_RESP(received_msg)); break; diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 6cce5b695e..86ecd6eead 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -749,6 +749,115 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r return 0; } +//--------------------------------------------------------------------------------------------------------- +int ngap_gNB_initial_ctxt_fail(instance_t instance, ngap_initial_context_setup_fail_t *initial_ctxt_fail) +//--------------------------------------------------------------------------------------------------------- +{ + ngap_gNB_instance_t *ngap_gNB_instance_p = NULL; + struct ngap_gNB_ue_context_s *ue_context_p = NULL; + NGAP_NGAP_PDU_t pdu; + uint8_t *buffer = NULL; + uint32_t length; + + /* Retrieve the NGAP gNB instance associated with Mod_id */ + ngap_gNB_instance_p = ngap_gNB_get_instance(instance); + DevAssert(initial_ctxt_fail != NULL); + DevAssert(ngap_gNB_instance_p != NULL); + + if ((ue_context_p = ngap_get_ue_context(initial_ctxt_fail->gNB_ue_ngap_id)) == NULL) { + /* The context for this gNB ue ngap id doesn't exist in the map of gNB UEs */ + NGAP_WARN("Failed to find ue context associated with gNB ue ngap id: 0x%08x\n", initial_ctxt_fail->gNB_ue_ngap_id); + return -1; + } + /* Uplink NAS transport can occur either during an ngap connected state + * or during initial attach (for example: NAS authentication). + */ + if (!(ue_context_p->ue_state == NGAP_UE_CONNECTED || ue_context_p->ue_state == NGAP_UE_WAITING_CSR)) { + NGAP_WARN( + "You are attempting to send NAS data over non-connected " + "gNB ue ngap id: %08x, current state: %d\n", + initial_ctxt_fail->gNB_ue_ngap_id, + ue_context_p->ue_state); + return -1; + } + + /* Prepare the NGAP message to encode */ + memset(&pdu, 0, sizeof(pdu)); + pdu.present = NGAP_NGAP_PDU_PR_unsuccessfulOutcome; + asn1cCalloc(pdu.choice.unsuccessfulOutcome, out); + out->procedureCode = NGAP_ProcedureCode_id_InitialContextSetup; + out->criticality = NGAP_Criticality_reject; + out->value.present = NGAP_UnsuccessfulOutcome__value_PR_InitialContextSetupFailure; + NGAP_InitialContextSetupFailure_t *fail = &out->value.choice.InitialContextSetupFailure; + /* mandatory */ + { + asn1cSequenceAdd(fail->protocolIEs.list, NGAP_InitialContextSetupFailureIEs_t, ie); + ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = NGAP_InitialContextSetupFailureIEs__value_PR_AMF_UE_NGAP_ID; + // ie->value.choice.AMF_UE_NGAP_ID = ue_context_p->amf_ue_ngap_id; + asn_uint642INTEGER(&ie->value.choice.AMF_UE_NGAP_ID, ue_context_p->amf_ue_ngap_id); + } + /* mandatory */ + { + asn1cSequenceAdd(fail->protocolIEs.list, NGAP_InitialContextSetupFailureIEs_t, ie); + ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = NGAP_InitialContextSetupFailureIEs__value_PR_RAN_UE_NGAP_ID; + ie->value.choice.RAN_UE_NGAP_ID = initial_ctxt_fail->gNB_ue_ngap_id; + } + /* mandatory */ + { + asn1cSequenceAdd(fail->protocolIEs.list, NGAP_InitialContextSetupFailureIEs_t, ie); + ie->id = NGAP_ProtocolIE_ID_id_Cause; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = NGAP_InitialContextSetupFailureIEs__value_PR_Cause; + + switch (initial_ctxt_fail->cause) { + case NGAP_CAUSE_RADIO_NETWORK: + ie->value.choice.Cause.present = NGAP_Cause_PR_radioNetwork; + ie->value.choice.Cause.choice.radioNetwork = initial_ctxt_fail->cause_value; + break; + case NGAP_CAUSE_TRANSPORT: + ie->value.choice.Cause.present = NGAP_Cause_PR_transport; + ie->value.choice.Cause.choice.transport = initial_ctxt_fail->cause_value; + break; + case NGAP_CAUSE_NAS: + ie->value.choice.Cause.present = NGAP_Cause_PR_nas; + ie->value.choice.Cause.choice.nas = initial_ctxt_fail->cause_value; + break; + case NGAP_CAUSE_PROTOCOL: + ie->value.choice.Cause.present = NGAP_Cause_PR_protocol; + ie->value.choice.Cause.choice.protocol = initial_ctxt_fail->cause_value; + break; + case NGAP_CAUSE_MISC: + ie->value.choice.Cause.present = NGAP_Cause_PR_misc; + ie->value.choice.Cause.choice.misc = initial_ctxt_fail->cause_value; + break; + case NGAP_CAUSE_NOTHING: + default: + AssertFatal(false, "Unknown NGAP Initial Context Setup failure cause %d\n", initial_ctxt_fail->cause); + break; + } + } + if (asn1_xer_print) { + xer_fprint(stdout, &asn_DEF_NGAP_NGAP_PDU, &pdu); + } + if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { + NGAP_ERROR("Failed to encode InitialContextSetupFailure\n"); + /* Encode procedure has failed... */ + return -1; + } + /* UE associated signalling -> use the allocated stream */ + LOG_I(NR_RRC, "Send message to sctp: NGAP_InitialContextSetupFailure\n"); + ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, + ue_context_p->amf_ref->assoc_id, + buffer, + length, + ue_context_p->tx_stream); + return 0; +} + //------------------------------------------------------------------------------ int ngap_gNB_ue_capabilities(instance_t instance, ngap_ue_cap_info_ind_t *ue_cap_info_ind_p) //------------------------------------------------------------------------------ diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.h b/openair3/NGAP/ngap_gNB_nas_procedures.h index f977bf3a69..3cd03838b4 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.h +++ b/openair3/NGAP/ngap_gNB_nas_procedures.h @@ -49,6 +49,8 @@ int ngap_gNB_handle_nas_first_req( int ngap_gNB_initial_ctxt_resp( instance_t instance, ngap_initial_context_setup_resp_t *initial_ctxt_resp_p); +int ngap_gNB_initial_ctxt_fail(instance_t instance, ngap_initial_context_setup_fail_t *initial_ctxt_fail); + int ngap_gNB_ue_capabilities(instance_t instance, ngap_ue_cap_info_ind_t *ue_cap_info_ind_p); From 00e1ad124d452b089d2a21de692041bffd29df23 Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Wed, 30 Oct 2024 14:38:04 +0100 Subject: [PATCH 38/83] feat(nrLDPC_coding_interface): Use reworked interface in gNB --- executables/nr-gnb.c | 1 - executables/softmodem-common.h | 2 - openair1/PHY/INIT/nr_init.c | 13 +- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 104 +++- openair1/PHY/NR_TRANSPORT/nr_dlsch.h | 24 +- openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 424 ++++++-------- openair1/PHY/NR_TRANSPORT/nr_ulsch.h | 21 +- openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c | 534 +++++++----------- openair1/PHY/defs_gNB.h | 6 +- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 274 ++++----- 10 files changed, 580 insertions(+), 823 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 4206cfd585..4636395f65 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -403,7 +403,6 @@ void init_eNB_afterRU(void) { for (inst=0; instldpc_offload_flag = get_softmodem_params()->ldpc_offload_flag; phy_init_nr_gNB(gNB); diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h index 5c8e032d5e..022f9add0a 100644 --- a/executables/softmodem-common.h +++ b/executables/softmodem-common.h @@ -142,7 +142,6 @@ extern "C" #define EMULATE_L1 softmodem_params.emulate_l1 #define CONTINUOUS_TX softmodem_params.continuous_tx #define SYNC_REF softmodem_params.sync_ref -#define LDPC_OFFLOAD_FLAG softmodem_params.ldpc_offload_flag #define DEFAULT_RFCONFIG_FILE "/usr/local/etc/syriq/ue.band7.tm1.PRB100.NR40.dat"; @@ -321,7 +320,6 @@ typedef struct { int continuous_tx; uint32_t sync_ref; int no_itti; - int ldpc_offload_flag; int threequarter_fs; } softmodem_params_t; diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index e723b3a330..07cdca7692 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -26,6 +26,7 @@ #include "PHY/defs_gNB.h" #include "PHY/NR_REFSIG/nr_refsig.h" #include "PHY/INIT/nr_phy_init.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" #include "PHY/CODING/nrPolar_tools/nr_polar_pbch_defs.h" #include "PHY/NR_TRANSPORT/nr_transport_proto.h" #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" @@ -40,6 +41,7 @@ #include "PHY/NR_REFSIG/nr_refsig.h" #include "SCHED_NR/fapi_nr_l1.h" #include "PHY/NR_REFSIG/ul_ref_seq_nr.h" +#include int l1_north_init_gNB() { @@ -96,9 +98,6 @@ void reset_active_stats(PHY_VARS_gNB *gNB, int frame) } } -// A global var to reduce the changes size -ldpc_interface_t ldpc_interface = {0}, ldpc_interface_offload = {0}; - void phy_init_nr_gNB(PHY_VARS_gNB *gNB) { // shortcuts @@ -134,15 +133,11 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB) nr_init_fde(); // Init array for frequency equalization of transform precoding of PUSCH - load_LDPClib(NULL, &ldpc_interface); + int ret_loader = load_nrLDPC_coding_interface(NULL, &gNB->nrLDPC_coding_interface); + AssertFatal(ret_loader == 0, "error loading LDPC library\n"); pthread_mutex_init(&gNB->UL_INFO.crc_rx_mutex, NULL); - if (gNB->ldpc_offload_flag) - load_LDPClib("_t2", &ldpc_interface_offload); - else - load_LDPClib(NULL, &ldpc_interface); - gNB->max_nb_pdsch = MAX_MOBILES_PER_GNB; init_delay_table(fp->ofdm_symbol_size, MAX_DELAY_COMP, NR_MAX_OFDM_SYMBOL_SIZE, fp->delay_table); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index e69e6b2f89..1202774798 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -65,6 +65,67 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) time_stats_t *dlsch_interleaving_stats=&gNB->dlsch_interleaving_stats; time_stats_t *dlsch_segmentation_stats=&gNB->dlsch_segmentation_stats; + size_t size_output = 0; + + for (int dlsch_id=0; dlsch_idnum_pdsch_slot; dlsch_id++) { + NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id]; + NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; + + LOG_D(PHY,"pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbsize %d\n", + rel15->BWPStart,rel15->BWPSize,rel15->rbStart,rel15->rbSize); + + const int Qm = rel15->qamModOrder[0]; + + /* PTRS */ + uint16_t dlPtrsSymPos = 0; + int n_ptrs = 0; + uint32_t ptrsSymbPerSlot = 0; + if(rel15->pduBitmap & 0x1) { + set_ptrs_symb_idx(&dlPtrsSymPos, + rel15->NrOfSymbols, + rel15->StartSymbolIndex, + 1 << rel15->PTRSTimeDensity, + rel15->dlDmrsSymbPos); + n_ptrs = (rel15->rbSize + rel15->PTRSFreqDensity - 1) / rel15->PTRSFreqDensity; + ptrsSymbPerSlot = get_ptrs_symbols_in_slot(dlPtrsSymPos, rel15->StartSymbolIndex, rel15->NrOfSymbols); + } + harq->unav_res = ptrsSymbPerSlot * n_ptrs; + + /// CRC, coding, interleaving and rate matching + AssertFatal(harq->pdu!=NULL,"harq->pdu is null\n"); + + /* output and its parts for each dlsch should be aligned on 64 bytes + * => size_output is a sum of parts sizes rounded up to a multiple of 64 + */ + size_t size_output_tb = rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers; + size_output += (size_output_tb + 63 - ((size_output_tb + 63) % 64)); + } + + unsigned char output[size_output] __attribute__((aligned(64))); + + bzero(output, size_output); + + size_t offset_output = 0; + + start_meas(dlsch_encoding_stats); + if (nr_dlsch_encoding(gNB, + msgTx, + frame, + slot, + frame_parms, + output, + tinput, + tprep, + tparity, + toutput, + dlsch_rate_matching_stats, + dlsch_interleaving_stats, + dlsch_segmentation_stats) == -1) { + return; + } + stop_meas(dlsch_encoding_stats); + for (int dlsch_id=0; dlsch_idnum_pdsch_slot; dlsch_id++) { NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id]; @@ -100,45 +161,24 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) } harq->unav_res = ptrsSymbPerSlot * n_ptrs; - /// CRC, coding, interleaving and rate matching - AssertFatal(harq->pdu!=NULL,"harq->pdu is null\n"); - unsigned char output[rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers] __attribute__((aligned(64))); - bzero(output,rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers); - start_meas(dlsch_encoding_stats); - - if (nr_dlsch_encoding(gNB, - frame, - slot, - harq, - frame_parms, - output, - tinput, - tprep, - tparity, - toutput, - dlsch_rate_matching_stats, - dlsch_interleaving_stats, - dlsch_segmentation_stats) == -1) - return; - stop_meas(dlsch_encoding_stats); #ifdef DEBUG_DLSCH printf("PDSCH encoding:\nPayload:\n"); - for (int i=0; iB>>7; i++) { - for (int j=0; j<16; j++) - printf("0x%02x\t", harq->pdu[(i<<4)+j]); + for (int i = 0; i < (harq->B>>3); i += 16) { + for (int j=0; j < 16; j++) + printf("0x%02x\t", harq->pdu[i + j]); printf("\n"); } printf("\nEncoded payload:\n"); - for (int i=0; i>3; i++) { - for (int j=0; j<8; j++) - printf("%d", output[(i<<3)+j]); + for (int i = 0; i < encoded_length; i += 8) { + for (int j = 0; j < 8; j++) + printf("%d", output[offset_output + i + j]); printf("\t"); } printf("\n"); #endif if (IS_SOFTMODEM_DLSIM) - memcpy(harq->f, output, encoded_length); + memcpy(harq->f, &output[offset_output], encoded_length); c16_t mod_symbs[rel15->NrOfCodewords][encoded_length]; for (int codeWord = 0; codeWord < rel15->NrOfCodewords; codeWord++) { @@ -147,7 +187,7 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) uint32_t scrambled_output[(encoded_length>>5)+4]; // modulator acces by 4 bytes in some cases memset(scrambled_output, 0, sizeof(scrambled_output)); if ( encoded_length > rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers) abort(); - nr_pdsch_codeword_scrambling(output, encoded_length, codeWord, rel15->dataScramblingId, rel15->rnti, scrambled_output); + nr_pdsch_codeword_scrambling(&output[offset_output], encoded_length, codeWord, rel15->dataScramblingId, rel15->rnti, scrambled_output); #ifdef DEBUG_DLSCH printf("PDSCH scrambling:\n"); @@ -176,6 +216,12 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) } /// Resource mapping + /* output and its parts for each dlsch should be aligned on 64 bytes + * => offset_output should remain a multiple of 64 with enough offset to fit each dlsch + */ + uint32_t size_output_tb = rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers; + offset_output += (size_output_tb + 63) & ~63; + // Non interleaved VRB to PRB mapping uint16_t start_sc = frame_parms->first_carrier_offset + (rel15->rbStart+rel15->BWPStart)*NR_NB_SC_PER_RB; if (start_sc >= frame_parms->ofdm_symbol_size) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.h b/openair1/PHY/NR_TRANSPORT/nr_dlsch.h index 17bfe2878a..53e0c17065 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.h +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.h @@ -44,18 +44,18 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int slot); int nr_dlsch_encoding(PHY_VARS_gNB *gNB, - int frame, - uint8_t slot, - NR_DL_gNB_HARQ_t *harq, - NR_DL_FRAME_PARMS* frame_parms, - unsigned char * output, - time_stats_t *tinput, - time_stats_t *tprep, - time_stats_t *tparity, - time_stats_t *toutput, - time_stats_t *dlsch_rate_matching_stats, - time_stats_t *dlsch_interleaving_stats, - time_stats_t *dlsch_segmentation_stats); + processingData_L1tx_t *msgTx, + int frame, + uint8_t slot, + NR_DL_FRAME_PARMS *frame_parms, + unsigned char *output, + time_stats_t *tinput, + time_stats_t *tprep, + time_stats_t *tparity, + time_stats_t *toutput, + time_stats_t *dlsch_rate_matching_stats, + time_stats_t *dlsch_interleaving_stats, + time_stats_t *dlsch_segmentation_stats); void nr_emulate_dlsch_payload(uint8_t* payload, uint16_t size); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index b66b785b7d..33ecfb3737 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -19,21 +19,15 @@ * contact@openairinterface.org */ -/*! \file PHY/LTE_TRANSPORT/dlsch_coding.c +/*! \file PHY/NR_TRANSPORT/nr_dlsch_coding_slot.c * \brief Top-level routines for implementing LDPC-coded (DLSCH) transport channels from 38-212, 15.2 -* \author H.Wang -* \date 2018 -* \version 0.1 -* \company Eurecom -* \email: -* \note -* \warning */ #include "PHY/defs_gNB.h" #include "PHY/CODING/coding_extern.h" #include "PHY/CODING/coding_defs.h" #include "PHY/CODING/lte_interleaver_inline.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" #include "PHY/CODING/nrLDPC_extern.h" #include "PHY/NR_TRANSPORT/nr_transport_proto.h" #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" @@ -117,130 +111,10 @@ NR_gNB_DLSCH_t new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, uint16_t N_RB) return(dlsch); } -static void ldpc8blocks(void *p) -{ - encoder_implemparams_t *impp=(encoder_implemparams_t *) p; - NR_DL_gNB_HARQ_t *harq = (NR_DL_gNB_HARQ_t *)impp->harq; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; - uint8_t mod_order = rel15->qamModOrder[0]; - uint16_t nb_rb = rel15->rbSize; - uint8_t nb_symb_sch = rel15->NrOfSymbols; - uint16_t length_dmrs = get_num_dmrs(rel15->dlDmrsSymbPos); - uint32_t A = rel15->TBSize[0]<<3; - uint8_t nb_re_dmrs; - - if (rel15->dmrsConfigType==NFAPI_NR_DMRS_TYPE1) - nb_re_dmrs = 6*rel15->numDmrsCdmGrpsNoData; - else - nb_re_dmrs = 4*rel15->numDmrsCdmGrpsNoData; - - unsigned int G = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, harq->unav_res, mod_order, rel15->nrOfLayers); - LOG_D(PHY,"dlsch coding A %d Kr %d G %d (nb_rb %d, nb_symb_sch %d, nb_re_dmrs %d, length_dmrs %d, mod_order %d)\n", - A,impp->K,G, nb_rb,nb_symb_sch,nb_re_dmrs,length_dmrs,(int)mod_order); - // nrLDPC_encoder output is in "d" - // let's make this interface happy! - uint8_t tmp[8][68 * 384]__attribute__((aligned(32))); - uint8_t *d[impp->n_segments]; - for (int rr=impp->macro_num*8, i=0; rr < impp->n_segments && rr < (impp->macro_num+1)*8; rr++,i++ ) - d[rr] = tmp[i]; - ldpc_interface.LDPCencoder(harq->c, d, impp); - // Compute where to place in output buffer that is concatenation of all segments - uint32_t r_offset=0; - for (int i=0; i < impp->macro_num*8; i++ ) - r_offset+=nr_get_E(G, impp->n_segments, mod_order, rel15->nrOfLayers, i); - for (int rr=impp->macro_num*8; rr < impp->n_segments && rr < (impp->macro_num+1)*8; rr++ ) { - if (impp->F>0) { - // writing into positions d[r][k-2Zc] as in clause 5.3.2 step 2) in 38.212 - memset(&d[rr][impp->K - impp->F - 2 * impp->Zc], NR_NULL, impp->F); - } - -#ifdef DEBUG_DLSCH_CODING - LOG_D(PHY,"rvidx in encoding = %d\n", rel15->rvIndex[0]); -#endif - uint32_t E = nr_get_E(G, impp->n_segments, mod_order, rel15->nrOfLayers, rr); - //#ifdef DEBUG_DLSCH_CODING - LOG_D(NR_PHY, - "Rate Matching, Code segment %d/%d (coded bits (G) %u, E %d, Filler bits %d, Filler offset %d mod_order %d, nb_rb " - "%d,nrOfLayer %d)...\n", - rr, - impp->n_segments, - G, - E, - impp->F, - impp->K - impp->F - 2 * impp->Zc, - mod_order, - nb_rb, - rel15->nrOfLayers); - - uint32_t Tbslbrm = rel15->maintenance_parms_v3.tbSizeLbrmBytes; - - uint8_t e[E]; - bzero (e, E); - nr_rate_matching_ldpc(Tbslbrm, - impp->BG, - impp->Zc, - d[rr], - e, - impp->n_segments, - impp->F, - impp->K - impp->F - 2 * impp->Zc, - rel15->rvIndex[0], - E); - if (impp->K - impp->F - 2 * impp->Zc > E) { - LOG_E(PHY, - "dlsch coding A %d Kr %d G %d (nb_rb %d, nb_symb_sch %d, nb_re_dmrs %d, length_dmrs %d, mod_order %d)\n", - A, - impp->K, - G, - nb_rb, - nb_symb_sch, - nb_re_dmrs, - length_dmrs, - (int)mod_order); - - LOG_E(NR_PHY, - "Rate Matching, Code segment %d/%d (coded bits (G) %u, E %d, Kr %d, Filler bits %d, Filler offset %d mod_order %d, " - "nb_rb %d)...\n", - rr, - impp->n_segments, - G, - E, - impp->K, - impp->F, - impp->K - impp->F - 2 * impp->Zc, - mod_order, - nb_rb); - } -#ifdef DEBUG_DLSCH_CODING - - for (int i =0; i<16; i++) - printf("output ratematching e[%d]= %d r_offset %u\n", i,e[i], r_offset); - -#endif - nr_interleaving_ldpc(E, - mod_order, - e, - impp->output+r_offset); -#ifdef DEBUG_DLSCH_CODING - - for (int i =0; i<16; i++) - printf("output interleaving f[%d]= %d r_offset %u\n", i,impp->output[i+r_offset], r_offset); - - if (r==impp->n_segments-1) - write_output("enc_output.m","enc",impp->output,G,1,4); - -#endif - r_offset += E; - } - - // Task running in // completed - completed_task_ans(impp->ans); -} - int nr_dlsch_encoding(PHY_VARS_gNB *gNB, + processingData_L1tx_t *msgTx, int frame, uint8_t slot, - NR_DL_gNB_HARQ_t *harq, NR_DL_FRAME_PARMS *frame_parms, unsigned char *output, time_stats_t *tinput, @@ -251,145 +125,195 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, time_stats_t *dlsch_interleaving_stats, time_stats_t *dlsch_segmentation_stats) { - encoder_implemparams_t impp; - impp.output=output; - unsigned int crc=1; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; - impp.Zc = harq->Z; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ENCODING, VCD_FUNCTION_IN); - uint32_t A = rel15->TBSize[0]<<3; - unsigned char *a=harq->pdu; - if (rel15->rnti != SI_RNTI) { - ws_trace_t tmp = {.nr = true, - .direction = DIRECTION_DOWNLINK, - .pdu_buffer = a, - .pdu_buffer_size = rel15->TBSize[0], - .ueid = 0, - .rntiType = WS_C_RNTI, - .rnti = rel15->rnti, - .sysFrame = frame, - .subframe = slot, - .harq_pid = 0, // difficult to find the harq pid here - .oob_event = 0, - .oob_event_value = 0}; - trace_pdu(&tmp); - } - NR_gNB_PHY_STATS_t *phy_stats = NULL; - if (rel15->rnti != 0xFFFF) - phy_stats = get_phy_stats(gNB, rel15->rnti); + nrLDPC_TB_encoding_parameters_t TBs[msgTx->num_pdsch_slot]; + memset(TBs, 0, sizeof(TBs)); + nrLDPC_slot_encoding_parameters_t slot_parameters = { + .frame = frame, + .slot = slot, + .nb_TBs = msgTx->num_pdsch_slot, + .threadPool = &gNB->threadPool, + .tinput = tinput, + .tprep = tprep, + .tparity = tparity, + .toutput = toutput, + .TBs = TBs + }; - if (phy_stats) { - phy_stats->frame = frame; - phy_stats->dlsch_stats.total_bytes_tx += rel15->TBSize[0]; - phy_stats->dlsch_stats.current_RI = rel15->nrOfLayers; - phy_stats->dlsch_stats.current_Qm = rel15->qamModOrder[0]; - } + int num_segments = 0; - int max_bytes = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER*rel15->nrOfLayers*1056; - int B; - if (A > NR_MAX_PDSCH_TBS) { - // Add 24-bit crc (polynomial A) to payload - crc = crc24a(a,A)>>8; - a[A>>3] = ((uint8_t *)&crc)[2]; - a[1+(A>>3)] = ((uint8_t *)&crc)[1]; - a[2+(A>>3)] = ((uint8_t *)&crc)[0]; - //printf("CRC %x (A %d)\n",crc,A); - //printf("a0 %d a1 %d a2 %d\n", a[A>>3], a[1+(A>>3)], a[2+(A>>3)]); - B = A + 24; - // harq->b = a; - AssertFatal((A / 8) + 4 <= max_bytes, - "A %d is too big (A/8+4 = %d > %d)\n", - A, - (A / 8) + 4, - max_bytes); - memcpy(harq->b, a, (A / 8) + 4); // why is this +4 if the CRC is only 3 bytes? - } else { - // Add 16-bit crc (polynomial A) to payload - crc = crc16(a,A)>>16; - a[A>>3] = ((uint8_t *)&crc)[1]; - a[1+(A>>3)] = ((uint8_t *)&crc)[0]; - //printf("CRC %x (A %d)\n",crc,A); - //printf("a0 %d a1 %d \n", a[A>>3], a[1+(A>>3)]); - B = A + 16; - // harq->b = a; - AssertFatal((A / 8) + 3 <= max_bytes, - "A %d is too big (A/8+3 = %d > %d)\n", - A, - (A / 8) + 3, - max_bytes); - memcpy(harq->b, a, (A / 8) + 3); // using 3 bytes to mimic the case of 24 bit crc - } + for (int dlsch_id=0; dlsch_idnum_pdsch_slot; dlsch_id++) { - impp.BG = rel15->maintenance_parms_v3.ldpcBaseGraph; + NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id]; - start_meas(dlsch_segmentation_stats); - impp.Kb = nr_segmentation(harq->b, harq->c, B, &impp.n_segments, &impp.K, &impp.Zc, &impp.F, impp.BG); - stop_meas(dlsch_segmentation_stats); - - if (impp.n_segments>MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER*rel15->nrOfLayers) { - LOG_E(PHY, "nr_segmentation.c: too many segments %d, B %d\n", impp.n_segments, B); - return(-1); - } - for (int r=0; rd[r][0]; - //channel_input[r] = &harq->d[r][0]; -#ifdef DEBUG_DLSCH_CODING - LOG_D(PHY,"Encoder: B %d F %d \n",harq->B, impp.F); - LOG_D(PHY,"start ldpc encoder segment %d/%d\n",r,impp.n_segments); - LOG_D(PHY,"input %d %d %d %d %d \n", harq->c[r][0], harq->c[r][1], harq->c[r][2],harq->c[r][3], harq->c[r][4]); - - for (int cnt =0 ; cnt < 22*(*impp.Zc)/8; cnt ++) { - LOG_D(PHY,"%d ", harq->c[r][cnt]); + NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; + unsigned int crc=1; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; + uint32_t A = rel15->TBSize[0]<<3; + unsigned char *a=harq->pdu; + if (rel15->rnti != SI_RNTI) { + ws_trace_t tmp = {.nr = true, + .direction = DIRECTION_DOWNLINK, + .pdu_buffer = a, + .pdu_buffer_size = rel15->TBSize[0], + .ueid = 0, + .rntiType = WS_C_RNTI, + .rnti = rel15->rnti, + .sysFrame = frame, + .subframe = slot, + .harq_pid = 0, // difficult to find the harq pid here + .oob_event = 0, + .oob_event_value = 0}; + trace_pdu(&tmp); } - LOG_D(PHY,"\n"); -#endif - //ldpc_encoder_orig((unsigned char*)harq->c[r],harq->d[r],*Zc,Kb,Kr,BG,0); - //ldpc_encoder_optim((unsigned char*)harq->c[r],(unsigned char*)&harq->d[r][0],*Zc,Kb,Kr,BG,NULL,NULL,NULL,NULL); + NR_gNB_PHY_STATS_t *phy_stats = NULL; + if (rel15->rnti != 0xFFFF) + phy_stats = get_phy_stats(gNB, rel15->rnti); + + if (phy_stats) { + phy_stats->frame = frame; + phy_stats->dlsch_stats.total_bytes_tx += rel15->TBSize[0]; + phy_stats->dlsch_stats.current_RI = rel15->nrOfLayers; + phy_stats->dlsch_stats.current_Qm = rel15->qamModOrder[0]; + } + + int max_bytes = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER*rel15->nrOfLayers*1056; + int B; + if (A > NR_MAX_PDSCH_TBS) { + // Add 24-bit crc (polynomial A) to payload + crc = crc24a(a,A)>>8; + a[A>>3] = ((uint8_t *)&crc)[2]; + a[1+(A>>3)] = ((uint8_t *)&crc)[1]; + a[2+(A>>3)] = ((uint8_t *)&crc)[0]; + //printf("CRC %x (A %d)\n",crc,A); + //printf("a0 %d a1 %d a2 %d\n", a[A>>3], a[1+(A>>3)], a[2+(A>>3)]); + B = A + 24; + // harq->b = a; + AssertFatal((A / 8) + 4 <= max_bytes, + "A %d is too big (A/8+4 = %d > %d)\n", + A, + (A / 8) + 4, + max_bytes); + memcpy(harq->b, a, (A / 8) + 4); // why is this +4 if the CRC is only 3 bytes? + } else { + // Add 16-bit crc (polynomial A) to payload + crc = crc16(a,A)>>16; + a[A>>3] = ((uint8_t *)&crc)[1]; + a[1+(A>>3)] = ((uint8_t *)&crc)[0]; + //printf("CRC %x (A %d)\n",crc,A); + //printf("a0 %d a1 %d \n", a[A>>3], a[1+(A>>3)]); + B = A + 16; + // harq->b = a; + AssertFatal((A / 8) + 3 <= max_bytes, + "A %d is too big (A/8+3 = %d > %d)\n", + A, + (A / 8) + 3, + max_bytes); + memcpy(harq->b, a, (A / 8) + 3); // using 3 bytes to mimic the case of 24 bit crc + } + + nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[dlsch_id]; + + // The harq_pid is not unique among the active HARQ processes in the instance so we use dlsch_id instead + TB_parameters->harq_unique_pid = dlsch_id; + TB_parameters->BG = rel15->maintenance_parms_v3.ldpcBaseGraph; + TB_parameters->Z = harq->Z; + TB_parameters->A = A; + start_meas(dlsch_segmentation_stats); + TB_parameters->Kb = nr_segmentation(harq->b, + harq->c, + B, + &TB_parameters->C, + &TB_parameters->K, + &TB_parameters->Z, + &TB_parameters->F, + TB_parameters->BG); + stop_meas(dlsch_segmentation_stats); + + if (TB_parameters->C>MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER*rel15->nrOfLayers) { + LOG_E(PHY, "nr_segmentation.c: too many segments %d, B %d\n", TB_parameters->C, B); + return(-1); + } + num_segments += TB_parameters->C; + } - impp.tprep = tprep; - impp.tinput = tinput; - impp.tparity = tparity; - impp.toutput = toutput; - impp.harq = harq; - if (gNB->ldpc_offload_flag) { - impp.Qm = rel15->qamModOrder[0]; - impp.Tbslbrm = rel15->maintenance_parms_v3.tbSizeLbrmBytes; - impp.rv = rel15->rvIndex[0]; + nrLDPC_segment_encoding_parameters_t segments[num_segments]; + memset(segments, 0, sizeof(segments)); + size_t segments_offset = 0; + size_t dlsch_offset = 0; + + for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { + NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id]; + NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; + + nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[dlsch_id]; + +#ifdef DEBUG_DLSCH_CODING + for (int r = 0; r < TB_parameters->C; r++) { + LOG_D(PHY, "Encoder: B %d F %d \n", harq->B, TB_parameters->F); + LOG_D(PHY, "start ldpc encoder segment %d/%d\n", r, TB_parameters->C); + LOG_D(PHY, "input %d %d %d %d %d \n", harq->c[r][0], harq->c[r][1], harq->c[r][2], harq->c[r][3], harq->c[r][4]); + for (int cnt = 0; cnt < 22 * (TB_parameters->Z) / 8; cnt++) { + LOG_D(PHY, "%d ", harq->c[r][cnt]); + } + LOG_D(PHY, "\n"); + } +#endif + + TB_parameters->nb_rb = rel15->rbSize; + TB_parameters->Qm = rel15->qamModOrder[0]; + TB_parameters->mcs = rel15->mcsIndex[0]; + TB_parameters->nb_layers = rel15->nrOfLayers; + TB_parameters->rv_index = rel15->rvIndex[0]; + int nb_re_dmrs = (rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1) ? (6 * rel15->numDmrsCdmGrpsNoData) : (4 * rel15->numDmrsCdmGrpsNoData); - impp.G = nr_get_G(rel15->rbSize, - rel15->NrOfSymbols, - nb_re_dmrs, - get_num_dmrs(rel15->dlDmrsSymbPos), - harq->unav_res, - rel15->qamModOrder[0], - rel15->nrOfLayers); - for (int r = 0; r < impp.n_segments; r++) { - impp.perCB[r].E_cb = nr_get_E(impp.G, impp.n_segments, impp.Qm, rel15->nrOfLayers, r); - } - ldpc_interface_offload.LDPCencoder(harq->c, &impp.output, &impp); - } else { - size_t const n_seg = (impp.n_segments / 8 + ((impp.n_segments & 7) == 0 ? 0 : 1)); + TB_parameters->G = nr_get_G(rel15->rbSize, + rel15->NrOfSymbols, + nb_re_dmrs, + get_num_dmrs(rel15->dlDmrsSymbPos), + harq->unav_res, + rel15->qamModOrder[0], + rel15->nrOfLayers); - encoder_implemparams_t arr[n_seg]; - task_ans_t ans[n_seg]; - memset(ans, 0, n_seg * sizeof(task_ans_t)); + TB_parameters->tbslbrm = rel15->maintenance_parms_v3.tbSizeLbrmBytes; - for (int j = 0; j < n_seg; j++) { - encoder_implemparams_t *perJobImpp = &arr[j]; - *perJobImpp = impp; - perJobImpp->macro_num = j; - perJobImpp->ans = &ans[j]; + TB_parameters->segments = &segments[segments_offset]; + + size_t r_offset = 0; + for (int r = 0; r < TB_parameters->C; r++) { + nrLDPC_segment_encoding_parameters_t *segment_parameters = &TB_parameters->segments[r]; + segment_parameters->c = harq->c[r]; + segment_parameters->E = nr_get_E(TB_parameters->G, + TB_parameters->C, + TB_parameters->Qm, + rel15->nrOfLayers, + r); + segment_parameters->output = &output[dlsch_offset + r_offset]; + r_offset += segment_parameters->E; + + reset_meas(&segment_parameters->ts_interleave); + reset_meas(&segment_parameters->ts_rate_match); + reset_meas(&segment_parameters->ts_ldpc_encode); - task_t t = {.func = ldpc8blocks, .args = perJobImpp}; - pushTpool(&gNB->threadPool, t); } - join_task_ans(ans, n_seg); + segments_offset += TB_parameters->C; + + /* output and its parts for each dlsch should be aligned on 64 bytes + * => dlsch_offset should remain a multiple of 64 with enough offset to fit each dlsch + */ + const size_t dlsch_size = rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * rel15->qamModOrder[0] * rel15->nrOfLayers; + dlsch_offset += (dlsch_size + 63 - ((dlsch_size + 63) % 64)); } + + gNB->nrLDPC_coding_interface.nrLDPC_coding_encoder(&slot_parameters); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ENCODING, VCD_FUNCTION_OUT); return 0; } diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.h b/openair1/PHY/NR_TRANSPORT/nr_ulsch.h index f771d9050a..95474f64c0 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.h +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.h @@ -42,28 +42,23 @@ void free_gNB_ulsch(NR_gNB_ULSCH_t *ulsch, uint16_t N_RB_UL); NR_gNB_ULSCH_t new_gNB_ulsch(uint8_t max_ldpc_iterations, uint16_t N_RB_UL); -/*! \brief Perform PUSCH decoding. TS 38.212 V15.4.0 subclause 6.2 +/*! \brief Perform PUSCH decoding for the whole current received TTI. TS 38.212 V15.4.0 subclause 6.2 @param phy_vars_gNB, Pointer to PHY data structure for gNB - @param UE_id, ID of UE transmitting this PUSCH - @param ulsch_llr, Pointer to received llr in ulsch @param frame_parms, Pointer to frame descriptor structure - @param nb_symb_sch, number of symbols used in the uplink shared channel - @param nb_re_dmrs, number of DMRS resource elements in one RB + @param frame, current received frame @param nr_tti_rx, current received TTI - @param harq_pid, harq process id - @param is_crnti + @param G + @param ULSCH_ids, array of ULSCH ids + @param nb_pusch, number of uplink shared channels */ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, - uint8_t UE_id, - short *ulsch_llr, NR_DL_FRAME_PARMS *frame_parms, - nfapi_nr_pusch_pdu_t *pusch_pdu, uint32_t frame, uint8_t nr_tti_rx, - uint8_t harq_pid, - uint32_t G, - thread_info_tm_t *t_info); + uint32_t *G, + uint8_t *ULSCH_ids, + int nb_pusch); /*! \brief Perform PUSCH unscrambling. TS 38.211 V15.4.0 subclause 6.3.1.1 @param llr, Pointer to llr bits diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index 55c32b48d2..c61898e9bb 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -19,15 +19,8 @@ * contact@openairinterface.org */ -/*! \file PHY/NR_TRANSPORT/nr_ulsch_decoding.c +/*! \file PHY/NR_TRANSPORT/nr_ulsch_decoding_slot.c * \brief Top-level routines for decoding LDPC (ULSCH) transport channels from 38.212, V15.4.0 2018-12 -* \author Ahmed Hussein -* \date 2019 -* \version 0.1 -* \company Fraunhofer IIS -* \email: ahmed.hussein@iis.fraunhofer.de -* \note -* \warning */ @@ -36,6 +29,7 @@ #include "PHY/CODING/coding_extern.h" #include "PHY/CODING/coding_defs.h" #include "PHY/CODING/lte_interleaver_inline.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" #include "PHY/CODING/nrLDPC_extern.h" #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" #include "PHY/NR_TRANSPORT/nr_transport_proto.h" @@ -50,10 +44,6 @@ //#define DEBUG_ULSCH_DECODING //#define gNB_DEBUG_TRACE -#include -#include -#include - #define OAI_UL_LDPC_MAX_NUM_LLR 27000//26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX = 68*384 //#define DEBUG_CRC #ifdef DEBUG_CRC @@ -123,361 +113,215 @@ NR_gNB_ULSCH_t new_gNB_ulsch(uint8_t max_ldpc_iterations, uint16_t N_RB_UL) return(ulsch); } -static void nr_processULSegment(void *arg) -{ - ldpcDecode_t *rdata = (ldpcDecode_t *)arg; - NR_UL_gNB_HARQ_t *ulsch_harq = rdata->ulsch_harq; - t_nrLDPC_dec_params *p_decoderParms = &rdata->decoderParms; - const int Kr = ulsch_harq->K; - const int Kr_bytes = Kr >> 3; - const int K_bits_F = Kr - ulsch_harq->F; - const int r = rdata->segment_r; - const int A = rdata->A; - const int E = rdata->E; - const int Qm = rdata->Qm; - const int rv_index = rdata->rv_index; - const int r_offset = rdata->r_offset; - const uint8_t kc = rdata->Kc; - short *ulsch_llr = rdata->ulsch_llr; - const int max_ldpc_iterations = p_decoderParms->numMaxIter; - int8_t llrProcBuf[OAI_UL_LDPC_MAX_NUM_LLR] __attribute__((aligned(32))); - - t_nrLDPC_time_stats procTime = {0}; - t_nrLDPC_time_stats *p_procTime = &procTime; - - //////////////////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////// nr_deinterleaving_ldpc /////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////////// - - //////////////////////////// ulsch_llr =====> ulsch_harq->e ////////////////////////////// - - /// code blocks after bit selection in rate matching for LDPC code (38.212 V15.4.0 section 5.4.2.1) - int16_t harq_e[E]; - - nr_deinterleaving_ldpc(E, Qm, harq_e, ulsch_llr + r_offset); - - // for (int i =0; i<16; i++) - // printf("rx output deinterleaving w[%d]= %d r_offset %d\n", i,ulsch_harq->w[r][i], r_offset); - - - ////////////////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////// nr_rate_matching_ldpc_rx //////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////////// - - ///////////////////////// ulsch_harq->e =====> ulsch_harq->d ///////////////////////// - - - if (nr_rate_matching_ldpc_rx(rdata->tbslbrm, - p_decoderParms->BG, - p_decoderParms->Z, - ulsch_harq->d[r], - harq_e, - ulsch_harq->C, - rv_index, - ulsch_harq->d_to_be_cleared[r], - E, - ulsch_harq->F, - Kr - ulsch_harq->F - 2 * (p_decoderParms->Z)) - == -1) { - - LOG_E(PHY, "ulsch_decoding.c: Problem in rate_matching\n"); - rdata->decodeIterations = max_ldpc_iterations + 1; - set_abort(&ulsch_harq->abort_decode, true); - - // Task completed - completed_task_ans(rdata->ans); - return; - } - - ulsch_harq->d_to_be_cleared[r] = false; - - memset(ulsch_harq->c[r], 0, Kr_bytes); - p_decoderParms->crc_type = crcType(ulsch_harq->C, A); - p_decoderParms->E = lenWithCrc(ulsch_harq->C, A); - - // set first 2*Z_c bits to zeros - - int16_t z[68 * 384 + 16] __attribute__((aligned(16))); - - memset(z, 0, 2 * ulsch_harq->Z * sizeof(*z)); - // set Filler bits - memset(z + K_bits_F, 127, ulsch_harq->F * sizeof(*z)); - // Move coded bits before filler bits - memcpy(z + 2 * ulsch_harq->Z, ulsch_harq->d[r], (K_bits_F - 2 * ulsch_harq->Z) * sizeof(*z)); - // skip filler bits - memcpy(z + Kr, ulsch_harq->d[r] + (Kr - 2 * ulsch_harq->Z), (kc * ulsch_harq->Z - Kr) * sizeof(*z)); - // Saturate coded bits before decoding into 8 bits values - simde__m128i *pv = (simde__m128i *)&z; - int8_t l[68 * 384 + 16] __attribute__((aligned(16))); - simde__m128i *pl = (simde__m128i *)&l; - for (int i = 0, j = 0; j < ((kc * ulsch_harq->Z) >> 4) + 1; i += 2, j++) { - pl[j] = simde_mm_packs_epi16(pv[i], pv[i + 1]); - } - ////////////////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////// nrLDPC_decoder ///////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////// pl =====> llrProcBuf ////////////////////////////////// - rdata->decodeIterations = - ldpc_interface.LDPCdecoder(p_decoderParms, 0, 0, 0, l, llrProcBuf, p_procTime, &ulsch_harq->abort_decode); - - if (rdata->decodeIterations <= p_decoderParms->numMaxIter) - memcpy(ulsch_harq->c[r],llrProcBuf, Kr>>3); - - // Task completed - completed_task_ans(rdata->ans); -} - -int decode_offload(PHY_VARS_gNB *phy_vars_gNB, - uint8_t ULSCH_id, - short *ulsch_llr, - nfapi_nr_pusch_pdu_t *pusch_pdu, - t_nrLDPC_dec_params *decParams, - uint8_t harq_pid, - uint32_t G) -{ - NR_gNB_ULSCH_t *ulsch = &phy_vars_gNB->ulsch[ULSCH_id]; - NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_process; - int16_t z_ol[LDPC_MAX_CB_SIZE] __attribute__((aligned(16))); - int8_t l_ol[NR_LDPC_MAX_NUM_CB * LDPC_MAX_CB_SIZE] __attribute__((aligned(16))); - const int kc = decParams->BG == 2 ? 52 : 68; - uint32_t A = (harq_process->TBS) << 3; - const int Kr = harq_process->K; - const int Kr_bytes = Kr >> 3; - int8_t decodeIterations = 0; - int r_offset = 0; - int offset = 0; - // new data received, set processedSegments to 0 - if (!decParams->setCombIn) - harq_process->processedSegments = 0; - - for (int r = 0; r < harq_process->C; r++) { - decParams->perCB[r].E_cb = nr_get_E(G, harq_process->C, decParams->Qm, pusch_pdu->nrOfLayers, r); - memcpy(z_ol, ulsch_llr + r_offset, decParams->perCB[r].E_cb * sizeof(int16_t)); - simde__m128i *pv_ol128 = (simde__m128i *)z_ol; - simde__m128i *pl_ol128 = (simde__m128i *)&l_ol[offset]; - for (int i = 0, j = 0; j < ((kc * harq_process->Z) >> 4) + 1; i += 2, j++) { - pl_ol128[j] = simde_mm_packs_epi16(pv_ol128[i], pv_ol128[i + 1]); - } - decParams->F = harq_process->F; - r_offset += decParams->perCB[r].E_cb; - offset += LDPC_MAX_CB_SIZE; - } - - int8_t p_outDec[harq_process->C * Kr_bytes]; - memset(p_outDec, 0, sizeof(p_outDec)); - decodeIterations = - ldpc_interface_offload.LDPCdecoder(decParams, harq_pid, ULSCH_id, harq_process->C, (int8_t *)l_ol, p_outDec, NULL, NULL); - - if (decodeIterations < 0) { - LOG_E(PHY, "ulsch_decoding.c: Problem in LDPC decoder offload\n"); - return -1; - } - - int offset_b = 0; - for (int r = 0; r < harq_process->C; r++) { - if (decParams->perCB[r].status_cb == 0 || harq_process->C == 1) { - memcpy(harq_process->b + offset_b, &p_outDec[offset_b], Kr_bytes - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0)); - harq_process->processedSegments++; - } - offset_b += (Kr_bytes - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0)); - } - - bool crc_valid = false; - // CRC check made by the T2, no need to perform CRC check for a single code block twice - if (harq_process->processedSegments == harq_process->C) { - crc_valid = check_crc(harq_process->b, lenWithCrc(1, A), crcType(1, A)); - if (harq_process->C == 1 && !crc_valid) { - harq_process->processedSegments--; - } - } - - if (crc_valid) { - LOG_D(PHY, "ULSCH: Setting ACK for slot %d TBS %d\n", ulsch->slot, harq_process->TBS); - nr_fill_indication(phy_vars_gNB, ulsch->frame, ulsch->slot, ULSCH_id, harq_pid, 0, 0); - ulsch->active = false; - harq_process->round = 0; - } else { - LOG_D(PHY, - "[gNB %d] ULSCH: Setting NAK for SFN/SF %d/%d (pid %d, status %d, round %d, TBS %d)\n", - phy_vars_gNB->Mod_id, - ulsch->frame, - ulsch->slot, - harq_pid, - ulsch->active, - harq_process->round, - harq_process->TBS); - nr_fill_indication(phy_vars_gNB, ulsch->frame, ulsch->slot, ULSCH_id, harq_pid, 1, 0); - ulsch->handled = 1; - decodeIterations = ulsch->max_ldpc_iterations + 1; - LOG_D(PHY, "ULSCH %d in error\n", ULSCH_id); - } - - ulsch->last_iteration_cnt = decodeIterations; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_ULSCH_DECODING,0); - return 0; -} - int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, - uint8_t ULSCH_id, - short *ulsch_llr, NR_DL_FRAME_PARMS *frame_parms, - nfapi_nr_pusch_pdu_t *pusch_pdu, uint32_t frame, uint8_t nr_tti_rx, - uint8_t harq_pid, - uint32_t G, - thread_info_tm_t *t_info) + uint32_t *G, + uint8_t *ULSCH_ids, + int nb_pusch) { - if (!ulsch_llr) { - LOG_E(PHY, "ulsch_decoding.c: NULL ulsch_llr pointer\n"); - return -1; - } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_ULSCH_DECODING, 1); - NR_gNB_ULSCH_t *ulsch = &phy_vars_gNB->ulsch[ULSCH_id]; - NR_gNB_PUSCH *pusch = &phy_vars_gNB->pusch_vars[ULSCH_id]; - NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_process; + nrLDPC_TB_decoding_parameters_t TBs[nb_pusch]; + memset(TBs, 0, sizeof(TBs)); + nrLDPC_slot_decoding_parameters_t slot_parameters = { + .frame = frame, + .slot = nr_tti_rx, + .nb_TBs = nb_pusch, + .threadPool = &phy_vars_gNB->threadPool, + .TBs = TBs + }; - if (!harq_process) { - LOG_E(PHY, "ulsch_decoding.c: NULL harq_process pointer\n"); - return -1; - } + int max_num_segments = 0; - // ------------------------------------------------------------------ - const uint16_t nb_rb = pusch_pdu->rb_size; - const uint8_t Qm = pusch_pdu->qam_mod_order; - const uint8_t mcs = pusch_pdu->mcs_index; - const uint8_t n_layers = pusch_pdu->nrOfLayers; - // ------------------------------------------------------------------ + for (uint8_t pusch_id = 0; pusch_id < nb_pusch; pusch_id++) { + uint8_t ULSCH_id = ULSCH_ids[pusch_id]; + NR_gNB_ULSCH_t *ulsch = &phy_vars_gNB->ulsch[ULSCH_id]; + NR_gNB_PUSCH *pusch = &phy_vars_gNB->pusch_vars[ULSCH_id]; + NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_process; + nfapi_nr_pusch_pdu_t *pusch_pdu = &harq_process->ulsch_pdu; - harq_process->TBS = pusch_pdu->pusch_data.tb_size; + nrLDPC_TB_decoding_parameters_t *TB_parameters = &TBs[pusch_id]; - t_nrLDPC_dec_params decParams = {.check_crc = check_crc}; - decParams.BG = pusch_pdu->maintenance_parms_v3.ldpcBaseGraph; - const uint32_t A = (harq_process->TBS) << 3; - NR_gNB_PHY_STATS_t *stats = get_phy_stats(phy_vars_gNB, ulsch->rnti); - if (stats) { - stats->frame = frame; - stats->ulsch_stats.round_trials[harq_process->round]++; - for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { - stats->ulsch_stats.power[aarx] = dB_fixed_x10(pusch->ulsch_power[aarx]); - stats->ulsch_stats.noise_power[aarx] = dB_fixed_x10(pusch->ulsch_noise_power[aarx]); + TB_parameters->G = G[pusch_id]; + + if (!harq_process) { + LOG_E(PHY, "ulsch_decoding.c: NULL harq_process pointer\n"); + return -1; } - if (!harq_process->harq_to_be_cleared) { - stats->ulsch_stats.current_Qm = Qm; - stats->ulsch_stats.current_RI = n_layers; - stats->ulsch_stats.total_bytes_tx += harq_process->TBS; + + // The harq_pid is not unique among the active HARQ processes in the instance so we use ULSCH_id instead + TB_parameters->harq_unique_pid = ULSCH_id; + + // ------------------------------------------------------------------ + TB_parameters->nb_rb = pusch_pdu->rb_size; + TB_parameters->Qm = pusch_pdu->qam_mod_order; + TB_parameters->mcs = pusch_pdu->mcs_index; + TB_parameters->nb_layers = pusch_pdu->nrOfLayers; + // ------------------------------------------------------------------ + + TB_parameters->processedSegments = &harq_process->processedSegments; + harq_process->TBS = pusch_pdu->pusch_data.tb_size; + + TB_parameters->BG = pusch_pdu->maintenance_parms_v3.ldpcBaseGraph; + TB_parameters->A = (harq_process->TBS) << 3; + NR_gNB_PHY_STATS_t *stats = get_phy_stats(phy_vars_gNB, ulsch->rnti); + if (stats) { + stats->frame = frame; + stats->ulsch_stats.round_trials[harq_process->round]++; + for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { + stats->ulsch_stats.power[aarx] = dB_fixed_x10(pusch->ulsch_power[aarx]); + stats->ulsch_stats.noise_power[aarx] = dB_fixed_x10(pusch->ulsch_noise_power[aarx]); + } + if (!harq_process->harq_to_be_cleared) { + stats->ulsch_stats.current_Qm = TB_parameters->Qm; + stats->ulsch_stats.current_RI = TB_parameters->nb_layers; + stats->ulsch_stats.total_bytes_tx += harq_process->TBS; + } } - } - - LOG_D(PHY, - "ULSCH Decoding, harq_pid %d rnti %x TBS %d G %d mcs %d Nl %d nb_rb %d, Qm %d, Coderate %f RV %d round %d new RX %d\n", - harq_pid, - ulsch->rnti, - A, - G, - mcs, - n_layers, - nb_rb, - Qm, - pusch_pdu->target_code_rate / 10240.0f, - pusch_pdu->pusch_data.rv_index, - harq_process->round, - harq_process->harq_to_be_cleared); - - // [hna] Perform nr_segmenation with input and output set to NULL to calculate only (C, K, Z, F) - nr_segmentation(NULL, - NULL, - lenWithCrc(1, A), // size in case of 1 segment - &harq_process->C, - &harq_process->K, - &harq_process->Z, // [hna] Z is Zc - &harq_process->F, - decParams.BG); - - uint16_t a_segments = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER * n_layers; // number of segments to be allocated - if (harq_process->C > a_segments) { - LOG_E(PHY, "nr_segmentation.c: too many segments %d, A %d\n", harq_process->C, A); - return(-1); - } - if (nb_rb != 273) { - a_segments = a_segments*nb_rb; - a_segments = a_segments/273 +1; - } - if (harq_process->C > a_segments) { - LOG_E(PHY,"Illegal harq_process->C %d > %d\n",harq_process->C,a_segments); - return -1; - } - + + uint8_t harq_pid = ulsch->harq_pid; + LOG_D(PHY, + "ULSCH Decoding, harq_pid %d rnti %x TBS %d G %d mcs %d Nl %d nb_rb %d, Qm %d, Coderate %f RV %d round %d new RX %d\n", + harq_pid, + ulsch->rnti, + TB_parameters->A, + TB_parameters->G, + TB_parameters->mcs, + TB_parameters->nb_layers, + TB_parameters->nb_rb, + TB_parameters->Qm, + pusch_pdu->target_code_rate / 10240.0f, + pusch_pdu->pusch_data.rv_index, + harq_process->round, + harq_process->harq_to_be_cleared); + + // [hna] Perform nr_segmenation with input and output set to NULL to calculate only (C, K, Z, F) + nr_segmentation(NULL, + NULL, + lenWithCrc(1, TB_parameters->A), // size in case of 1 segment + &TB_parameters->C, + &TB_parameters->K, + &TB_parameters->Z, // [hna] Z is Zc + &TB_parameters->F, + TB_parameters->BG); + harq_process->C = TB_parameters->C; + harq_process->K = TB_parameters->K; + harq_process->Z = TB_parameters->Z; + harq_process->F = TB_parameters->F; + + uint16_t a_segments = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER * TB_parameters->nb_layers; // number of segments to be allocated + if (TB_parameters->C > a_segments) { + LOG_E(PHY, "nr_segmentation.c: too many segments %d, A %d\n", harq_process->C, TB_parameters->A); + return(-1); + } + if (TB_parameters->nb_rb != 273) { + a_segments = a_segments*TB_parameters->nb_rb; + a_segments = a_segments/273 +1; + } + if (TB_parameters->C > a_segments) { + LOG_E(PHY,"Illegal harq_process->C %d > %d\n",harq_process->C,a_segments); + return -1; + } + max_num_segments = max(max_num_segments, TB_parameters->C); + #ifdef DEBUG_ULSCH_DECODING - printf("ulsch decoding nr segmentation Z %d\n", harq_process->Z); - if (!frame % 100) - printf("K %d C %d Z %d \n", harq_process->K, harq_process->C, harq_process->Z); - printf("Segmentation: C %d, K %d\n",harq_process->C,harq_process->K); + printf("ulsch decoding nr segmentation Z %d\n", TB_parameters->Z); + if (!frame % 100) + printf("K %d C %d Z %d \n", + TB_parameters->K, + TB_parameters->C, + TB_parameters->Z); + printf("Segmentation: C %d, K %d\n", + TB_parameters->C, + TB_parameters->K); #endif + + TB_parameters->max_ldpc_iterations = ulsch->max_ldpc_iterations; + TB_parameters->rv_index = pusch_pdu->pusch_data.rv_index; + TB_parameters->tbslbrm = pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes; + TB_parameters->abort_decode = &harq_process->abort_decode; + set_abort(&harq_process->abort_decode, false); - decParams.Z = harq_process->Z; - decParams.numMaxIter = ulsch->max_ldpc_iterations; - decParams.Qm = Qm; - decParams.rv = pusch_pdu->pusch_data.rv_index; - decParams.outMode = 0; - decParams.setCombIn = !harq_process->harq_to_be_cleared; - if (harq_process->harq_to_be_cleared) { - for (int r = 0; r < harq_process->C; r++) - harq_process->d_to_be_cleared[r] = true; - harq_process->harq_to_be_cleared = false; } - if (phy_vars_gNB->ldpc_offload_flag) - return decode_offload(phy_vars_gNB, ULSCH_id, ulsch_llr, pusch_pdu, &decParams, harq_pid, G); - harq_process->processedSegments = 0; - uint32_t offset = 0, r_offset = 0; - set_abort(&harq_process->abort_decode, false); - for (int r = 0; r < harq_process->C; r++) { - int E = nr_get_E(G, harq_process->C, Qm, n_layers, r); + nrLDPC_segment_decoding_parameters_t segments[nb_pusch][max_num_segments]; + memset(segments, 0, sizeof(segments)); - ldpcDecode_t *rdata = &((ldpcDecode_t *)t_info->buf)[t_info->len]; - DevAssert(t_info->len < t_info->cap); - rdata->ans = &t_info->ans[t_info->len]; - t_info->len += 1; + for (uint8_t pusch_id = 0; pusch_id < nb_pusch; pusch_id++) { + uint8_t ULSCH_id = ULSCH_ids[pusch_id]; + NR_gNB_ULSCH_t *ulsch = &phy_vars_gNB->ulsch[ULSCH_id]; + NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_process; + short *ulsch_llr = phy_vars_gNB->pusch_vars[ULSCH_id].llr; - decParams.R = nr_get_R_ldpc_decoder(pusch_pdu->pusch_data.rv_index, - E, - decParams.BG, - decParams.Z, - &harq_process->llrLen, - harq_process->round); - rdata->gNB = phy_vars_gNB; - rdata->ulsch_harq = harq_process; - rdata->decoderParms = decParams; - rdata->ulsch_llr = ulsch_llr; - rdata->Kc = decParams.BG == 2 ? 52 : 68; - rdata->harq_pid = harq_pid; - rdata->segment_r = r; - rdata->nbSegments = harq_process->C; - rdata->E = E; - rdata->A = A; - rdata->Qm = Qm; - rdata->r_offset = r_offset; - rdata->Kr_bytes = harq_process->K >> 3; - rdata->rv_index = pusch_pdu->pusch_data.rv_index; - rdata->offset = offset; - rdata->ulsch = ulsch; - rdata->ulsch_id = ULSCH_id; - rdata->tbslbrm = pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes; + if (!ulsch_llr) { + LOG_E(PHY, "ulsch_decoding.c: NULL ulsch_llr pointer\n"); + return -1; + } - task_t t = {.func = &nr_processULSegment, .args = rdata}; - pushTpool(&phy_vars_gNB->threadPool, t); + nrLDPC_TB_decoding_parameters_t *TB_parameters = &TBs[pusch_id]; + TB_parameters->segments = segments[pusch_id]; + + uint32_t r_offset = 0; + for (int r = 0; r < TB_parameters->C; r++) { + nrLDPC_segment_decoding_parameters_t *segment_parameters = &TB_parameters->segments[r]; + segment_parameters->E = nr_get_E(TB_parameters->G, + TB_parameters->C, + TB_parameters->Qm, + TB_parameters->nb_layers, + r); + segment_parameters->R = nr_get_R_ldpc_decoder(TB_parameters->rv_index, + segment_parameters->E, + TB_parameters->BG, + TB_parameters->Z, + &harq_process->llrLen, + harq_process->round); + segment_parameters->llr = ulsch_llr + r_offset; + segment_parameters->d = harq_process->d[r]; + segment_parameters->d_to_be_cleared = &harq_process->d_to_be_cleared[r]; + segment_parameters->c = harq_process->c[r]; + segment_parameters->decodeSuccess = false; + + reset_meas(&segment_parameters->ts_deinterleave); + reset_meas(&segment_parameters->ts_rate_unmatch); + reset_meas(&segment_parameters->ts_ldpc_decode); + + r_offset += segment_parameters->E; + } + if (harq_process->harq_to_be_cleared) { + for (int r = 0; r < TB_parameters->C; r++) { + harq_process->d_to_be_cleared[r] = true; + } + harq_process->harq_to_be_cleared = false; + } - LOG_D(PHY, "Added a block to decode, in pipe: %d\n", r); - r_offset += E; - offset += ((harq_process->K >> 3) - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0)); } - return harq_process->C; + + int ret_decoder = phy_vars_gNB->nrLDPC_coding_interface.nrLDPC_coding_decoder(&slot_parameters); + + // post decode + for (uint8_t pusch_id = 0; pusch_id < nb_pusch; pusch_id++) { + uint8_t ULSCH_id = ULSCH_ids[pusch_id]; + NR_gNB_ULSCH_t *ulsch = &phy_vars_gNB->ulsch[ULSCH_id]; + NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_process; + + nrLDPC_TB_decoding_parameters_t TB_parameters = TBs[pusch_id]; + + uint32_t offset = 0; + for (int r = 0; r < TB_parameters.C; r++) { + nrLDPC_segment_decoding_parameters_t nrLDPC_segment_decoding_parameters = TB_parameters.segments[r]; + // Copy c to b in case of decoding success + if (nrLDPC_segment_decoding_parameters.decodeSuccess) { + memcpy(harq_process->b + offset, harq_process->c[r], (harq_process->K >> 3) - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0)); + } else { + LOG_D(PHY, "uplink segment error %d/%d\n", r, harq_process->C); + LOG_D(PHY, "ULSCH %d in error\n", ULSCH_id); + } + offset += ((harq_process->K >> 3) - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0)); + } + } + + return ret_decoder; } diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index f6e6559414..e8fdfd4dda 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -40,6 +40,7 @@ #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" #include "PHY/impl_defs_top.h" #include "PHY/defs_common.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" #include "PHY/CODING/nrLDPC_extern.h" #include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h" #include "executables/rt_profiling.h" @@ -494,9 +495,10 @@ typedef struct PHY_VARS_gNB_s { /// OFDM symbol offset divisor for UL uint32_t ofdm_offset_divisor; - int ldpc_offload_flag; - + /// NR LDPC coding related + nrLDPC_coding_interface_t nrLDPC_coding_interface; int max_ldpc_iterations; + /// indicate the channel estimation technique in time domain int chest_time; /// indicate the channel estimation technique in freq domain diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 7b3a82c7ce..26251506c7 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -305,187 +305,144 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_TX + gNB->CC_id, 0); } -static void nr_postDecode(PHY_VARS_gNB *gNB, ldpcDecode_t *rdata) +static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, bool *ulsch_to_decode) { - NR_UL_gNB_HARQ_t *ulsch_harq = rdata->ulsch_harq; - NR_gNB_ULSCH_t *ulsch = rdata->ulsch; - int r = rdata->segment_r; - nfapi_nr_pusch_pdu_t *pusch_pdu = &gNB->ulsch[rdata->ulsch_id].harq_process->ulsch_pdu; - bool decodeSuccess = (rdata->decodeIterations <= rdata->decoderParms.numMaxIter); - ulsch_harq->processedSegments++; - LOG_D(PHY, - "processing result of segment: %d, processed %d/%d, %s\n", - rdata->segment_r, - ulsch_harq->processedSegments, - rdata->nbSegments, - decodeSuccess ? "Decoded Successfully" : "Decoding Unsuccessful"); + NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - if (decodeSuccess) { - memcpy(ulsch_harq->b + rdata->offset, ulsch_harq->c[r], rdata->Kr_bytes - (ulsch_harq->F >> 3) - ((ulsch_harq->C > 1) ? 3 : 0)); - - } else { - LOG_D(PHY, "ULSCH %d in error\n", rdata->ulsch_id); + int nb_pusch = 0; + for (uint8_t ULSCH_id = 0; ULSCH_id < gNB->max_nb_pusch; ULSCH_id++) { + if (ulsch_to_decode[ULSCH_id]) { + nb_pusch++; + } } - //int dumpsig=0; - // if all segments are done - if (ulsch_harq->processedSegments == ulsch_harq->C) { - // When the number of code blocks is 1 (C = 1) and ulsch_harq->processedSegments = 1, we can assume a good TB because of the - // CRC check made by the LDPC for early termination, so, no need to perform CRC check twice for a single code block - bool crc_valid = true; - if (ulsch_harq->C > 1) { - crc_valid = check_crc(ulsch_harq->b, lenWithCrc(1, rdata->A), crcType(1, rdata->A)); + if (nb_pusch == 0) { + return 0; + } + + uint8_t ULSCH_ids[nb_pusch]; + uint32_t G[nb_pusch]; + int pusch_id = 0; + for (uint8_t ULSCH_id = 0; ULSCH_id < gNB->max_nb_pusch; ULSCH_id++) { + + if (ulsch_to_decode[ULSCH_id]) { + + ULSCH_ids[pusch_id] = ULSCH_id; + + nfapi_nr_pusch_pdu_t *pusch_pdu = &gNB->ulsch[ULSCH_id].harq_process->ulsch_pdu; + + uint16_t nb_re_dmrs; + uint16_t start_symbol = pusch_pdu->start_symbol_index; + uint16_t number_symbols = pusch_pdu->nr_of_symbols; + + uint8_t number_dmrs_symbols = 0; + for (int l = start_symbol; l < start_symbol + number_symbols; l++) + number_dmrs_symbols += ((pusch_pdu->ul_dmrs_symb_pos)>>l)&0x01; + + if (pusch_pdu->dmrs_config_type==pusch_dmrs_type1) + nb_re_dmrs = 6*pusch_pdu->num_dmrs_cdm_grps_no_data; + else + nb_re_dmrs = 4*pusch_pdu->num_dmrs_cdm_grps_no_data; + + G[pusch_id] = nr_get_G(pusch_pdu->rb_size, + number_symbols, + nb_re_dmrs, + number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs + gNB->ulsch[ULSCH_id].unav_res, + pusch_pdu->qam_mod_order, + pusch_pdu->nrOfLayers); + AssertFatal(G[pusch_id]>0,"G is 0 : rb_size %u, number_symbols %d, nb_re_dmrs %d, number_dmrs_symbols %d, qam_mod_order %u, nrOfLayer %u\n", + pusch_pdu->rb_size, + number_symbols, + nb_re_dmrs, + number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs + pusch_pdu->qam_mod_order, + pusch_pdu->nrOfLayers); + LOG_D(PHY,"rb_size %d, number_symbols %d, nb_re_dmrs %d, dmrs symbol positions %d, number_dmrs_symbols %d, qam_mod_order %d, nrOfLayer %d\n", + pusch_pdu->rb_size, + number_symbols, + nb_re_dmrs, + pusch_pdu->ul_dmrs_symb_pos, + number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs + pusch_pdu->qam_mod_order, + pusch_pdu->nrOfLayers); + pusch_id++; + } + } + + //---------------------------------------------------------- + //--------------------- ULSCH decoding --------------------- + //---------------------------------------------------------- + + int ret_nr_ulsch_decoding = + nr_ulsch_decoding(gNB, frame_parms, frame_rx, slot_rx, G, ULSCH_ids, nb_pusch); + + // CRC check per uplink shared channel + for (pusch_id = 0; pusch_id < nb_pusch; pusch_id++) { + uint8_t ULSCH_id = ULSCH_ids[pusch_id]; + NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id]; + NR_gNB_PUSCH *pusch = &gNB->pusch_vars[ULSCH_id]; + NR_UL_gNB_HARQ_t *ulsch_harq = ulsch->harq_process; + nfapi_nr_pusch_pdu_t *pusch_pdu = &ulsch_harq->ulsch_pdu; + + bool crc_valid = false; + + // if all segments are done + if (ulsch_harq->processedSegments == ulsch_harq->C) { + if (ulsch_harq->C > 1) { + crc_valid = check_crc(ulsch_harq->b, lenWithCrc(1, (ulsch_harq->TBS) << 3), crcType(1, (ulsch_harq->TBS) << 3)); + } else { + // When the number of code blocks is 1 (C = 1) and ulsch_harq->processedSegments = 1, we can assume a good TB because of the + // CRC check made by the LDPC for early termination, so, no need to perform CRC check twice for a single code block + crc_valid = true; + } } - if (crc_valid && !check_abort(&ulsch_harq->abort_decode) && !gNB->pusch_vars[rdata->ulsch_id].DTX) { + if (crc_valid && !check_abort(&ulsch_harq->abort_decode) && !pusch->DTX) { LOG_D(NR_PHY, "[gNB %d] ULSCH %d: Setting ACK for SFN/SF %d.%d (rnti %x, pid %d, ndi %d, status %d, round %d, TBS %d, Max interation " "(all seg) %d)\n", gNB->Mod_id, - rdata->ulsch_id, + ULSCH_id, ulsch->frame, ulsch->slot, ulsch->rnti, - rdata->harq_pid, + ulsch->harq_pid, pusch_pdu->pusch_data.new_data_indicator, ulsch->active, ulsch_harq->round, ulsch_harq->TBS, - rdata->decodeIterations); - nr_fill_indication(gNB, ulsch->frame, ulsch->slot, rdata->ulsch_id, rdata->harq_pid, 0, 0); + ulsch->max_ldpc_iterations); + nr_fill_indication(gNB, ulsch->frame, ulsch->slot, ULSCH_id, ulsch->harq_pid, 0, 0); LOG_D(PHY, "ULSCH received ok \n"); ulsch->active = false; ulsch_harq->round = 0; - //dumpsig=1; + ulsch->last_iteration_cnt = ulsch->max_ldpc_iterations; // Setting to max_ldpc_iterations is sufficient given that this variable is only used for checking for failure } else { LOG_D(PHY, "[gNB %d] ULSCH: Setting NAK for SFN/SF %d/%d (pid %d, ndi %d, status %d, round %d, RV %d, prb_start %d, prb_size %d, " - "TBS %d) r %d\n", + "TBS %d)\n", gNB->Mod_id, ulsch->frame, ulsch->slot, - rdata->harq_pid, + ulsch->harq_pid, pusch_pdu->pusch_data.new_data_indicator, ulsch->active, ulsch_harq->round, ulsch_harq->ulsch_pdu.pusch_data.rv_index, ulsch_harq->ulsch_pdu.rb_start, ulsch_harq->ulsch_pdu.rb_size, - ulsch_harq->TBS, - r); - nr_fill_indication(gNB, ulsch->frame, ulsch->slot, rdata->ulsch_id, rdata->harq_pid, 1, 0); + ulsch_harq->TBS); + nr_fill_indication(gNB, ulsch->frame, ulsch->slot, ULSCH_id, ulsch->harq_pid, 1, 0); ulsch->handled = 1; - LOG_D(PHY, "ULSCH %d in error\n",rdata->ulsch_id); - // dumpsig=1; + LOG_D(PHY, "ULSCH %d in error\n",ULSCH_id); + ulsch->last_iteration_cnt = ulsch->max_ldpc_iterations + 1; // Setting to max_ldpc_iterations + 1 is sufficient given that this variable is only used for checking for failure } - ulsch->last_iteration_cnt = rdata->decodeIterations; - /* - if (ulsch_harq->ulsch_pdu.mcs_index == 0 && dumpsig==1) { - int off = ((ulsch_harq->ulsch_pdu.rb_size&1) == 1)? 4:0; - - LOG_M("rxsigF0.m","rxsF0",&gNB->common_vars.rxdataF[0][0][(ulsch_harq->slot%RU_RX_SLOT_DEPTH)*gNB->frame_parms.ofdm_symbol_size*gNB->frame_parms.symbols_per_slot],gNB->frame_parms.ofdm_symbol_size*gNB->frame_parms.symbols_per_slot,1,1); - LOG_M("rxsigF0_ext.m","rxsF0_ext", - &gNB->pusch_vars[0].rxdataF_ext[0][ulsch_harq->ulsch_pdu.start_symbol_index*NR_NB_SC_PER_RB * - ulsch_harq->ulsch_pdu.rb_size],ulsch_harq->ulsch_pdu.nr_of_symbols*(off+(NR_NB_SC_PER_RB * - ulsch_harq->ulsch_pdu.rb_size)),1,1); LOG_M("chestF0.m","chF0", - &gNB->pusch_vars[0].ul_ch_estimates[0][ulsch_harq->ulsch_pdu.start_symbol_index*gNB->frame_parms.ofdm_symbol_size],gNB->frame_parms.ofdm_symbol_size,1,1); - LOG_M("rxsigF0_comp.m","rxsF0_comp", - &gNB->pusch_vars[0].rxdataF_comp[0][ulsch_harq->ulsch_pdu.start_symbol_index*(off+(NR_NB_SC_PER_RB * - ulsch_harq->ulsch_pdu.rb_size))],ulsch_harq->ulsch_pdu.nr_of_symbols*(off+(NR_NB_SC_PER_RB * - ulsch_harq->ulsch_pdu.rb_size)),1,1); LOG_M("rxsigF0_llr.m","rxsF0_llr", - &gNB->pusch_vars[0].llr[0],(ulsch_harq->ulsch_pdu.nr_of_symbols-1)*NR_NB_SC_PER_RB * ulsch_harq->ulsch_pdu.rb_size * - ulsch_harq->ulsch_pdu.qam_mod_order,1,0); if (gNB->frame_parms.nb_antennas_rx > 1) { - - LOG_M("rxsigF1_ext.m","rxsF0_ext", - &gNB->pusch_vars[0].rxdataF_ext[1][ulsch_harq->ulsch_pdu.start_symbol_index*NR_NB_SC_PER_RB * - ulsch_harq->ulsch_pdu.rb_size],ulsch_harq->ulsch_pdu.nr_of_symbols*(off+(NR_NB_SC_PER_RB * - ulsch_harq->ulsch_pdu.rb_size)),1,1); LOG_M("chestF1.m","chF1", - &gNB->pusch_vars[0].ul_ch_estimates[1][ulsch_harq->ulsch_pdu.start_symbol_index*gNB->frame_parms.ofdm_symbol_size],gNB->frame_parms.ofdm_symbol_size,1,1); - LOG_M("rxsigF1_comp.m","rxsF1_comp", - &gNB->pusch_vars[0].rxdataF_comp[1][ulsch_harq->ulsch_pdu.start_symbol_index*(off+(NR_NB_SC_PER_RB * - ulsch_harq->ulsch_pdu.rb_size))],ulsch_harq->ulsch_pdu.nr_of_symbols*(off+(NR_NB_SC_PER_RB * - ulsch_harq->ulsch_pdu.rb_size)),1,1); - } - exit(-1); - - } - */ - ulsch->last_iteration_cnt = rdata->decodeIterations; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_ULSCH_DECODING,0); } + + return ret_nr_ulsch_decoding; } -static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, - int frame_rx, - int slot_rx, - int ULSCH_id, - uint8_t harq_pid, - thread_info_tm_t *t_info) -{ - NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - nfapi_nr_pusch_pdu_t *pusch_pdu = &gNB->ulsch[ULSCH_id].harq_process->ulsch_pdu; - - uint16_t nb_re_dmrs; - uint16_t start_symbol = pusch_pdu->start_symbol_index; - uint16_t number_symbols = pusch_pdu->nr_of_symbols; - - uint8_t number_dmrs_symbols = 0; - for (int l = start_symbol; l < start_symbol + number_symbols; l++) - number_dmrs_symbols += ((pusch_pdu->ul_dmrs_symb_pos)>>l)&0x01; - - if (pusch_pdu->dmrs_config_type==pusch_dmrs_type1) - nb_re_dmrs = 6*pusch_pdu->num_dmrs_cdm_grps_no_data; - else - nb_re_dmrs = 4*pusch_pdu->num_dmrs_cdm_grps_no_data; - - uint32_t G = nr_get_G(pusch_pdu->rb_size, - number_symbols, - nb_re_dmrs, - number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs - gNB->ulsch[ULSCH_id].unav_res, - pusch_pdu->qam_mod_order, - pusch_pdu->nrOfLayers); - - AssertFatal(G>0,"G is 0 : rb_size %u, number_symbols %d, nb_re_dmrs %d, number_dmrs_symbols %d, qam_mod_order %u, nrOfLayer %u\n", - pusch_pdu->rb_size, - number_symbols, - nb_re_dmrs, - number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs - pusch_pdu->qam_mod_order, - pusch_pdu->nrOfLayers); - LOG_D(PHY,"rb_size %d, number_symbols %d, nb_re_dmrs %d, dmrs symbol positions %d, number_dmrs_symbols %d, qam_mod_order %d, nrOfLayer %d\n", - pusch_pdu->rb_size, - number_symbols, - nb_re_dmrs, - pusch_pdu->ul_dmrs_symb_pos, - number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs - pusch_pdu->qam_mod_order, - pusch_pdu->nrOfLayers); - - //---------------------------------------------------------- - //--------------------- ULSCH decoding --------------------- - //---------------------------------------------------------- - /* Do ULSCH decoding time measurement only when number of PUSCH is limited to 1 - * (valid for unitary physical simulators). ULSCH processing lopp is then executed - * only once, which ensures exactly one start and stop of the ULSCH decoding time - * measurement per processed TB.*/ - if (gNB->max_nb_pusch == 1) - start_meas(&gNB->ulsch_decoding_stats); - - int const nbDecode = nr_ulsch_decoding(gNB, - ULSCH_id, - gNB->pusch_vars[ULSCH_id].llr, - frame_parms, - pusch_pdu, - frame_rx, - slot_rx, - harq_pid, - G, - t_info); - return nbDecode; -} - - void nr_fill_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int ULSCH_id, uint8_t harq_pid, uint8_t crc_flag, int dtx_flag) { NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id]; @@ -840,12 +797,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) } } - ldpcDecode_t arr[64]; - task_ans_t ans[64] = {0}; - thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .len = 0, .cap = 64, .ans = ans}; - - // int64_t const t0 = time_now_ns(); - int totalDecode = 0; + bool ulsch_to_decode[gNB->max_nb_pusch]; + bzero((void *)ulsch_to_decode, sizeof(ulsch_to_decode)); for (int ULSCH_id = 0; ULSCH_id < gNB->max_nb_pusch; ULSCH_id++) { NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id]; NR_UL_gNB_HARQ_t *ulsch_harq = ulsch->harq_process; @@ -937,25 +890,26 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) pusch_vars->DTX = 0; } + ulsch_to_decode[ULSCH_id] = true; stop_meas(&gNB->rx_pusch_stats); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RX_PUSCH, 0); // LOG_M("rxdataF_comp.m","rxF_comp",gNB->pusch_vars[0]->rxdataF_comp[0],6900,1,1); // LOG_M("rxdataF_ext.m","rxF_ext",gNB->pusch_vars[0]->rxdataF_ext[0],6900,1,1); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_ULSCH_PROCEDURES_RX, 1); - int const tasks_added = nr_ulsch_procedures(gNB, frame_rx, slot_rx, ULSCH_id, ulsch->harq_pid, &t_info); - if (tasks_added > 0) - totalDecode += tasks_added; - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_ULSCH_PROCEDURES_RX, 0); } } - DevAssert(totalDecode == t_info.len); + /* Do ULSCH decoding time measurement only when number of PUSCH is limited to 1 + * (valid for unitary physical simulators). ULSCH processing lopp is then executed + * only once, which ensures exactly one start and stop of the ULSCH decoding time + * measurement per processed TB.*/ + if (gNB->max_nb_pusch == 1) + start_meas(&gNB->ulsch_decoding_stats); - join_task_ans(t_info.ans, t_info.len); - for (int i = 0; i < t_info.len; ++i) { - nr_postDecode(gNB, &arr[i]); + int const ret_nr_ulsch_procedures = nr_ulsch_procedures(gNB, frame_rx, slot_rx, ulsch_to_decode); + if (ret_nr_ulsch_procedures != 0) { + LOG_E(PHY,"Error in nr_ulsch_procedures, returned %d\n",ret_nr_ulsch_procedures); } + /* Do ULSCH decoding time measurement only when number of PUSCH is limited to 1 * (valid for unitary physical simulators). ULSCH processing loop is then executed * only once, which ensures exactly one start and stop of the ULSCH decoding time From 80c406693f3955a6b9f15f7bff1ee09b14d568ad Mon Sep 17 00:00:00 2001 From: Yi-Hung Chang Date: Wed, 9 Oct 2024 14:16:29 +0200 Subject: [PATCH 39/83] feat(nrLDPC_coding_interface): Use reworked interface in UE --- executables/nr-uesoftmodem.c | 11 +- executables/nr-uesoftmodem.h | 2 - executables/softmodem-common.h | 3 - openair1/PHY/INIT/nr_init_ue.c | 2 + .../PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c | 635 ++++++++---------- .../NR_UE_TRANSPORT/nr_transport_proto_ue.h | 88 +-- .../PHY/NR_UE_TRANSPORT/nr_transport_ue.h | 4 + .../PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c | 285 ++++---- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 204 +++--- openair1/PHY/defs_nr_UE.h | 4 +- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 179 ++--- 11 files changed, 622 insertions(+), 795 deletions(-) diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index ff8a7f7fa8..55e80ce7d4 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -42,6 +42,7 @@ //#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all #include "openair1/PHY/MODULATION/nr_modulation.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" #include "PHY/phy_vars_nr_ue.h" #include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h" #include "PHY/NR_TRANSPORT/nr_dlsch.h" @@ -219,7 +220,6 @@ void set_options(int CC_id, PHY_VARS_NR_UE *UE){ UE->rf_map.card = 0; UE->rf_map.chain = CC_id + 0; UE->max_ldpc_iterations = nrUE_params.max_ldpc_iterations; - UE->ldpc_offload_enable = nrUE_params.ldpc_offload_flag; UE->UE_scan_carrier = nrUE_params.UE_scan_carrier; UE->UE_fo_compensation = nrUE_params.UE_fo_compensation; UE->if_freq = nrUE_params.if_freq; @@ -388,6 +388,7 @@ configmodule_interface_t *uniqCfg = NULL; // A global var to reduce the changes size ldpc_interface_t ldpc_interface = {0}, ldpc_interface_offload = {0}; +nrLDPC_coding_interface_t nrLDPC_coding_interface = {0}; int main(int argc, char **argv) { @@ -427,10 +428,8 @@ int main(int argc, char **argv) init_opt(); - if (nrUE_params.ldpc_offload_flag) - load_LDPClib("_t2", &ldpc_interface_offload); - - load_LDPClib(NULL, &ldpc_interface); + int ret_loader = load_nrLDPC_coding_interface(NULL, &nrLDPC_coding_interface); + AssertFatal(ret_loader == 0, "error loading LDPC library\n"); if (ouput_vcd) { vcd_signal_dumper_init("/tmp/openair_dump_nrUE.vcd"); @@ -445,6 +444,8 @@ int main(int argc, char **argv) for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { PHY_vars_UE_g[inst][CC_id] = malloc(sizeof(*PHY_vars_UE_g[inst][CC_id])); memset(PHY_vars_UE_g[inst][CC_id], 0, sizeof(*PHY_vars_UE_g[inst][CC_id])); + // All instances use the same coding interface + PHY_vars_UE_g[inst][CC_id]->nrLDPC_coding_interface = nrLDPC_coding_interface; } } diff --git a/executables/nr-uesoftmodem.h b/executables/nr-uesoftmodem.h index 40ff2075a5..e34307e574 100644 --- a/executables/nr-uesoftmodem.h +++ b/executables/nr-uesoftmodem.h @@ -42,7 +42,6 @@ {"dlsch-parallel", CONFIG_HLP_DLSCH_PARA, 0, .u8ptr=NULL, .defintval=0, TYPE_UINT8, 0}, \ {"offset-divisor", CONFIG_HLP_OFFSET_DIV, 0, .uptr=&nrUE_params.ofdm_offset_divisor, .defuintval=8, TYPE_UINT32, 0}, \ {"max-ldpc-iterations", CONFIG_HLP_MAX_LDPC_ITERATIONS, 0, .iptr=&nrUE_params.max_ldpc_iterations, .defuintval=8, TYPE_UINT8, 0}, \ - {"ldpc-offload-enable", CONFIG_HLP_LDPC_OFFLOAD, PARAMFLAG_BOOL, .iptr=&(nrUE_params.ldpc_offload_flag), .defintval=0, TYPE_INT, 0}, \ {"V" , CONFIG_HLP_VCD, PARAMFLAG_BOOL, .iptr=&nrUE_params.vcdflag, .defintval=0, TYPE_INT, 0}, \ {"uecap_file", CONFIG_HLP_UECAP_FILE, 0, .strptr=&nrUE_params.uecap_file, .defstrval="./uecap_ports1.xml", TYPE_STRING, 0}, \ {"reconfig-file", CONFIG_HLP_RE_CFG_FILE, 0, .strptr=&nrUE_params.reconfig_file, .defstrval="./reconfig.raw", TYPE_STRING, 0}, \ @@ -91,7 +90,6 @@ typedef struct { int nb_antennas_tx; int N_RB_DL; int ssb_start_subcarrier; - int ldpc_offload_flag; double time_sync_P; double time_sync_I; unsigned int ntn_koffset; diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h index 022f9add0a..dfeded92ba 100644 --- a/executables/softmodem-common.h +++ b/executables/softmodem-common.h @@ -108,7 +108,6 @@ extern "C" #define CONFIG_HLP_CONTINUOUS_TX "perform continuous transmission, even in TDD mode (to work around USRP issues)\n" #define CONFIG_HLP_STATS_DISABLE "disable globally the stats generation and persistence" #define CONFIG_HLP_NOITTI "Do not start itti threads, call queue processing in place, inside the caller thread" -#define CONFIG_HLP_LDPC_OFFLOAD "Enable LDPC offload to AMD Xilinx T2 telco card\n" #define CONFIG_HLP_SYNC_REF "UE acts a Sync Reference in Sidelink. 0-none 1-GNB 2-GNSS 4-localtiming\n" #define CONFIG_HLP_TADV \ "Set RF board timing_advance to compensate fix delay inside the RF board between Rx and Tx timestamps (RF board internal " \ @@ -181,7 +180,6 @@ extern int usrp_tx_thread; {"continuous-tx", CONFIG_HLP_CONTINUOUS_TX, PARAMFLAG_BOOL, .iptr=&CONTINUOUS_TX, .defintval=0, TYPE_INT, 0}, \ {"disable-stats", CONFIG_HLP_STATS_DISABLE, PARAMFLAG_BOOL, .iptr=&stats_disabled, .defintval=0, TYPE_INT, 0}, \ {"no-itti-threads", CONFIG_HLP_NOITTI, PARAMFLAG_BOOL, .iptr=&softmodem_params.no_itti, .defintval=0, TYPE_INT, 0}, \ - {"ldpc-offload-enable", CONFIG_HLP_LDPC_OFFLOAD, PARAMFLAG_BOOL, .iptr=&LDPC_OFFLOAD_FLAG, .defstrval=0, TYPE_INT, 0}, \ {"sync-ref", CONFIG_HLP_SYNC_REF, 0, .uptr=&SYNC_REF, .defintval=0, TYPE_UINT, 0}, \ {"A" , CONFIG_HLP_TADV, 0, .iptr=&softmodem_params.command_line_sample_advance,.defintval=0, TYPE_INT, 0}, \ {"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, .iptr=&softmodem_params.threequarter_fs, .defintval=0, TYPE_INT, 0}, \ @@ -231,7 +229,6 @@ extern int usrp_tx_thread; { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ - { .s5 = { NULL } }, \ } // clang-format on diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 677401ae47..b0cc3803de 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -356,6 +356,7 @@ void free_nr_ue_dl_harq(NR_DL_UE_HARQ_t harq_list[2][NR_MAX_DLSCH_HARQ_PROCESSES free_and_zero(harq_list[j][i].c[r]); free_and_zero(harq_list[j][i].d[r]); } + free_and_zero(harq_list[j][i].b); free_and_zero(harq_list[j][i].c); free_and_zero(harq_list[j][i].d); } @@ -406,6 +407,7 @@ void nr_init_dl_harq_processes(NR_DL_UE_HARQ_t harq_list[2][NR_MAX_DLSCH_HARQ_PR memset(harq_list[j] + i, 0, sizeof(NR_DL_UE_HARQ_t)); init_downlink_harq_status(harq_list[j] + i); + harq_list[j][i].b = malloc16_clear(a_segments * 1056); harq_list[j][i].c = malloc16(a_segments*sizeof(uint8_t *)); harq_list[j][i].d = malloc16(a_segments*sizeof(int16_t *)); const int sz=5*8448*sizeof(int16_t); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c index 8285a7036c..4fb88ec969 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c @@ -19,16 +19,8 @@ * contact@openairinterface.org */ -/*! \file PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c -* \brief Top-level routines for decoding Turbo-coded (DLSCH) transport channels from 36-212, V8.6 2009-03 -* \author R. Knopp -* \date 2011 -* \version 0.1 -* \company Eurecom -* \email: knopp@eurecom.fr -* \note -* \warning -*/ +/*! \file PHY/NR_UE_TRANSPORT/nr_dlsch_decoding_slot.c + */ #include "common/utils/LOG/vcd_signal_dumper.h" #include "PHY/defs_nr_UE.h" @@ -36,6 +28,7 @@ #include "PHY/phy_extern_nr_ue.h" #include "PHY/CODING/coding_extern.h" #include "PHY/CODING/coding_defs.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" #include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h" #include "SCHED_NR_UE/defs.h" #include "SIMULATION/TOOLS/sim.h" @@ -45,11 +38,6 @@ #include "openair1/PHY/TOOLS/phy_scope_interface.h" #include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h" -//#define ENABLE_PHY_PAYLOAD_DEBUG 1 - -#define OAI_UL_LDPC_MAX_NUM_LLR 27000//26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX = 68*384 -//#define OAI_LDPC_MAX_NUM_LLR 27000//26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX - static extended_kpi_ue kpiStructure = {0}; extended_kpi_ue* getKPIUE(void) { @@ -69,371 +57,302 @@ void nr_dlsch_unscrambling(int16_t *llr, uint32_t size, uint8_t q, uint32_t Nid, nr_codeword_unscrambling(llr, size, q, Nid, n_RNTI); } -static bool nr_ue_postDecode(PHY_VARS_NR_UE *phy_vars_ue, - ldpcDecode_ue_t *rdata, - bool last, - int b_size, - uint8_t b[b_size], - int *num_seg_ok, - const UE_nr_rxtx_proc_t *proc) +/*! \brief Prepare necessary parameters for nrLDPC_coding_interface + */ +uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, + const UE_nr_rxtx_proc_t *proc, + NR_UE_DLSCH_t *dlsch, + int16_t **dlsch_llr, + uint8_t **b, + int *G, + int nb_dlsch, + uint8_t *DLSCH_ids) { - NR_DL_UE_HARQ_t *harq_process = rdata->harq_process; - NR_UE_DLSCH_t *dlsch = (NR_UE_DLSCH_t *) rdata->dlsch; - int r = rdata->segment_r; + nrLDPC_TB_decoding_parameters_t TBs[nb_dlsch]; + memset(TBs, 0, sizeof(TBs)); + nrLDPC_slot_decoding_parameters_t slot_parameters = { + .frame = proc->frame_rx, + .slot = proc->nr_slot_rx, + .nb_TBs = nb_dlsch, + .threadPool = &get_nrUE_params()->Tpool, + .TBs = TBs + }; - merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_DEINTERLEAVING_STATS], &rdata->ts_deinterleave); - merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_RATE_UNMATCHING_STATS], &rdata->ts_rate_unmatch); - merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_LDPC_DECODING_STATS], &rdata->ts_ldpc_decode); + int max_num_segments = 0; - bool decodeSuccess = (rdata->decodeIterations < (1+dlsch->max_ldpc_iterations)); + for (uint8_t pdsch_id = 0; pdsch_id < nb_dlsch; pdsch_id++) { + uint8_t DLSCH_id = DLSCH_ids[pdsch_id]; + fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[DLSCH_id].dlsch_config; + uint8_t dmrs_Type = dlsch_config->dmrsConfigType; + int harq_pid = dlsch_config->harq_process_nbr; + NR_DL_UE_HARQ_t *harq_process = &phy_vars_ue->dl_harq_processes[DLSCH_id][harq_pid]; - if (decodeSuccess) { - memcpy(b+rdata->offset, - harq_process->c[r], - rdata->Kr_bytes - (harq_process->F>>3) -((harq_process->C>1)?3:0)); + AssertFatal(dmrs_Type == 0 || dmrs_Type == 1, "Illegal dmrs_type %d\n", dmrs_Type); + uint8_t nb_re_dmrs; - (*num_seg_ok)++; - } else { - LOG_D(PHY, "DLSCH %d in error\n", rdata->dlsch_id); + LOG_D(PHY, "Round %d RV idx %d\n", harq_process->DLround, dlsch->dlsch_config.rv); + + if (dmrs_Type == NFAPI_NR_DMRS_TYPE1) + nb_re_dmrs = 6 * dlsch_config->n_dmrs_cdm_groups; + else + nb_re_dmrs = 4 * dlsch_config->n_dmrs_cdm_groups; + uint16_t dmrs_length = get_num_dmrs(dlsch_config->dlDmrsSymbPos); + + if (!harq_process) { + LOG_E(PHY, "dlsch_decoding_slot.c: NULL harq_process pointer\n"); + return dlsch[DLSCH_id].max_ldpc_iterations + 1; + } + + nrLDPC_TB_decoding_parameters_t *TB_parameters = &TBs[pdsch_id]; + + /* Neither harq_pid nor DLSCH_id are unique in the instance + * but their combination is. + * Since DLSCH_id < 2 + * then 2 * harq_pid + DLSCH_id is unique. + */ + TB_parameters->harq_unique_pid = 2 * harq_pid + DLSCH_id; + + // ------------------------------------------------------------------ + TB_parameters->G = G[DLSCH_id]; + TB_parameters->nb_rb = dlsch_config->number_rbs; + TB_parameters->Qm = dlsch_config->qamModOrder; + TB_parameters->mcs = dlsch_config->mcs; + TB_parameters->nb_layers = dlsch[DLSCH_id].Nl; + TB_parameters->BG = dlsch_config->ldpcBaseGraph; + TB_parameters->A = dlsch_config->TBS; + // ------------------------------------------------------------------ + + TB_parameters->processedSegments = &harq_process->processedSegments; + + float Coderate = (float)dlsch->dlsch_config.targetCodeRate / 10240.0f; + + LOG_D( + PHY, + "%d.%d DLSCH %d Decoding, harq_pid %d TBS %d G %d nb_re_dmrs %d length dmrs %d mcs %d Nl %d nb_symb_sch %d nb_rb %d Qm %d " + "Coderate %f\n", + slot_parameters.frame, + slot_parameters.slot, + DLSCH_id, + harq_pid, + dlsch_config->TBS, + TB_parameters->G, + nb_re_dmrs, + dmrs_length, + TB_parameters->mcs, + TB_parameters->nb_layers, + dlsch_config->number_symbols, + TB_parameters->nb_rb, + TB_parameters->Qm, + Coderate); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_IN); + + if (harq_process->first_rx == 1) { + // This is a new packet, so compute quantities regarding segmentation + nr_segmentation(NULL, + NULL, + lenWithCrc(1, TB_parameters->A), // We give a max size in case of 1 segment + &TB_parameters->C, + &TB_parameters->K, + &TB_parameters->Z, // [hna] Z is Zc + &TB_parameters->F, + TB_parameters->BG); + harq_process->C = TB_parameters->C; + harq_process->K = TB_parameters->K; + harq_process->Z = TB_parameters->Z; + harq_process->F = TB_parameters->F; + + if (harq_process->C > MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * TB_parameters->nb_layers) { + LOG_E(PHY, "nr_segmentation.c: too many segments %d, A %d\n", harq_process->C, TB_parameters->A); + return dlsch[DLSCH_id].max_ldpc_iterations + 1; + } + + if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD) && (!slot_parameters.frame % 100)) + LOG_I(PHY, "K %d C %d Z %d nl %d \n", harq_process->K, harq_process->C, harq_process->Z, TB_parameters->nb_layers); + // clear HARQ buffer + for (int i = 0; i < harq_process->C; i++) + memset(harq_process->d[i], 0, 5 * 8448 * sizeof(int16_t)); + } else { + // This is not a new packet, so retrieve previously computed quantities regarding segmentation + TB_parameters->C = harq_process->C; + TB_parameters->K = harq_process->K; + TB_parameters->Z = harq_process->Z; + TB_parameters->F = harq_process->F; + } + max_num_segments = max(max_num_segments, TB_parameters->C); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_OUT); + + if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD)) + LOG_I(PHY, "Segmentation: C %d, K %d\n", harq_process->C, harq_process->K); + + TB_parameters->max_ldpc_iterations = dlsch[DLSCH_id].max_ldpc_iterations; + TB_parameters->rv_index = dlsch_config->rv; + TB_parameters->tbslbrm = dlsch_config->tbslbrm; + TB_parameters->abort_decode = &harq_process->abort_decode; + set_abort(&harq_process->abort_decode, false); } - if (!last) - return false; // continue decoding + nrLDPC_segment_decoding_parameters_t segments[nb_dlsch][max_num_segments]; + memset(segments, 0, sizeof(segments)); + bool d_to_be_cleared[nb_dlsch][max_num_segments]; + memset(d_to_be_cleared, 0, sizeof(d_to_be_cleared)); - // all segments are done - kpiStructure.nb_total++; - kpiStructure.blockSize = dlsch->dlsch_config.TBS; - kpiStructure.dl_mcs = dlsch->dlsch_config.mcs; - kpiStructure.nofRBs = dlsch->dlsch_config.number_rbs; + for (uint8_t pdsch_id = 0; pdsch_id < nb_dlsch; pdsch_id++) { + uint8_t DLSCH_id = DLSCH_ids[pdsch_id]; + fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[DLSCH_id].dlsch_config; + int harq_pid = dlsch_config->harq_process_nbr; + NR_DL_UE_HARQ_t *harq_process = &phy_vars_ue->dl_harq_processes[DLSCH_id][harq_pid]; - harq_process->decodeResult = *num_seg_ok == harq_process->C; + nrLDPC_TB_decoding_parameters_t *TB_parameters = &TBs[pdsch_id]; + TB_parameters->segments = segments[pdsch_id]; - if (harq_process->decodeResult && harq_process->C > 1) { - /* check global CRC */ - int A = dlsch->dlsch_config.TBS; - // we have regrouped the transport block - if (!check_crc(b, lenWithCrc(1, A), crcType(1, A))) { - LOG_E(PHY, - " Frame %d.%d LDPC global CRC fails, but individual LDPC CRC succeeded. %d segs\n", - proc->frame_rx, - proc->nr_slot_rx, - harq_process->C); - harq_process->decodeResult = false; + uint32_t r_offset = 0; + for (int r = 0; r < TB_parameters->C; r++) { + if (harq_process->first_rx == 1) + d_to_be_cleared[pdsch_id][r] = true; + else + d_to_be_cleared[pdsch_id][r] = false; + nrLDPC_segment_decoding_parameters_t *segment_parameters = &TB_parameters->segments[r]; + segment_parameters->E = nr_get_E(TB_parameters->G, + TB_parameters->C, + TB_parameters->Qm, + TB_parameters->nb_layers, + r); + segment_parameters->R = nr_get_R_ldpc_decoder(TB_parameters->rv_index, + segment_parameters->E, + TB_parameters->BG, + TB_parameters->Z, + &harq_process->llrLen, + harq_process->DLround); + segment_parameters->llr = dlsch_llr[DLSCH_id] + r_offset; + segment_parameters->d = harq_process->d[r]; + segment_parameters->d_to_be_cleared = &d_to_be_cleared[pdsch_id][r]; + segment_parameters->c = harq_process->c[r]; + segment_parameters->decodeSuccess = false; + + reset_meas(&segment_parameters->ts_deinterleave); + reset_meas(&segment_parameters->ts_rate_unmatch); + reset_meas(&segment_parameters->ts_ldpc_decode); + + r_offset += segment_parameters->E; } } - if (harq_process->decodeResult) { - // We search only a reccuring OAI error that propagates all 0 packets with a 0 CRC, so we - const int sz = dlsch->dlsch_config.TBS / 8; - if (b[sz] == 0 && b[sz + 1] == 0) { - // do the check only if the 2 first bytes of the CRC are 0 (it can be CRC16 or CRC24) - int i = 0; - while (b[i] == 0 && i < sz) - i++; - if (i == sz) { + int ret_decoder = phy_vars_ue->nrLDPC_coding_interface.nrLDPC_coding_decoder(&slot_parameters); + + if (ret_decoder != 0) { + return dlsch->max_ldpc_iterations + 1; + } + + // post decode + for (uint8_t pdsch_id = 0; pdsch_id < nb_dlsch; pdsch_id++) { + uint8_t DLSCH_id = DLSCH_ids[pdsch_id]; + fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[DLSCH_id].dlsch_config; + int harq_pid = dlsch_config->harq_process_nbr; + NR_DL_UE_HARQ_t *harq_process = &phy_vars_ue->dl_harq_processes[DLSCH_id][harq_pid]; + + nrLDPC_TB_decoding_parameters_t *TB_parameters = &TBs[pdsch_id]; + + uint32_t offset = 0; + for (int r = 0; r < TB_parameters->C; r++) { + nrLDPC_segment_decoding_parameters_t *segment_parameters = &TB_parameters->segments[r]; + if (segment_parameters->decodeSuccess) { + memcpy(b[DLSCH_id] + offset, + harq_process->c[r], + (harq_process->K >> 3) - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0)); + } else { + fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[DLSCH_id].dlsch_config; + LOG_D(PHY, "frame=%d, slot=%d, first_rx=%d, rv_index=%d\n", proc->frame_rx, proc->nr_slot_rx, harq_process->first_rx, dlsch_config->rv); + LOG_D(PHY, "downlink segment error %d/%d\n", r, harq_process->C); + LOG_D(PHY, "DLSCH %d in error\n", DLSCH_id); + } + offset += (harq_process->K >> 3) - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0); + + merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_DEINTERLEAVING_STATS], &segment_parameters->ts_deinterleave); + merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_RATE_UNMATCHING_STATS], &segment_parameters->ts_rate_unmatch); + merge_meas(&phy_vars_ue->phy_cpu_stats.cpu_time_stats[DLSCH_LDPC_DECODING_STATS], &segment_parameters->ts_ldpc_decode); + + } + + kpiStructure.nb_total++; + kpiStructure.blockSize = dlsch_config->TBS; + kpiStructure.dl_mcs = dlsch_config->mcs; + kpiStructure.nofRBs = dlsch_config->number_rbs; + + harq_process->decodeResult = harq_process->processedSegments == harq_process->C; + + if (harq_process->decodeResult && harq_process->C > 1) { + /* check global CRC */ + int A = dlsch->dlsch_config.TBS; + // we have regrouped the transport block + if (!check_crc(b[DLSCH_id], lenWithCrc(1, A), crcType(1, A))) { LOG_E(PHY, - "received all 0 pdu, consider it false reception, even if the TS 38.212 7.2.1 says only we should attach the " - "corresponding CRC, and nothing prevents to have a all 0 packet\n"); + " Frame %d.%d LDPC global CRC fails, but individual LDPC CRC succeeded. %d segs\n", + proc->frame_rx, + proc->nr_slot_rx, + harq_process->C); harq_process->decodeResult = false; } } - } - if (harq_process->decodeResult) { - LOG_D(PHY, "DLSCH received ok \n"); - harq_process->status = SCH_IDLE; - dlsch->last_iteration_cnt = rdata->decodeIterations; - } else { - LOG_D(PHY, "DLSCH received nok \n"); - kpiStructure.nb_nack++; - dlsch->last_iteration_cnt = dlsch->max_ldpc_iterations + 1; - } - return true; // end TB decoding -} - -static void nr_processDLSegment(void *arg) -{ - ldpcDecode_ue_t *rdata = (ldpcDecode_ue_t*) arg; - NR_UE_DLSCH_t *dlsch = rdata->dlsch; - NR_DL_UE_HARQ_t *harq_process= rdata->harq_process; - t_nrLDPC_dec_params *p_decoderParms = &rdata->decoderParms; - int r = rdata->segment_r; - int E = rdata->E; - int Qm = rdata->Qm; - int r_offset = rdata->r_offset; - uint8_t kc = rdata->Kc; - uint32_t Tbslbrm = rdata->Tbslbrm; - short* dlsch_llr = rdata->dlsch_llr; - int8_t LDPCoutput[OAI_UL_LDPC_MAX_NUM_LLR] __attribute__((aligned(32))); - int16_t z[68 * 384 + 16] __attribute__((aligned(16))); - int8_t l [68*384 + 16] __attribute__ ((aligned(16))); - - const int Kr = harq_process->K; - const int K_bits_F = Kr - harq_process->F; - - t_nrLDPC_time_stats procTime = {0}; - - //if we return before LDPC decoder run, the block is in error - rdata->decodeIterations = dlsch->max_ldpc_iterations + 1; - - start_meas(&rdata->ts_deinterleave); - - //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DEINTERLEAVING, VCD_FUNCTION_IN); - int16_t w[E]; - nr_deinterleaving_ldpc(E, - Qm, - w, // [hna] w is e - dlsch_llr+r_offset); - //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DEINTERLEAVING, VCD_FUNCTION_OUT); - stop_meas(&rdata->ts_deinterleave); - - start_meas(&rdata->ts_rate_unmatch); - /* LOG_D(PHY,"HARQ_PID %d Rate Matching Segment %d (coded bits %d,E %d, F %d,unpunctured/repeated bits %d, TBS %d, mod_order %d, nb_rb %d, Nl %d, rv %d, round %d)...\n", - harq_pid,r, G,E,harq_process->F, - Kr*3, - harq_process->TBS, - Qm, - harq_process->nb_rb, - harq_process->Nl, - harq_process->rvidx, - harq_process->round); */ - //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_RATE_MATCHING, VCD_FUNCTION_IN); - - if (nr_rate_matching_ldpc_rx(Tbslbrm, - p_decoderParms->BG, - p_decoderParms->Z, - harq_process->d[r], - w, - harq_process->C, - dlsch->dlsch_config.rv, - harq_process->first_rx, - E, - harq_process->F, - Kr-harq_process->F-2*(p_decoderParms->Z))==-1) { - //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_RATE_MATCHING, VCD_FUNCTION_OUT); - stop_meas(&rdata->ts_rate_unmatch); - LOG_E(PHY,"dlsch_decoding.c: Problem in rate_matching\n"); - return; - } - stop_meas(&rdata->ts_rate_unmatch); - - if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD)) { - LOG_D(PHY,"decoder input(segment %u) :",r); - - for (int i=0; id[r][i]); - - LOG_D(PHY,"\n"); - } - { - start_meas(&rdata->ts_ldpc_decode); - //set first 2*Z_c bits to zeros - memset(z,0,2*harq_process->Z*sizeof(int16_t)); - //set Filler bits - memset((z+K_bits_F),127,harq_process->F*sizeof(int16_t)); - //Move coded bits before filler bits - memcpy((z+2*harq_process->Z),harq_process->d[r],(K_bits_F-2*harq_process->Z)*sizeof(int16_t)); - //skip filler bits - memcpy((z+Kr),harq_process->d[r]+(Kr-2*harq_process->Z),(kc*harq_process->Z-Kr)*sizeof(int16_t)); - - //Saturate coded bits before decoding into 8 bits values - simde__m128i *pv = (simde__m128i*)&z; - simde__m128i *pl = (simde__m128i*)&l; - for (int i=0, j=0; j < ((kc*harq_process->Z)>>4)+1; i+=2, j++) { - pl[j] = simde_mm_packs_epi16(pv[i],pv[i+1]); + if (harq_process->decodeResult) { + // We search only a reccuring OAI error that propagates all 0 packets with a 0 CRC, so we + const int sz = dlsch->dlsch_config.TBS / 8; + if (b[DLSCH_id][sz] == 0 && b[DLSCH_id][sz + 1] == 0) { + // do the check only if the 2 first bytes of the CRC are 0 (it can be CRC16 or CRC24) + int i = 0; + while (b[DLSCH_id][i] == 0 && i < sz) + i++; + if (i == sz) { + LOG_E(PHY, + "received all 0 pdu, consider it false reception, even if the TS 38.212 7.2.1 says only we should attach the " + "corresponding CRC, and nothing prevents to have a all 0 packet\n"); + harq_process->decodeResult = false; + } + } } - //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_LDPC, VCD_FUNCTION_IN); - uint32_t A = dlsch->dlsch_config.TBS; - p_decoderParms->E = lenWithCrc(harq_process->C, A); - p_decoderParms->crc_type = crcType(harq_process->C, A); - rdata->decodeIterations = - ldpc_interface.LDPCdecoder(p_decoderParms, 0, 0, 0, l, LDPCoutput, &procTime, &harq_process->abort_decode); - //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_LDPC, VCD_FUNCTION_OUT); - - if (rdata->decodeIterations <= dlsch->max_ldpc_iterations) - memcpy(harq_process->c[r], LDPCoutput, Kr >> 3); - stop_meas(&rdata->ts_ldpc_decode); - } - completed_task_ans(rdata->ans); -} - -uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, - const UE_nr_rxtx_proc_t *proc, - int eNB_id, - short *dlsch_llr, - NR_DL_FRAME_PARMS *frame_parms, - NR_UE_DLSCH_t *dlsch, - NR_DL_UE_HARQ_t *harq_process, - uint32_t frame, - uint16_t nb_symb_sch, - uint8_t nr_slot_rx, - uint8_t harq_pid, - int b_size, - uint8_t b[b_size], - int G) -{ - uint32_t ret,offset; - uint32_t r,r_offset=0,Kr=8424,Kr_bytes; - t_nrLDPC_dec_params decParams; - decParams.check_crc = check_crc; - - if (!harq_process) { - LOG_E(PHY,"dlsch_decoding.c: NULL harq_process pointer\n"); - return(dlsch->max_ldpc_iterations + 1); - } - - // HARQ stats - LOG_D(PHY, "Round %d RV idx %d\n", harq_process->DLround, dlsch->dlsch_config.rv); - uint16_t nb_rb;// = 30; - uint8_t dmrs_Type = dlsch->dlsch_config.dmrsConfigType; - AssertFatal(dmrs_Type == 0 || dmrs_Type == 1, "Illegal dmrs_type %d\n", dmrs_Type); - uint8_t nb_re_dmrs; - - if (dmrs_Type==NFAPI_NR_DMRS_TYPE1) { - nb_re_dmrs = 6*dlsch->dlsch_config.n_dmrs_cdm_groups; - } else { - nb_re_dmrs = 4*dlsch->dlsch_config.n_dmrs_cdm_groups; - } - - uint16_t dmrs_length = get_num_dmrs(dlsch->dlsch_config.dlDmrsSymbPos); - vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_IN); - - //NR_DL_UE_HARQ_t *harq_process = dlsch->harq_processes[0]; - - if (!dlsch_llr) { - LOG_E(PHY,"dlsch_decoding.c: NULL dlsch_llr pointer\n"); - return(dlsch->max_ldpc_iterations + 1); - } - - if (!frame_parms) { - LOG_E(PHY,"dlsch_decoding.c: NULL frame_parms pointer\n"); - return(dlsch->max_ldpc_iterations + 1); - } - - nb_rb = dlsch->dlsch_config.number_rbs; - uint32_t A = dlsch->dlsch_config.TBS; - ret = dlsch->max_ldpc_iterations + 1; - dlsch->last_iteration_cnt = ret; - - // target_code_rate is in 0.1 units - float Coderate = (float) dlsch->dlsch_config.targetCodeRate / 10240.0f; - - decParams.BG = dlsch->dlsch_config.ldpcBaseGraph; - unsigned int kc = decParams.BG == 2 ? 52 : 68; - - if (harq_process->first_rx == 1) { - // This is a new packet, so compute quantities regarding segmentation - nr_segmentation(NULL, - NULL, - lenWithCrc(1, A), // We give a max size in case of 1 segment - &harq_process->C, - &harq_process->K, - &harq_process->Z, // [hna] Z is Zc - &harq_process->F, - decParams.BG); - - if (harq_process->C > MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * dlsch->Nl) { - LOG_E(PHY, "nr_segmentation.c: too many segments %d, A %d\n", harq_process->C, A); - return(-1); + if (harq_process->decodeResult) { + LOG_D(PHY, "DLSCH received ok \n"); + harq_process->status = SCH_IDLE; + dlsch->last_iteration_cnt = dlsch->max_ldpc_iterations; + } else { + LOG_D(PHY, "DLSCH received nok \n"); + kpiStructure.nb_nack++; + dlsch->last_iteration_cnt = dlsch->max_ldpc_iterations + 1; } - if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD) && (!frame%100)) - LOG_I(PHY,"K %d C %d Z %d nl %d \n", harq_process->K, harq_process->C, harq_process->Z, dlsch->Nl); - // clear HARQ buffer - for (int i=0; i C; i++) - memset(harq_process->d[i],0,5*8448*sizeof(int16_t)); + uint8_t dmrs_Type = dlsch_config->dmrsConfigType; + uint8_t nb_re_dmrs; + if (dmrs_Type == NFAPI_NR_DMRS_TYPE1) + nb_re_dmrs = 6 * dlsch_config->n_dmrs_cdm_groups; + else + nb_re_dmrs = 4 * dlsch_config->n_dmrs_cdm_groups; + uint16_t dmrs_length = get_num_dmrs(dlsch_config->dlDmrsSymbPos); + float Coderate = (float)dlsch->dlsch_config.targetCodeRate / 10240.0f; + LOG_D(PHY, + "%d.%d DLSCH Decoded, harq_pid %d, round %d, result: %d TBS %d (%d) G %d nb_re_dmrs %d length dmrs %d mcs %d Nl %d " + "nb_symb_sch %d " + "nb_rb %d Qm %d Coderate %f\n", + proc->frame_rx, + proc->nr_slot_rx, + harq_pid, + harq_process->DLround, + harq_process->decodeResult, + dlsch->dlsch_config.TBS, + dlsch->dlsch_config.TBS / 8, + G[DLSCH_id], + nb_re_dmrs, + dmrs_length, + dlsch->dlsch_config.mcs, + dlsch->Nl, + dlsch_config->number_symbols, + dlsch_config->number_rbs, + dlsch_config->qamModOrder, + Coderate); + } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_OUT); - decParams.Z = harq_process->Z; - decParams.numMaxIter = dlsch->max_ldpc_iterations; - decParams.outMode = 0; - r_offset = 0; - uint16_t a_segments = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * dlsch->Nl; //number of segments to be allocated - - if (nb_rb != 273) { - a_segments = a_segments*nb_rb; - a_segments = a_segments/273 +1; - } - - if (harq_process->C > a_segments) { - LOG_E(PHY,"Illegal harq_process->C %d > %d\n",harq_process->C,a_segments); - return((1+dlsch->max_ldpc_iterations)); - } - - if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD)) - LOG_I(PHY,"Segmentation: C %d, K %d\n",harq_process->C,harq_process->K); - - Kr = harq_process->K; - Kr_bytes = Kr>>3; - offset = 0; - - ldpcDecode_ue_t arr[harq_process->C]; - task_ans_t ans[harq_process->C]; - memset(ans, 0, harq_process->C * sizeof(task_ans_t)); - set_abort(&harq_process->abort_decode, false); - for (r=0; rC; r++) { - //printf("start rx segment %d\n",r); - uint32_t E = nr_get_E(G, harq_process->C, dlsch->dlsch_config.qamModOrder, dlsch->Nl, r); - decParams.R = nr_get_R_ldpc_decoder(dlsch->dlsch_config.rv, E, decParams.BG, decParams.Z, &harq_process->llrLen, harq_process->DLround); - ldpcDecode_ue_t *rdata = &arr[r]; - rdata->ans = &ans[r]; - - rdata->phy_vars_ue = phy_vars_ue; - rdata->harq_process = harq_process; - rdata->decoderParms = decParams; - rdata->dlsch_llr = dlsch_llr; - rdata->Kc = kc; - rdata->segment_r = r; - rdata->E = E; - rdata->Qm = dlsch->dlsch_config.qamModOrder; - rdata->r_offset = r_offset; - rdata->Kr_bytes = Kr_bytes; - rdata->rv_index = dlsch->dlsch_config.rv; - rdata->Tbslbrm = dlsch->dlsch_config.tbslbrm; - rdata->offset = offset; - rdata->dlsch = dlsch; - rdata->dlsch_id = harq_pid; - reset_meas(&rdata->ts_deinterleave); - reset_meas(&rdata->ts_rate_unmatch); - reset_meas(&rdata->ts_ldpc_decode); - task_t t = {.args = rdata, .func = nr_processDLSegment}; - pushTpool(&get_nrUE_params()->Tpool, t); - LOG_D(PHY, "Added a block to decode, in pipe: %d\n", r); - r_offset += E; - offset += (Kr_bytes - (harq_process->F>>3) - ((harq_process->C>1)?3:0)); - ////////////////////////////////////////////////////////////////////////////////////////// - } - int num_seg_ok = 0; - int nbDecode = harq_process->C; - if (nbDecode > 0) { - join_task_ans(ans, nbDecode); - for (size_t i = 0; i < nbDecode; ++i) { - nr_ue_postDecode(phy_vars_ue, &arr[i], i == nbDecode - 1, b_size, b, &num_seg_ok, proc); - } - } - LOG_D(PHY, - "%d.%d DLSCH Decoded, harq_pid %d, round %d, result: %d TBS %d (%d) G %d nb_re_dmrs %d length dmrs %d mcs %d Nl %d " - "nb_symb_sch %d " - "nb_rb %d Qm %d Coderate %f\n", - frame, - nr_slot_rx, - harq_pid, - harq_process->DLround, - harq_process->decodeResult, - A, - A / 8, - G, - nb_re_dmrs, - dmrs_length, - dlsch->dlsch_config.mcs, - dlsch->Nl, - nb_symb_sch, - nb_rb, - dlsch->dlsch_config.qamModOrder, - Coderate); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_COMBINE_SEG, VCD_FUNCTION_OUT); - ret = dlsch->last_iteration_cnt; - return(ret); + return dlsch[0].last_iteration_cnt; } diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index 176ed67cf3..0ca616ba34 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -65,50 +65,51 @@ void nr_conjch0_mult_ch1(int *ch0, unsigned short nb_rb, unsigned char output_shift0); -/** \brief This is the top-level entry point for DLSCH decoding in UE. It should be replicated on several - threads (on multi-core machines) corresponding to different HARQ processes. The routine first - computes the segmentation information, followed by rate dematching and sub-block deinterleaving the of the - received LLRs computed by dlsch_demodulation for each transport block segment. It then calls the - turbo-decoding algorithm for each segment and stops after either after unsuccesful decoding of at least - one segment or correct decoding of all segments. Only the segment CRCs are check for the moment, the - overall CRC is ignored. Finally transport block reassembly is performed. - @param phy_vars_ue Pointer to ue variables - @param proc - @param eNB_id - @param dlsch_llr Pointer to LLR values computed by dlsch_demodulation - @param frame_parms Pointer to frame descriptor - @param dlsch Pointer to DLSCH descriptor - @param harq_process - @param frame Frame number - @param nb_symb_sch - @param nr_slot_rx Slot number - @param harq_pid - @param b_size - @param b +/** \brief This is the alternative top-level entry point for DLSCH decoding in UE. + It handles all the HARQ processes in only one call. The routine first + computes the segmentation information and then call LDPC decoder on the + received LLRs computed by dlsch_demodulation. + It stops after either unsuccesful decoding of at least + one segment or correct decoding of all segments. Only the segment CRCs are checked for the moment, the + overall CRC is ignored. Finally transport block reassembly is performed. + @param[in] phy_vars_ue Pointer to ue variables + @param[in] proc + @param[in] dlsch_llr Pointers to LLR values computed by dlsch_demodulation + @param[in] b + @param[in] G array of Gs + @param[in] nb_dlsch number of active downlink shared channels + @param[in] DLSCH_ids array of active downlink shared channels @returns 0 on success, 1 on unsuccessful decoding */ - uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, const UE_nr_rxtx_proc_t *proc, - int eNB_id, - short *dlsch_llr, - NR_DL_FRAME_PARMS *frame_parms, NR_UE_DLSCH_t *dlsch, - NR_DL_UE_HARQ_t *harq_process, - uint32_t frame, - uint16_t nb_symb_sch, - uint8_t nr_slot_rx, - uint8_t harq_pid, - int b_size, - uint8_t b[b_size], - int G); + short **dlsch_llr, + uint8_t **b, + int *G, + int nb_dlsch, + uint8_t *DLSCH_ids); +/** \brief This is the alternative top-level entry point for ULSCH encoding in UE. + It handles all the HARQ processes in only one call. The routine first + computes the segmentation information, followed by LDPC encoding algorithm of the + Transport Block. + @param[in] phy_vars_ue pointer to ue variables + @param[in] ulsch Pointer to ULSCH descriptor + @param[in] frame frame index + @param[in] slot slot index + @param[in] G array of Gs + @param[in] nb_ulsch number of uplink shared channels + @param[in] ULSCH_ids array of uplink shared channel ids + @returns 0 on success, -1 on unsuccessful decoding +*/ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, - NR_UE_ULSCH_t *ulsch, - NR_DL_FRAME_PARMS* frame_parms, - uint8_t harq_pid, - uint32_t tb_size, - unsigned int G); + NR_UE_ULSCH_t *ulsch, + const uint32_t frame, + const uint8_t slot, + unsigned int *G, + int nb_ulsch, + uint8_t *ULSCH_ids); /*! \brief Perform PUSCH scrambling. TS 38.211 V15.4.0 subclause 6.3.1.1 @param[in] in Pointer to input bits @@ -125,18 +126,23 @@ void nr_pusch_codeword_scrambling(uint8_t *in, bool uci_on_pusch, uint32_t* out); -/** \brief Perform the following functionalities: + +/** \brief Alternative entry point to UE uplink shared channels procedures. + It handles all the HARQ processes in only one call. + Performs the following functionalities: - encoding - scrambling - modulation - transform precoding + @param[in] UE pointer to ue variables + @param[in] frame frame index + @param[in] slot slot index + @param[in] phy_data PHY layer informations + @param[in] c16_t */ - void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, - const unsigned char harq_pid, const uint32_t frame, const uint8_t slot, - const int gNB_id, nr_phy_data_tx_t *phy_data, c16_t **txdataF); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h index cd24114323..419988a961 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h @@ -104,6 +104,8 @@ typedef struct { uint8_t first_rx; /// DLSCH status flag indicating SCH_status_t status; + /// Pointer to the payload (38.212 V15.4.0 section 5.1) + uint8_t *b; /// Pointers to transport block segments uint8_t **c; /// soft bits for each received segment ("d"-sequence)(for definition see 36-212 V8.6 2009-03, p.15) @@ -126,6 +128,8 @@ typedef struct { /// Last index of LLR buffer that contains information. /// Used for computing LDPC decoder R int llrLen; + /// Number of segments processed so far + uint32_t processedSegments; decode_abort_t abort_decode; } NR_DL_UE_HARQ_t; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c index d4cf69d8f4..bed86bf852 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c @@ -19,16 +19,8 @@ * contact@openairinterface.org */ -/*! \file PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c -* \brief Top-level routines for coding the ULSCH transport channel as described in 38.212 V15.4 2018-12 -* \author Khalid Ahmed -* \date 2019 -* \version 0.1 -* \company Fraunhofer IIS -* \email: khalid.ahmed@iis.fraunhofer.de -* \note -* \warning -*/ +/*! \file PHY/NR_UE_TRANSPORT/nr_ulsch_coding_slot.c + */ #include "PHY/defs_UE.h" #include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h" @@ -36,54 +28,68 @@ #include "PHY/CODING/coding_extern.h" #include "PHY/CODING/lte_interleaver_inline.h" #include "PHY/CODING/nrLDPC_extern.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" #include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h" +#include "executables/nr-uesoftmodem.h" #include "common/utils/LOG/vcd_signal_dumper.h" -//#define DEBUG_ULSCH_CODING - int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, NR_UE_ULSCH_t *ulsch, - NR_DL_FRAME_PARMS* frame_parms, - uint8_t harq_pid, - uint32_t tb_size, - unsigned int G) + const uint32_t frame, + const uint8_t slot, + unsigned int *G, + int nb_ulsch, + uint8_t *ULSCH_ids) { start_meas_nr_ue_phy(ue, ULSCH_ENCODING_STATS); - - /////////////////////////parameters and variables initialization///////////////////////// - - unsigned int crc = 1; - NR_UL_UE_HARQ_t *harq_process = &ue->ul_harq_processes[harq_pid]; - uint16_t nb_rb = ulsch->pusch_pdu.rb_size; - uint32_t A = tb_size << 3; - uint32_t r_offset = 0; - // target_code_rate is in 0.1 units - float Coderate = (float) ulsch->pusch_pdu.target_code_rate / 10240.0f; - encoder_implemparams_t impp = {.n_segments = harq_process->C, - .macro_num = 0, - .K = harq_process->K, - .Kr = harq_process->K, - .Zc = harq_process->Z, - .BG = harq_process->BG, - .F = harq_process->F, - .rv = ulsch->pusch_pdu.pusch_data.rv_index, - .Qm = ulsch->pusch_pdu.qam_mod_order, - .tinput = NULL, - .tprep = NULL, - .tparity = NULL, - .toutput = NULL}; - ///////////////////////////////////////////////////////////////////////////////////////// - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_UE_ULSCH_ENCODING, VCD_FUNCTION_IN); - LOG_D(NR_PHY, "ulsch coding nb_rb %d, Nl = %d\n", nb_rb, ulsch->pusch_pdu.nrOfLayers); - LOG_D(NR_PHY, "ulsch coding A %d G %d mod_order %d Coderate %f\n", A, G, impp.Qm, Coderate); - LOG_D(NR_PHY, "harq_pid %d, pusch_data.new_data_indicator %d\n", harq_pid, ulsch->pusch_pdu.pusch_data.new_data_indicator); - if (ulsch->pusch_pdu.pusch_data.new_data_indicator) { // this is a new packet -#ifdef DEBUG_ULSCH_CODING - printf("encoding thinks this is a new packet \n"); -#endif + + nrLDPC_TB_encoding_parameters_t TBs[nb_ulsch]; + memset(TBs, 0, sizeof(TBs)); + nrLDPC_slot_encoding_parameters_t slot_parameters = { + .frame = frame, + .slot = slot, + .nb_TBs = nb_ulsch, + .threadPool = &get_nrUE_params()->Tpool, + .tinput = NULL, + .tprep = NULL, + .tparity = NULL, + .toutput = NULL, + .TBs = TBs + }; + + int max_num_segments = 0; + + for (uint8_t pusch_id = 0; pusch_id < nb_ulsch; pusch_id++) { + uint8_t ULSCH_id = ULSCH_ids[pusch_id]; + uint8_t harq_pid = ulsch[ULSCH_id].pusch_pdu.pusch_data.harq_process_id; + + nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[pusch_id]; + /* Neither harq_pid nor ULSCH_id are unique in the instance + * but their combination is. + * Since ULSCH_id < 2 + * then 2 * harq_pid + ULSCH_id is unique. + */ + TB_parameters->harq_unique_pid = 2 * harq_pid + ULSCH_id; + + /////////////////////////parameters and variables initialization///////////////////////// + + unsigned int crc = 1; + NR_UL_UE_HARQ_t *harq_process = &ue->ul_harq_processes[harq_pid]; + const nfapi_nr_ue_pusch_pdu_t *pusch_pdu = &ulsch->pusch_pdu; + uint16_t nb_rb = pusch_pdu->rb_size; + uint32_t A = pusch_pdu->pusch_data.tb_size << 3; + uint8_t Qm = pusch_pdu->qam_mod_order; + // target_code_rate is in 0.1 units + float Coderate = (float)pusch_pdu->target_code_rate / 10240.0f; + + LOG_D(NR_PHY, "ulsch coding nb_rb %d, Nl = %d\n", nb_rb, pusch_pdu->nrOfLayers); + LOG_D(NR_PHY, "ulsch coding A %d G %d mod_order %d Coderate %f\n", A, G[pusch_id], Qm, Coderate); + LOG_D(NR_PHY, "harq_pid %d, pusch_data.new_data_indicator %d\n", harq_pid, pusch_pdu->pusch_data.new_data_indicator); + ///////////////////////// a---->| add CRC |---->b ///////////////////////// - int max_payload_bytes = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER*ulsch->pusch_pdu.nrOfLayers*1056; + + int max_payload_bytes = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER * pusch_pdu->nrOfLayers * 1056; int B; if (A > NR_MAX_PDSCH_TBS) { // Add 24-bit crc (polynomial A) to payload @@ -104,137 +110,90 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, ///////////////////////// b---->| block segmentation |---->c ///////////////////////// - harq_process->BG = ulsch->pusch_pdu.ldpcBaseGraph; + harq_process->BG = pusch_pdu->ldpcBaseGraph; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_SEGMENTATION, VCD_FUNCTION_IN); start_meas_nr_ue_phy(ue, ULSCH_SEGMENTATION_STATS); - impp.Kb = nr_segmentation(harq_process->payload_AB, - harq_process->c, - B, - &harq_process->C, - &harq_process->K, - &harq_process->Z, - &harq_process->F, - harq_process->BG); + TB_parameters->Kb = nr_segmentation(harq_process->payload_AB, + harq_process->c, + B, + &harq_process->C, + &harq_process->K, + &harq_process->Z, + &harq_process->F, + harq_process->BG); + TB_parameters->C = harq_process->C; + TB_parameters->K = harq_process->K; + TB_parameters->Z = harq_process->Z; + TB_parameters->F = harq_process->F; + TB_parameters->BG = harq_process->BG; + if (TB_parameters->C > MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * pusch_pdu->nrOfLayers) { + LOG_E(PHY, "nr_segmentation.c: too many segments %d, B %d\n", TB_parameters->C, B); + return (-1); + } stop_meas_nr_ue_phy(ue, ULSCH_SEGMENTATION_STATS); - impp.n_segments = harq_process->C; - impp.K = harq_process->K; - impp.Kr = impp.K; - impp.Zc = harq_process->Z; - impp.F = harq_process->F; - impp.BG = harq_process->BG; - if (impp.n_segments > MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * ulsch->pusch_pdu.nrOfLayers) { - LOG_E(PHY, "nr_segmentation.c: too many segments %d, B %d\n", impp.n_segments, B); - return(-1); - } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_SEGMENTATION, VCD_FUNCTION_OUT); + max_num_segments = max(max_num_segments, TB_parameters->C); -#ifdef DEBUG_ULSCH_CODING - uint16_t Kr_bytes; - Kr_bytes = impp.Kr >> 3; -#endif + TB_parameters->nb_rb = nb_rb; + TB_parameters->Qm = Qm; + TB_parameters->mcs = pusch_pdu->mcs_index; + TB_parameters->nb_layers = pusch_pdu->nrOfLayers; + TB_parameters->rv_index = pusch_pdu->pusch_data.rv_index; + TB_parameters->G = G[pusch_id]; + TB_parameters->tbslbrm = pusch_pdu->tbslbrm; + TB_parameters->A = A; + } // pusch_id - ///////////////////////// c---->| LDCP coding |---->d //////////////////////////////////// - for (int r = 0; r < impp.n_segments; r++) { -#ifdef DEBUG_ULSCH_CODING - printf("Encoder: B %d F %d \n", B, impp.F); - printf("start ldpc encoder segment %d/%d\n", r, impp.n_segments); - printf("input %d %d %d %d %d \n", harq_process->c[r][0], harq_process->c[r][1], harq_process->c[r][2],harq_process->c[r][3], harq_process->c[r][4]); - for (int cnt = 0; cnt < 22 * impp.Zc / 8; cnt++) { - printf("%d ", harq_process->c[r][cnt]); - } - printf("\n"); -#endif - } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_IN); - } + nrLDPC_segment_encoding_parameters_t segments[nb_ulsch][max_num_segments]; + memset(segments, 0, sizeof(segments)); - if (ldpc_interface_offload.LDPCencoder) { - for (int j = 0; j < impp.n_segments; j++) { - impp.perCB[j].E_cb = nr_get_E(G, impp.n_segments, impp.Qm, ulsch->pusch_pdu.nrOfLayers, j); - } - start_meas_nr_ue_phy(ue, ULSCH_LDPC_ENCODING_STATS); - ldpc_interface_offload.LDPCencoder(harq_process->c, &harq_process->f, &impp); - stop_meas_nr_ue_phy(ue, ULSCH_LDPC_ENCODING_STATS); - } else { - if (ulsch->pusch_pdu.pusch_data.new_data_indicator) { - start_meas_nr_ue_phy(ue, ULSCH_LDPC_ENCODING_STATS); - for (int j = 0; j < (impp.n_segments / 8 + 1); j++) { - impp.macro_num = j; - impp.Kr = impp.K; - ldpc_interface.LDPCencoder(harq_process->c, harq_process->d, &impp); - } - stop_meas_nr_ue_phy(ue, ULSCH_LDPC_ENCODING_STATS); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_OUT); + for (uint8_t pusch_id = 0; pusch_id < nb_ulsch; pusch_id++) { + uint8_t ULSCH_id = ULSCH_ids[pusch_id]; + uint8_t harq_pid = ulsch[ULSCH_id].pusch_pdu.pusch_data.harq_process_id; -#ifdef DEBUG_ULSCH_CODING - write_output("ulsch_enc_input0.m", "enc_in0", &harq_process->c[0][0], Kr_bytes, 1, 4); - write_output("ulsch_enc_output0.m", "enc0", &harq_process->d[0][0], (3 * 8 * Kr_bytes) + 12, 1, 4); -#endif - } -/////////////////////////////////////////////////////////////////////////////// - for (int r = 0; r < impp.n_segments; r++) { // looping over C segments - if (impp.F > 0) { - for (int k = impp.Kr - impp.F - 2 * impp.Zc; k < impp.Kr - 2 * impp.Zc; k++) { - harq_process->d[r][k] = NR_NULL; - } - } + nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[pusch_id]; + NR_UL_UE_HARQ_t *harq_process = &ue->ul_harq_processes[harq_pid]; + TB_parameters->segments = segments[pusch_id]; - LOG_D(PHY, - "Rate Matching, Code segment %d (coded bits (G) %u, unpunctured/repeated bits per code segment %d, mod_order %d, nb_rb " - "%d, " - "rvidx %d)...\n", - r, - G, - impp.Kr * 3, - impp.Qm, - nb_rb, - ulsch->pusch_pdu.pusch_data.rv_index); + int r_offset = 0; + for (int r = 0; r < TB_parameters->C; r++) { + nrLDPC_segment_encoding_parameters_t *segment_parameters = &TB_parameters->segments[r]; + segment_parameters->c = harq_process->c[r]; + segment_parameters->E = nr_get_E(TB_parameters->G, + TB_parameters->C, + TB_parameters->Qm, + TB_parameters->nb_layers, + r); + segment_parameters->output = harq_process->f + r_offset; + r_offset += segment_parameters->E; - ///////////////////////// d---->| Rate matching bit selection |---->e ///////////////////////// - impp.perCB[r].E_cb = nr_get_E(G, impp.n_segments, impp.Qm, ulsch->pusch_pdu.nrOfLayers, r); + reset_meas(&segment_parameters->ts_interleave); + reset_meas(&segment_parameters->ts_rate_match); + reset_meas(&segment_parameters->ts_ldpc_encode); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RATE_MATCHING_LDPC, VCD_FUNCTION_IN); - start_meas(&ue->phy_cpu_stats.cpu_time_stats[ULSCH_RATE_MATCHING_STATS]); - if (nr_rate_matching_ldpc(ulsch->pusch_pdu.tbslbrm, - impp.BG, - impp.Zc, - harq_process->d[r], - harq_process->e + r_offset, - impp.n_segments, - impp.F, - impp.Kr - impp.F - 2 * impp.Zc, - impp.rv, - impp.perCB[r].E_cb) - == -1) - return -1; + } // TB_parameters->C + } // pusch_id - stop_meas(&ue->phy_cpu_stats.cpu_time_stats[ULSCH_RATE_MATCHING_STATS]); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RATE_MATCHING_LDPC, VCD_FUNCTION_OUT); + ///////////////////////// | LDCP coding | //////////////////////////////////// -#ifdef DEBUG_ULSCH_CODING - for (int i = 0; i < 16; i++) - printf("output ratematching e[%d]= %d r_offset %u\n", i, harq_process->e[i + r_offset], r_offset); -#endif + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_IN); -///////////////////////// e---->| Rate matching bit interleaving |---->f ///////////////////////// - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INTERLEAVING_LDPC, VCD_FUNCTION_IN); - start_meas_nr_ue_phy(ue, ULSCH_INTERLEAVING_STATS); - nr_interleaving_ldpc(impp.perCB[r].E_cb, impp.Qm, harq_process->e + r_offset, harq_process->f + r_offset); - stop_meas_nr_ue_phy(ue, ULSCH_INTERLEAVING_STATS); - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INTERLEAVING_LDPC, VCD_FUNCTION_OUT); -#ifdef DEBUG_ULSCH_CODING - for (int i = 0; i < 16; i++) - printf("output interleaving f[%d]= %d r_offset %u\n", i, harq_process->f[i+r_offset], r_offset); - if (r == impp.n_segments - 1) - write_output("enc_output.m","enc", harq_process->f, G, 1, 4); -#endif - r_offset += impp.perCB[r].E_cb; + ue->nrLDPC_coding_interface.nrLDPC_coding_encoder(&slot_parameters); + + for (uint8_t pusch_id = 0; pusch_id < nb_ulsch; pusch_id++) { + nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[pusch_id]; + for (int r = 0; r < TB_parameters->C; r++) { + nrLDPC_segment_encoding_parameters_t *segment_parameters = &TB_parameters->segments[r]; + merge_meas(&ue->phy_cpu_stats.cpu_time_stats[ULSCH_INTERLEAVING_STATS], &segment_parameters->ts_interleave); + merge_meas(&ue->phy_cpu_stats.cpu_time_stats[ULSCH_RATE_MATCHING_STATS], &segment_parameters->ts_rate_match); + merge_meas(&ue->phy_cpu_stats.cpu_time_stats[ULSCH_LDPC_ENCODING_STATS], &segment_parameters->ts_ldpc_encode); } } - /////////////////////////////////////////////////////////////////////////////////////////////// + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_OUT); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_UE_ULSCH_ENCODING, VCD_FUNCTION_OUT); stop_meas_nr_ue_phy(ue, ULSCH_ENCODING_STATS); - return(0); + return 0; } diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index bef7724e5d..646ac2dd94 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -462,65 +462,49 @@ static void map_symbols(const nr_phy_pxsch_params_t p, } void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, - const unsigned char harq_pid, const uint32_t frame, const uint8_t slot, - const int gNB_id, nr_phy_data_tx_t *phy_data, c16_t **txdataF) { - LOG_D(PHY,"nr_ue_ulsch_procedures hard_id %d %d.%d\n",harq_pid,frame,slot); - int l_prime[2]; - uint8_t nb_dmrs_re_per_rb; + int harq_pid = phy_data->ulsch.pusch_pdu.pusch_data.harq_process_id; - NR_DL_FRAME_PARMS *frame_parms = &UE->frame_parms; + if (UE->ul_harq_processes[harq_pid].ULstatus != ACTIVE) + return; - int N_PRB_oh = 0; // higher layer (RRC) parameter xOverhead in PUSCH-ServingCellConfig - uint16_t number_dmrs_symbols = 0; + start_meas_nr_ue_phy(UE, PUSCH_PROC_STATS); + + uint8_t ULSCH_ids[1]; + unsigned int G[1]; + uint8_t pusch_id = 0; + ULSCH_ids[pusch_id] = 0; + LOG_D(PHY, "nr_ue_ulsch_procedures_slot hard_id %d %d.%d prepare for coding\n", harq_pid, frame, slot); NR_UE_ULSCH_t *ulsch_ue = &phy_data->ulsch; NR_UL_UE_HARQ_t *harq_process_ul_ue = &UE->ul_harq_processes[harq_pid]; const nfapi_nr_ue_pusch_pdu_t *pusch_pdu = &ulsch_ue->pusch_pdu; - uint32_t tb_size = pusch_pdu->pusch_data.tb_size; - AssertFatal(pusch_pdu->pusch_uci.harq_ack_bit_length == 0 && - pusch_pdu->pusch_uci.csi_part1_bit_length == 0 && - pusch_pdu->pusch_uci.csi_part2_bit_length == 0, - "UCI on PUSCH not supported at PHY\n"); + uint16_t number_dmrs_symbols = 0; - int start_symbol = pusch_pdu->start_symbol_index; - uint16_t ul_dmrs_symb_pos = pusch_pdu->ul_dmrs_symb_pos; + uint16_t nb_rb = pusch_pdu->rb_size; uint8_t number_of_symbols = pusch_pdu->nr_of_symbols; - uint8_t dmrs_type = pusch_pdu->dmrs_config_type; - uint16_t start_rb = pusch_pdu->rb_start; - uint16_t nb_rb = pusch_pdu->rb_size; - uint8_t Nl = pusch_pdu->nrOfLayers; - uint8_t mod_order = pusch_pdu->qam_mod_order; - uint16_t rnti = pusch_pdu->rnti; - uint8_t cdm_grps_no_data = pusch_pdu->num_dmrs_cdm_grps_no_data; - uint16_t start_sc = frame_parms->first_carrier_offset + (start_rb+pusch_pdu->bwp_start)*NR_NB_SC_PER_RB; - - if (start_sc >= frame_parms->ofdm_symbol_size) - start_sc -= frame_parms->ofdm_symbol_size; - - ulsch_ue->Nid_cell = frame_parms->Nid_cell; + uint8_t dmrs_type = pusch_pdu->dmrs_config_type; + uint8_t cdm_grps_no_data = pusch_pdu->num_dmrs_cdm_grps_no_data; + uint8_t nb_dmrs_re_per_rb = ((dmrs_type == pusch_dmrs_type1) ? 6 : 4) * cdm_grps_no_data; + int start_symbol = pusch_pdu->start_symbol_index; + uint16_t ul_dmrs_symb_pos = pusch_pdu->ul_dmrs_symb_pos; + uint8_t mod_order = pusch_pdu->qam_mod_order; + uint8_t Nl = pusch_pdu->nrOfLayers; + uint32_t tb_size = pusch_pdu->pusch_data.tb_size; + uint16_t rnti = pusch_pdu->rnti; for (int i = start_symbol; i < start_symbol + number_of_symbols; i++) { - if((ul_dmrs_symb_pos >> i) & 0x01) + if ((ul_dmrs_symb_pos >> i) & 0x01) number_dmrs_symbols += 1; } - nb_dmrs_re_per_rb = ((dmrs_type == pusch_dmrs_type1) ? 6:4)*cdm_grps_no_data; - - LOG_D(PHY,"ulsch TX %x : start_rb %d nb_rb %d mod_order %d Nl %d Tpmi %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_re_per_rb %d\n", - rnti,start_rb,nb_rb,mod_order,Nl,pusch_pdu->Tpmi,pusch_pdu->bwp_start,start_sc,start_symbol,number_of_symbols,cdm_grps_no_data,number_dmrs_symbols,nb_dmrs_re_per_rb); - // TbD num_of_mod_symbols is set but never used - const uint32_t N_RE_prime = NR_NB_SC_PER_RB * number_of_symbols - nb_dmrs_re_per_rb * number_dmrs_symbols - N_PRB_oh; - harq_process_ul_ue->num_of_mod_symbols = N_RE_prime*nb_rb; - - /////////////////////////PTRS parameters' initialization///////////////////////// - /////////// + ///////////////////////PTRS parameters' initialization/////////////////// unsigned int K_ptrs = 0, k_RE_ref = 0; uint32_t unav_res = 0; @@ -531,32 +515,14 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, ulsch_ue->ptrs_symbols = 0; - set_ptrs_symb_idx(&ulsch_ue->ptrs_symbols, - number_of_symbols, - start_symbol, - L_ptrs, - ul_dmrs_symb_pos); + set_ptrs_symb_idx(&ulsch_ue->ptrs_symbols, number_of_symbols, start_symbol, L_ptrs, ul_dmrs_symb_pos); int n_ptrs = (nb_rb + K_ptrs - 1) / K_ptrs; - int ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ulsch_ue->ptrs_symbols, - start_symbol, - number_of_symbols); + int ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ulsch_ue->ptrs_symbols, start_symbol, number_of_symbols); unav_res = n_ptrs * ptrsSymbPerSlot; } - /////////// - //////////////////////////////////////////////////////////////////// + G[pusch_id] = nr_get_G(nb_rb, number_of_symbols, nb_dmrs_re_per_rb, number_dmrs_symbols, unav_res, mod_order, Nl); - - /////////////////////////ULSCH coding///////////////////////// - /////////// - - unsigned int G = nr_get_G(nb_rb, - number_of_symbols, - nb_dmrs_re_per_rb, - number_dmrs_symbols, - unav_res, - mod_order, - Nl); ws_trace_t tmp = {.nr = true, .direction = DIRECTION_UPLINK, .pdu_buffer = harq_process_ul_ue->payload_AB, @@ -571,19 +537,59 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, .oob_event_value = 0}; trace_pdu(&tmp); - if (nr_ulsch_encoding(UE, ulsch_ue, frame_parms, harq_pid, tb_size, G) == -1) { + /////////////////////////ULSCH coding///////////////////////// + + if (nr_ulsch_encoding(UE, &phy_data->ulsch, frame, slot, G, 1, ULSCH_ids) == -1) { NR_UL_UE_HARQ_t *harq_process_ulsch = &UE->ul_harq_processes[harq_pid]; harq_process_ulsch->ULstatus = SCH_IDLE; + stop_meas_nr_ue_phy(UE, PUSCH_PROC_STATS); return; } - /////////// - //////////////////////////////////////////////////////////////////// + LOG_D(PHY, "nr_ue_ulsch_procedures_slot hard_id %d %d.%d\n", harq_pid, frame, slot); + + int l_prime[2]; + + NR_DL_FRAME_PARMS *frame_parms = &UE->frame_parms; + + int N_PRB_oh = 0; // higher layer (RRC) parameter xOverhead in PUSCH-ServingCellConfig + + AssertFatal(pusch_pdu->pusch_uci.harq_ack_bit_length == 0 && pusch_pdu->pusch_uci.csi_part1_bit_length == 0 + && pusch_pdu->pusch_uci.csi_part2_bit_length == 0, + "UCI on PUSCH not supported at PHY\n"); + + uint16_t start_rb = pusch_pdu->rb_start; + uint16_t start_sc = frame_parms->first_carrier_offset + (start_rb + pusch_pdu->bwp_start) * NR_NB_SC_PER_RB; + + if (start_sc >= frame_parms->ofdm_symbol_size) + start_sc -= frame_parms->ofdm_symbol_size; + + ulsch_ue->Nid_cell = frame_parms->Nid_cell; + + LOG_D(PHY, + "ulsch TX %x : start_rb %d nb_rb %d mod_order %d Nl %d Tpmi %d bwp_start %d start_sc %d start_symbol %d num_symbols %d " + "cdmgrpsnodata %d " + "num_dmrs %d dmrs_re_per_rb %d\n", + rnti, + start_rb, + nb_rb, + mod_order, + Nl, + pusch_pdu->Tpmi, + pusch_pdu->bwp_start, + start_sc, + start_symbol, + number_of_symbols, + cdm_grps_no_data, + number_dmrs_symbols, + nb_dmrs_re_per_rb); + // TbD num_of_mod_symbols is set but never used + const uint32_t N_RE_prime = NR_NB_SC_PER_RB * number_of_symbols - nb_dmrs_re_per_rb * number_dmrs_symbols - N_PRB_oh; + harq_process_ul_ue->num_of_mod_symbols = N_RE_prime * nb_rb; /////////////////////////ULSCH scrambling///////////////////////// - /////////// - uint32_t available_bits = G; + uint32_t available_bits = G[pusch_id]; // +1 because size can be not modulo 4 uint32_t scrambled_output[available_bits / (8 * sizeof(uint32_t)) + 1]; memset(scrambled_output, 0, sizeof(scrambled_output)); @@ -595,13 +601,9 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, false, scrambled_output); - ///////////// - ////////////////////////////////////////////////////////////////////////// - /////////////////////////ULSCH modulation///////////////////////// - /////////// - int max_num_re = Nl*number_of_symbols*nb_rb*NR_NB_SC_PER_RB; + int max_num_re = Nl * number_of_symbols * nb_rb * NR_NB_SC_PER_RB; c16_t d_mod[max_num_re] __attribute__((aligned(16))); nr_modulation(scrambled_output, // assume one codeword for the moment @@ -609,23 +611,14 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, mod_order, (int16_t *)d_mod); - - /////////// - //////////////////////////////////////////////////////////////////////// - /////////////////////////ULSCH layer mapping///////////////////////// - /////////// + const int sz = available_bits / mod_order / Nl; c16_t ulsch_mod[Nl][sz]; nr_ue_layer_mapping(d_mod, Nl, sz, ulsch_mod); - /////////// - //////////////////////////////////////////////////////////////////////// - - //////////////////////// ULSCH transform precoding //////////////////////// - /////////// l_prime[0] = 0; // single symbol ap 0 @@ -636,10 +629,9 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, memset(ulsch_mod_tp, 0, sizeof(ulsch_mod_tp)); if (pusch_pdu->transform_precoding == transformPrecoder_enabled) { - - uint32_t nb_re_pusch=nb_rb * NR_NB_SC_PER_RB; + uint32_t nb_re_pusch = nb_rb * NR_NB_SC_PER_RB; uint32_t y_offset = 0; - uint16_t num_dmrs_res_per_symbol = nb_rb*(NR_NB_SC_PER_RB/2); + uint16_t num_dmrs_res_per_symbol = nb_rb * (NR_NB_SC_PER_RB / 2); // Calculate index to dmrs seq array based on number of DMRS Subcarriers on this symbol int index = get_index_for_dmrs_lowpapr_seq(num_dmrs_res_per_symbol); @@ -647,14 +639,16 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, v = pusch_pdu->dfts_ofdm.low_papr_sequence_number; dmrs_seq = dmrs_lowpaprtype1_ul_ref_sig[u][v][index]; - AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n"); + AssertFatal(index >= 0, + "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs " + "cannot be multiple " + "of any other primenumber other than 2,3,5\n"); AssertFatal(dmrs_seq != NULL, "DMRS low PAPR seq not found, check if DMRS sequences are generated"); - LOG_D(PHY,"Transform Precoding params. u: %d, v: %d, index for dmrsseq: %d\n", u, v, index); + LOG_D(PHY, "Transform Precoding params. u: %d, v: %d, index for dmrsseq: %d\n", u, v, index); for (int l = start_symbol; l < start_symbol + number_of_symbols; l++) { - - if((ul_dmrs_symb_pos >> l) & 0x01) + if ((ul_dmrs_symb_pos >> l) & 0x01) /* In the symbol with DMRS no data would be transmitted CDM groups is 2*/ continue; @@ -662,43 +656,35 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, y_offset = y_offset + nb_re_pusch; - LOG_D(PHY,"Transform precoding being done on data- symbol: %d, nb_re_pusch: %d, y_offset: %d\n", l, nb_re_pusch, y_offset); + LOG_D(PHY, "Transform precoding being done on data- symbol: %d, nb_re_pusch: %d, y_offset: %d\n", l, nb_re_pusch, y_offset); #ifdef DEBUG_PUSCH_MAPPING - printf("NR_ULSCH_UE: y_offset %u\t nb_re_pusch %u \t Symbol %d \t nb_rb %d \n", - y_offset, nb_re_pusch, l, nb_rb); + printf("NR_ULSCH_UE: y_offset %u\t nb_re_pusch %u \t Symbol %d \t nb_rb %d \n", y_offset, nb_re_pusch, l, nb_rb); #endif } #ifdef DEBUG_DFT_IDFT - int32_t debug_symbols[MAX_NUM_NR_RE] __attribute__ ((aligned(16))); + int32_t debug_symbols[MAX_NUM_NR_RE] __attribute__((aligned(16))); int offset = 0; - printf("NR_ULSCH_UE: available_bits: %u, mod_order: %d", available_bits,mod_order); + printf("NR_ULSCH_UE: available_bits: %u, mod_order: %d", available_bits, mod_order); - for (int ll = 0; ll < (available_bits/mod_order); ll++) { + for (int ll = 0; ll < (available_bits / mod_order); ll++) { debug_symbols[ll] = ulsch_ue->ulsch_mod_tp[ll]; } - - printf("NR_ULSCH_UE: numSym: %d, num_dmrs_sym: %d", number_of_symbols,number_dmrs_symbols); - for (int ll = 0; ll < (number_of_symbols-number_dmrs_symbols); ll++) { + + printf("NR_ULSCH_UE: numSym: %d, num_dmrs_sym: %d", number_of_symbols, number_dmrs_symbols); + for (int ll = 0; ll < (number_of_symbols - number_dmrs_symbols); ll++) { nr_idft(&debug_symbols[offset], nb_re_pusch); offset = offset + nb_re_pusch; } LOG_M("preDFT_all_symbols.m", "UE_preDFT", ulsch_mod[0], number_of_symbols * nb_re_pusch, 1, 1); LOG_M("postDFT_all_symbols.m", "UE_postDFT", ulsch_mod_tp, number_of_symbols * nb_re_pusch, 1, 1); - LOG_M("DEBUG_IDFT_SYMBOLS.m","UE_Debug_IDFT", debug_symbols,number_of_symbols*nb_re_pusch,1,1); - LOG_M("UE_DMRS_SEQ.m","UE_DMRS_SEQ", dmrs_seq,nb_re_pusch,1,1); + LOG_M("DEBUG_IDFT_SYMBOLS.m", "UE_Debug_IDFT", debug_symbols, number_of_symbols * nb_re_pusch, 1, 1); + LOG_M("UE_DMRS_SEQ.m", "UE_DMRS_SEQ", dmrs_seq, nb_re_pusch, 1, 1); #endif - } - - /////////// - //////////////////////////////////////////////////////////////////////// - - /////////////////////////ULSCH RE mapping///////////////////////// - /////////// const int slot_sz = frame_parms->ofdm_symbol_size * frame_parms->symbols_per_slot; c16_t tx_precoding[Nl][slot_sz]; @@ -748,12 +734,13 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, } // for (nl=0; nl < Nl; nl++) /////////////////////////ULSCH precoding///////////////////////// - /////////// + /// Layer Precoding and Antenna port mapping // ulsch_mod 0-3 are mapped on antenna ports // The precoding info is supported by nfapi such as num_prgs, prg_size, prgs_list and pm_idx // The same precoding matrix is applied on prg_size RBs, Thus // pmi = prgs_list[rbidx/prg_size].pm_idx, rbidx =0,...,rbSize-1 + // The Precoding matrix: for (int ap = 0; ap < frame_parms->nb_antennas_tx; ap++) { for (int l = start_symbol; l < start_symbol + number_of_symbols; l++) { @@ -834,8 +821,9 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, NR_UL_UE_HARQ_t *harq_process_ulsch = NULL; harq_process_ulsch = &UE->ul_harq_processes[harq_pid]; harq_process_ulsch->ULstatus = SCH_IDLE; - /////////// - //////////////////////////////////////////////////////////////////////// + + stop_meas_nr_ue_phy(UE, PUSCH_PROC_STATS); + } uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE, diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index 774309831c..8cef0b6f4c 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -89,6 +89,7 @@ #include "impl_defs_nr.h" #include "time_meas.h" #include "PHY/CODING/coding_defs.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" #include "PHY/TOOLS/tools_defs.h" #include "common/platform_types.h" #include "NR_UE_TRANSPORT/nr_transport_ue.h" @@ -481,9 +482,10 @@ typedef struct PHY_VARS_NR_UE_s { /// N0 (used for abstraction) double N0; + /// NR LDPC coding related + nrLDPC_coding_interface_t nrLDPC_coding_interface; uint8_t max_ldpc_iterations; - int ldpc_offload_enable; /// SRS variables nr_srs_info_t *nr_srs_info; diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 664a293a96..a9552b1677 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -271,7 +271,6 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n { const int slot_tx = proc->nr_slot_tx; const int frame_tx = proc->frame_tx; - const int gNB_id = proc->gNB_id; AssertFatal(ue->CC_id == 0, "Transmission on secondary CCs is not supported yet\n"); @@ -288,12 +287,7 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n start_meas_nr_ue_phy(ue, PHY_PROC_TX); - const int harq_pid = phy_data->ulsch.pusch_pdu.pusch_data.harq_process_id; - if (ue->ul_harq_processes[harq_pid].ULstatus == ACTIVE) { - start_meas_nr_ue_phy(ue, PUSCH_PROC_STATS); - nr_ue_ulsch_procedures(ue, harq_pid, frame_tx, slot_tx, gNB_id, phy_data, (c16_t **)&txdataF); - stop_meas_nr_ue_phy(ue, PUSCH_PROC_STATS); - } + nr_ue_ulsch_procedures(ue, frame_tx, slot_tx, phy_data, (c16_t **)&txdataF); ue_srs_procedures_nr(ue, proc, (c16_t **)&txdataF); @@ -685,23 +679,22 @@ static uint32_t compute_csi_rm_unav_res(fapi_nr_dl_config_dlsch_pdu_rel15_t *dls return unav_res; } +/*! \brief Process the whole DLSCH slot + */ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, NR_UE_DLSCH_t dlsch[2], - int16_t *llr[2], - int G) -{ + int16_t *llr[2]) { if (dlsch[0].active == false) { LOG_E(PHY, "DLSCH should be active when calling this function\n"); return true; } - int gNB_id = proc->gNB_id; bool dec = false; int harq_pid = dlsch[0].dlsch_config.harq_process_nbr; int frame_rx = proc->frame_rx; int nr_slot_rx = proc->nr_slot_rx; - uint32_t ret = UINT32_MAX, ret1 = UINT32_MAX; + uint32_t ret = UINT32_MAX; NR_DL_UE_HARQ_t *dl_harq0 = &ue->dl_harq_processes[0][harq_pid]; NR_DL_UE_HARQ_t *dl_harq1 = &ue->dl_harq_processes[1][harq_pid]; uint16_t dmrs_len = get_num_dmrs(dlsch[0].dlsch_config.dlDmrsSymbPos); @@ -711,19 +704,21 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, uint8_t is_cw0_active = dl_harq0->status; uint8_t is_cw1_active = dl_harq1->status; + int nb_dlsch = 0; + nb_dlsch += (is_cw0_active == ACTIVE) ? 1 : 0; + nb_dlsch += (is_cw1_active == ACTIVE) ? 1 : 0; uint16_t nb_symb_sch = dlsch[0].dlsch_config.number_symbols; uint8_t dmrs_type = dlsch[0].dlsch_config.dmrsConfigType; uint8_t nb_re_dmrs; - if (dmrs_type==NFAPI_NR_DMRS_TYPE1) { - nb_re_dmrs = 6*dlsch[0].dlsch_config.n_dmrs_cdm_groups; - } - else { - nb_re_dmrs = 4*dlsch[0].dlsch_config.n_dmrs_cdm_groups; + if (dmrs_type == NFAPI_NR_DMRS_TYPE1) { + nb_re_dmrs = 6 * dlsch[0].dlsch_config.n_dmrs_cdm_groups; + } else { + nb_re_dmrs = 4 * dlsch[0].dlsch_config.n_dmrs_cdm_groups; } - LOG_D(PHY,"AbsSubframe %d.%d Start LDPC Decoder for CW0 [harq_pid %d] ? %d \n", frame_rx%1024, nr_slot_rx, harq_pid, is_cw0_active); - LOG_D(PHY,"AbsSubframe %d.%d Start LDPC Decoder for CW1 [harq_pid %d] ? %d \n", frame_rx%1024, nr_slot_rx, harq_pid, is_cw1_active); + LOG_D(PHY, "AbsSubframe %d.%d Start LDPC Decoder for CW0 [harq_pid %d] ? %d \n", frame_rx % 1024, nr_slot_rx, harq_pid, is_cw0_active); + LOG_D(PHY, "AbsSubframe %d.%d Start LDPC Decoder for CW1 [harq_pid %d] ? %d \n", frame_rx % 1024, nr_slot_rx, harq_pid, is_cw1_active); // exit dlsch procedures as there are no active dlsch if (is_cw0_active != ACTIVE && is_cw1_active != ACTIVE) { @@ -734,44 +729,43 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, return false; } - start_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS); - nr_dlsch_unscrambling(llr[0], G, 0, dlsch[0].dlsch_config.dlDataScramblingId, dlsch[0].rnti); - stop_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS); + int G[2]; + uint8_t DLSCH_ids[nb_dlsch]; + int pdsch_id = 0; + uint8_t *p_b[2] = {NULL}; + for (uint8_t DLSCH_id = 0; DLSCH_id < 2; DLSCH_id++) { + NR_DL_UE_HARQ_t *dl_harq = &ue->dl_harq_processes[DLSCH_id][harq_pid]; + if (dl_harq->status != ACTIVE) continue; + + DLSCH_ids[pdsch_id++] = DLSCH_id; + fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[DLSCH_id].dlsch_config; + uint32_t unav_res = 0; + if (dlsch_config->pduBitmap & 0x1) { + uint16_t ptrsSymbPos = 0; + set_ptrs_symb_idx(&ptrsSymbPos, dlsch_config->number_symbols, dlsch_config->start_symbol, 1 << dlsch_config->PTRSTimeDensity, + dlsch_config->dlDmrsSymbPos); + int n_ptrs = (dlsch_config->number_rbs + dlsch_config->PTRSFreqDensity - 1) / dlsch_config->PTRSFreqDensity; + int ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ptrsSymbPos, dlsch_config->start_symbol, dlsch_config->number_symbols); + unav_res = n_ptrs * ptrsSymbPerSlot; + } + unav_res += compute_csi_rm_unav_res(dlsch_config); + G[DLSCH_id] = nr_get_G(dlsch_config->number_rbs, nb_symb_sch, nb_re_dmrs, dmrs_len, unav_res, dlsch_config->qamModOrder, dlsch[DLSCH_id].Nl); + + start_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS); + nr_dlsch_unscrambling(llr[DLSCH_id], G[DLSCH_id], 0, dlsch[DLSCH_id].dlsch_config.dlDataScramblingId, dlsch[DLSCH_id].rnti); + stop_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS); + + p_b[DLSCH_id] = dl_harq->b; + } start_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS); - // create memory to store decoder output - int a_segments = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER*NR_MAX_NB_LAYERS; //number of segments to be allocated - int num_rb = dlsch[0].dlsch_config.number_rbs; - if (num_rb != 273) { - a_segments = a_segments*num_rb; - a_segments = (a_segments/273)+1; - } - uint32_t dlsch_bytes = a_segments*1056; // allocated bytes per segment - __attribute__ ((aligned(32))) uint8_t p_b[dlsch_bytes]; + ret = nr_dlsch_decoding(ue, proc, dlsch, llr, p_b, G, nb_dlsch, DLSCH_ids); + stop_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS); - ret = nr_dlsch_decoding(ue, - proc, - gNB_id, - llr[0], - &ue->frame_parms, - &dlsch[0], - dl_harq0, - frame_rx, - nb_symb_sch, - nr_slot_rx, - harq_pid, - dlsch_bytes, - p_b, - G); - - LOG_T(PHY,"dlsch decoding, ret = %d\n", ret); - - - if(retmax_ldpc_iterations+1) - dec = true; + if (ret < ue->max_ldpc_iterations + 1) dec = true; int ind_type = -1; - switch(dlsch[0].rnti_type) { + switch (dlsch[0].rnti_type) { case TYPE_RA_RNTI_: ind_type = FAPI_NR_RX_PDU_TYPE_RAR; break; @@ -790,75 +784,21 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, } nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL); - nr_fill_rx_indication(&rx_ind, ind_type, ue, &dlsch[0], NULL, number_pdus, proc, NULL, p_b); + nr_fill_rx_indication(&rx_ind, ind_type, ue, &dlsch[0], NULL, number_pdus, proc, NULL, p_b[0]); LOG_D(PHY, "DL PDU length in bits: %d, in bytes: %d \n", dlsch[0].dlsch_config.TBS, dlsch[0].dlsch_config.TBS / 8); - - stop_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS); if (cpumeas(CPUMEAS_GETSTATE)) { LOG_D(PHY, - " --> Unscrambling for CW0 %5.3f\n", + " --> Unscrambling %5.3f\n", ue->phy_cpu_stats.cpu_time_stats[DLSCH_UNSCRAMBLING_STATS].p_time / (cpuf * 1000.0)); LOG_D(PHY, - "AbsSubframe %d.%d --> LDPC Decoding for CW0 %5.3f\n", + "AbsSubframe %d.%d --> LDPC Decoding %5.3f\n", frame_rx % 1024, nr_slot_rx, ue->phy_cpu_stats.cpu_time_stats[DLSCH_DECODING_STATS].p_time / (cpuf * 1000.0)); } - if(is_cw1_active) { - // start ldpc decode for CW 1 - fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[1].dlsch_config; - uint32_t unav_res = 0; - if(dlsch_config->pduBitmap & 0x1) { - uint16_t ptrsSymbPos = 0; - set_ptrs_symb_idx(&ptrsSymbPos, - dlsch_config->number_symbols, - dlsch_config->start_symbol, - 1 << dlsch_config->PTRSTimeDensity, - dlsch_config->dlDmrsSymbPos); - int n_ptrs = (dlsch_config->number_rbs + dlsch_config->PTRSFreqDensity - 1) / dlsch_config->PTRSFreqDensity; - int ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ptrsSymbPos, dlsch_config->start_symbol, dlsch_config->number_symbols); - unav_res = n_ptrs * ptrsSymbPerSlot; - } - start_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS); - unav_res += compute_csi_rm_unav_res(dlsch_config); - G = nr_get_G(dlsch_config->number_rbs, nb_symb_sch, nb_re_dmrs, dmrs_len, unav_res, dlsch_config->qamModOrder, dlsch[1].Nl); - nr_dlsch_unscrambling(llr[1], G, 0, dlsch[1].dlsch_config.dlDataScramblingId, dlsch[1].rnti); - stop_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS); - - start_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS); - ret1 = nr_dlsch_decoding(ue, - proc, - gNB_id, - llr[1], - &ue->frame_parms, - &dlsch[1], - dl_harq1, - frame_rx, - nb_symb_sch, - nr_slot_rx, - harq_pid, - dlsch_bytes, - p_b, - G); - LOG_T(PHY,"CW dlsch decoding, ret1 = %d\n", ret1); - - stop_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS); - if (cpumeas(CPUMEAS_GETSTATE)) { - LOG_D(PHY, - " --> Unscrambling for CW1 %5.3f\n", - ue->phy_cpu_stats.cpu_time_stats[DLSCH_UNSCRAMBLING_STATS].p_time / (cpuf * 1000.0)); - LOG_D(PHY, - "AbsSubframe %d.%d --> ldpc Decoding for CW1 %5.3f\n", - frame_rx % 1024, - nr_slot_rx, - ue->phy_cpu_stats.cpu_time_stats[DLSCH_DECODING_STATS].p_time / (cpuf * 1000.0)); - } - LOG_D(PHY, "harq_pid: %d, TBS expected dlsch1: %d \n", harq_pid, dlsch[1].dlsch_config.TBS); - } - - // send to mac + // send to mac if (ue->if_inst && ue->if_inst->dl_indication) { ue->if_inst->dl_indication(&dl_indication); } @@ -869,8 +809,18 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot]); } - if (ue->phy_sim_dlsch_b) - memcpy(ue->phy_sim_dlsch_b, p_b, dlsch_bytes); + int a_segments = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * NR_MAX_NB_LAYERS; // number of segments to be allocated + int num_rb = dlsch[0].dlsch_config.number_rbs; + if (num_rb != 273) { + a_segments = a_segments * num_rb; + a_segments = (a_segments / 273) + 1; + } + uint32_t dlsch_bytes = a_segments * 1056; // allocated bytes per segment + + if (ue->phy_sim_dlsch_b && is_cw0_active == ACTIVE) + memcpy(ue->phy_sim_dlsch_b, p_b[0], dlsch_bytes); + else if (ue->phy_sim_dlsch_b && is_cw1_active == ACTIVE) + memcpy(ue->phy_sim_dlsch_b, p_b[1], dlsch_bytes); return dec; } @@ -1144,8 +1094,9 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_ start_meas_nr_ue_phy(ue, DLSCH_PROCEDURES_STATS); - if (ret_pdsch >= 0) - nr_ue_dlsch_procedures(ue, proc, dlsch, llr, G); + if (ret_pdsch >= 0) { + nr_ue_dlsch_procedures(ue, proc, dlsch, llr); + } else { LOG_E(NR_PHY, "Demodulation impossible, internal error\n"); int ack_nack_slot = (proc->nr_slot_rx + dlsch_config->k1_feedback) % ue->frame_parms.slots_per_frame; From 7f1d3c6644f55b081e516e1e1471c4f2b8e37c51 Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Wed, 9 Oct 2024 14:19:35 +0200 Subject: [PATCH 40/83] feat(nrLDPC_coding_interface): Use reworked interface in PHY simulators --- openair1/SIMULATION/NR_PHY/dlschsim.c | 31 ++++++++++------- openair1/SIMULATION/NR_PHY/dlsim.c | 15 +++----- openair1/SIMULATION/NR_PHY/ulschsim.c | 50 +++++++-------------------- openair1/SIMULATION/NR_PHY/ulsim.c | 18 ++++------ 4 files changed, 41 insertions(+), 73 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index da02d13be1..cac4c6604a 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -35,6 +35,7 @@ #include "PHY/defs_nr_common.h" #include "PHY/defs_nr_UE.h" #include "PHY/types.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" #include "PHY/INIT/nr_phy_init.h" #include "PHY/MODULATION/modulation_eNB.h" #include "PHY/MODULATION/modulation_UE.h" @@ -380,7 +381,7 @@ int main(int argc, char **argv) RC.gNB[0] = calloc(1, sizeof(PHY_VARS_gNB)); gNB = RC.gNB[0]; initNamedTpool(gNBthreads, &gNB->threadPool, true, "gNB-tpool"); - initFloatingCoresTpool(dlsch_threads, &nrUE_params.Tpool, false, "UE-tpool"); + initFloatingCoresTpool(dlsch_threads, &nrUE_params.Tpool, false, "UE-tpool"); //gNB_config = &gNB->gNB_config; frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH) frame_parms->nb_antennas_tx = n_tx; @@ -430,6 +431,8 @@ int main(int argc, char **argv) //nr_init_frame_parms_ue(&UE->frame_parms); //init_nr_ue_transport(UE, 0); + UE->nrLDPC_coding_interface = gNB->nrLDPC_coding_interface; + NR_UE_DLSCH_t dlsch_ue[NR_MAX_NB_LAYERS > 4? 2:1] = {0}; int num_codeword = NR_MAX_NB_LAYERS > 4? 2:1; nr_ue_dlsch_init(dlsch_ue, num_codeword, 5); @@ -513,7 +516,8 @@ int main(int argc, char **argv) unsigned char output[rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS] __attribute__((aligned(32))); bzero(output,rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS); if (input_fd == NULL) { - nr_dlsch_encoding(gNB, frame, slot, &dlsch->harq_process, frame_parms,output,NULL,NULL,NULL,NULL,NULL,NULL,NULL); + msgDataTx.num_pdsch_slot = 1; + nr_dlsch_encoding(gNB, &msgDataTx, frame, slot, frame_parms, output, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } for (SNR = snr0; SNR < snr1; SNR += snr_step) { @@ -569,20 +573,18 @@ int main(int argc, char **argv) } uint32_t dlsch_bytes = a_segments*1056; // allocated bytes per segment __attribute__ ((aligned(32))) uint8_t b[dlsch_bytes]; + uint8_t DLSCH_ids[1] = {0}; + short *p_channel_output_fixed = channel_output_fixed; + uint8_t *p_b = b; + int available_bits_array[1] = { available_bits }; ret = nr_dlsch_decoding(UE, &proc, - 0, - channel_output_fixed, - &UE->frame_parms, dlsch0_ue, - harq_process, - frame, - nb_symb_sch, - slot, - harq_pid, - dlsch_bytes, - b, - available_bits); + &p_channel_output_fixed, + &p_b, + available_bits_array, + 1, + DLSCH_ids); vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DECODING0, VCD_FUNCTION_OUT); @@ -661,7 +663,10 @@ int main(int argc, char **argv) free(gNB->gNB_config.tdd_table.max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list); free(gNB->gNB_config.tdd_table.max_tdd_periodicity_list); + free_nrLDPC_coding_interface(&gNB->nrLDPC_coding_interface); + abortTpool(&gNB->threadPool); + phy_free_nr_gNB(gNB); free(RC.gNB[0]); free(RC.gNB); diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index c445bfb6a0..99ab0c82b1 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -47,7 +47,7 @@ #include "NR_ServingCellConfig.h" #include "NR_SetupRelease.h" #include "NR_UE_PHY_INTERFACE/NR_IF_Module.h" -#include "PHY/CODING/nrLDPC_extern.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" #include "PHY/INIT/nr_phy_init.h" #include "PHY/MODULATION/modulation_common.h" #include "PHY/NR_REFSIG/ptrs_nr.h" @@ -297,7 +297,6 @@ int main(int argc, char **argv) uint8_t n_tx=1,n_rx=1; uint8_t round; uint8_t num_rounds = 4; - int ldpc_offload_flag = 0; char gNBthreads[128]="n"; channel_desc_t *gNB2UE; @@ -360,7 +359,7 @@ int main(int argc, char **argv) FILE *scg_fd=NULL; - while ((c = getopt(argc, argv, "--:O:f:hA:p:f:g:i:n:s:S:t:v:x:y:z:o:M:N:F:GR:d:PI:L:a:b:e:m:w:T:U:q:X:Y:Z:c")) != -1) { + while ((c = getopt(argc, argv, "--:O:f:hA:p:f:g:i:n:s:S:t:v:x:y:z:o:M:N:F:GR:d:PI:L:a:b:e:m:w:T:U:q:X:Y:Z:")) != -1) { /* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */ /* with this opstring getopt returns 1 for non-option arguments, refer to 'man 3 getopt' */ @@ -412,10 +411,6 @@ int main(int argc, char **argv) n_trials = atoi(optarg); break; - case 'c': - ldpc_offload_flag = 1; - break; - case 's': snr0 = atof(optarg); printf("Setting SNR0 to %f\n",snr0); @@ -580,7 +575,6 @@ int main(int argc, char **argv) //printf("-j Relative strength of second intefering gNB (in dB) - cell_id mod 3 = 2\n"); printf("-R N_RB_DL\n"); printf("-O oversampling factor (1,2,4,8,16)\n"); - printf("-c ldpc offload flag\n"); printf("-A Interpolation_filname Run with Abstraction to generate Scatter plot using interpolation polynomial in file\n"); //printf("-C Generate Calibration information for Abstraction (effective SNR adjustment to remove Pe bias w.r.t. AWGN)\n"); printf("-f raw file containing RRC configuration (generated by gNB)\n"); @@ -640,7 +634,6 @@ int main(int argc, char **argv) gNB = RC.gNB[0]; gNB->ofdm_offset_divisor = UINT_MAX; - gNB->ldpc_offload_flag = ldpc_offload_flag; gNB->phase_comp = true; // we need to perform phase compensation, otherwise everything will fail frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH) frame_parms->nb_antennas_tx = n_tx; @@ -849,6 +842,7 @@ int main(int argc, char **argv) memcpy(&UE->frame_parms,frame_parms,sizeof(NR_DL_FRAME_PARMS)); UE->frame_parms.nb_antennas_rx = n_rx; UE->frame_parms.nb_antenna_ports_gNB = n_tx; + UE->nrLDPC_coding_interface = gNB->nrLDPC_coding_interface; UE->max_ldpc_iterations = max_ldpc_iterations; init_nr_ue_phy_cpu_stats(&UE->phy_cpu_stats); @@ -1337,8 +1331,7 @@ int main(int argc, char **argv) free(UE->phy_sim_pdsch_dl_ch_estimates_ext); free(UE->phy_sim_dlsch_b); - if (gNB->ldpc_offload_flag) - free_LDPClib(&ldpc_interface_offload); + free_nrLDPC_coding_interface(&gNB->nrLDPC_coding_interface); if (output_fd) fclose(output_fd); diff --git a/openair1/SIMULATION/NR_PHY/ulschsim.c b/openair1/SIMULATION/NR_PHY/ulschsim.c index f578e217e9..e2802feffd 100644 --- a/openair1/SIMULATION/NR_PHY/ulschsim.c +++ b/openair1/SIMULATION/NR_PHY/ulschsim.c @@ -33,6 +33,7 @@ #include "PHY/defs_nr_common.h" #include "PHY/defs_nr_UE.h" #include "PHY/defs_gNB.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" #include "PHY/INIT/nr_phy_init.h" #include "PHY/NR_REFSIG/refsig_defs_ue.h" #include "PHY/MODULATION/modulation_eNB.h" @@ -90,28 +91,6 @@ void deref_sched_response(int _) exit(1); } -int nr_postDecode_sim(PHY_VARS_gNB *gNB, ldpcDecode_t *rdata, int *nb_ok) -{ - NR_UL_gNB_HARQ_t *ulsch_harq = rdata->ulsch_harq; - int r = rdata->segment_r; - - bool decodeSuccess = (rdata->decodeIterations <= rdata->decoderParms.numMaxIter); - ulsch_harq->processedSegments++; - - if (decodeSuccess) { - memcpy(ulsch_harq->b+rdata->offset, - ulsch_harq->c[r], - rdata->Kr_bytes - (ulsch_harq->F>>3) -((ulsch_harq->C>1)?3:0)); - } - - // if all segments are done - if (rdata->nbSegments == ulsch_harq->processedSegments) { - return *nb_ok == rdata->nbSegments; - } - - return 0; -} - nrUE_params_t nrUE_params; nrUE_params_t *get_nrUE_params(void) { @@ -143,7 +122,6 @@ int main(int argc, char **argv) NR_DL_FRAME_PARMS *frame_parms; double sigma; unsigned char qbits = 8; - int ret=0; int loglvl = OAILOG_WARNING; uint64_t SSB_positions=0x01; uint16_t nb_symb_sch = 12; @@ -439,6 +417,7 @@ int main(int argc, char **argv) UE->frame_parms.nb_antennas_tx = n_tx; UE->frame_parms.nb_antennas_rx = 1; + UE->nrLDPC_coding_interface = gNB->nrLDPC_coding_interface; //phy_init_nr_top(frame_parms); if (init_nr_ue_signal(UE, 1) != 0) { @@ -448,6 +427,8 @@ int main(int argc, char **argv) nr_init_ul_harq_processes(UE->ul_harq_processes, NR_MAX_ULSCH_HARQ_PROCESSES, UE->frame_parms.N_RB_UL, UE->frame_parms.nb_antennas_tx); + initFloatingCoresTpool(1, &nrUE_params.Tpool, false, "UE-tpool"); + unsigned char harq_pid = 0; unsigned int TBS = 8424; unsigned int available_bits; @@ -530,7 +511,8 @@ int main(int argc, char **argv) unsigned int G = available_bits; if (input_fd == NULL) { - nr_ulsch_encoding(UE, ulsch_ue, frame_parms, harq_pid, TBS>>3, G); + uint8_t ULSCH_ids[] = {0}; + nr_ulsch_encoding(UE, ulsch_ue, 0, 0, &G, 1, ULSCH_ids); } printf("\n"); @@ -594,21 +576,11 @@ int main(int argc, char **argv) exit(-1); #endif - ldpcDecode_t arr[16] = {0}; - task_ans_t ans[16] = {0}; - thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .cap = 16, .len = 0, .ans = ans}; - int nbDecode = - nr_ulsch_decoding(gNB, UE_id, channel_output_fixed, frame_parms, rel15_ul, frame, subframe, harq_pid, G, &t_info); - DevAssert(nbDecode > 0); - - int nb_ok = 0; - join_task_ans(t_info.ans, t_info.len); - for (size_t i = 0; i < nbDecode; ++i) { - ret = nr_postDecode_sim(gNB, &arr[i], &nb_ok); - } - nbDecode = 0; - if (ret) + nr_ulsch_decoding(gNB, frame_parms, frame, subframe, &G, &UE_id, 1); + bool crc_valid = check_crc(harq_process_gNB->b, lenWithCrc(1, (harq_process_gNB->TBS) << 3), crcType(1, (harq_process_gNB->TBS) << 3)); + if (!crc_valid) { n_errors++; + } } printf("*****************************************\n"); @@ -633,6 +605,8 @@ int main(int argc, char **argv) free(gNB->gNB_config.tdd_table.max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list); free(gNB->gNB_config.tdd_table.max_tdd_periodicity_list); + free_nrLDPC_coding_interface(&gNB->nrLDPC_coding_interface); + term_nr_ue_signal(UE, 1); free(UE); diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 8ffa0e4a3f..bdeab5a139 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -45,7 +45,7 @@ #include "NR_ReconfigurationWithSync.h" #include "NR_ServingCellConfig.h" #include "NR_UE-NR-Capability.h" -#include "PHY/CODING/nrLDPC_extern.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" #include "PHY/INIT/nr_phy_init.h" #include "PHY/MODULATION/nr_modulation.h" #include "PHY/NR_REFSIG/dmrs_nr.h" @@ -212,7 +212,6 @@ int main(int argc, char *argv[]) double effRate; double effTP; float eff_tp_check = 100; - int ldpc_offload_flag = 0; uint8_t max_rounds = 4; int chest_type[2] = {0}; int enable_ptrs = 0; @@ -251,7 +250,7 @@ int main(int argc, char *argv[]) InitSinLUT(); int c; - while ((c = getopt(argc, argv, "--:O:a:b:c:d:ef:g:h:i:k:m:n:op:q:r:s:t:u:v:w:y:z:A:C:F:G:H:I:M:N:PR:S:T:U:L:ZW:E:X:")) != -1) { + while ((c = getopt(argc, argv, "--:O:a:b:c:d:ef:g:h:i:k:m:n:p:q:r:s:t:u:v:w:y:z:A:C:F:G:H:I:M:N:PR:S:T:U:L:ZW:E:X:")) != -1) { /* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */ /* with this opstring getopt returns 1 for non-option arguments, refer to 'man 3 getopt' */ @@ -364,10 +363,6 @@ int main(int argc, char *argv[]) n_trials = atoi(optarg); break; - case 'o': - ldpc_offload_flag = 1; - break; - case 'p': extended_prefix_flag = 1; break; @@ -531,7 +526,6 @@ int main(int argc, char *argv[]) printf("-k 3/4 sampling\n"); printf("-m MCS value\n"); printf("-n Number of trials to simulate\n"); - printf("-o ldpc offload flag\n"); printf("-p Use extended prefix mode\n"); printf("-q MCS table\n"); printf("-r Number of allocated resource blocks for PUSCH\n"); @@ -682,7 +676,6 @@ int main(int argc, char *argv[]) cfg->carrier_config.num_rx_ant.value = n_rx; // nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu,0,0x01); - gNB->ldpc_offload_flag = ldpc_offload_flag; gNB->chest_freq = chest_type[0]; gNB->chest_time = chest_type[1]; @@ -729,6 +722,7 @@ int main(int argc, char *argv[]) memcpy(&UE->frame_parms, frame_parms, sizeof(NR_DL_FRAME_PARMS)); UE->frame_parms.nb_antennas_tx = n_tx; UE->frame_parms.nb_antennas_rx = 0; + UE->nrLDPC_coding_interface = gNB->nrLDPC_coding_interface; if (init_nr_ue_signal(UE, 1) != 0) { printf("Error at UE NR initialisation\n"); @@ -751,6 +745,8 @@ int main(int argc, char *argv[]) UE_mac->if_module = nr_ue_if_module_init(0); + initFloatingCoresTpool(threadCnt, &nrUE_params.Tpool, false, "UE-tpool"); + nr_ue_phy_config_request(&UE_mac->phy_config); unsigned char harq_pid = 0; @@ -1596,8 +1592,8 @@ int main(int argc, char *argv[]) num_dmrs_cdm_grps_no_data); free_MIB_NR(mib); - if (gNB->ldpc_offload_flag) - free_LDPClib(&ldpc_interface_offload); + + free_nrLDPC_coding_interface(&gNB->nrLDPC_coding_interface); if (output_fd) fclose(output_fd); From 49bdcfd95cfdd069cd8ef8397d84856bbaf56d3d Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Wed, 9 Oct 2024 14:31:56 +0200 Subject: [PATCH 41/83] feat(nrLDPC_coding_interface): Add ldpc_slot_segment coding library --- CMakeLists.txt | 15 +- .../nrLDPC_coding_segment_decoder.c | 344 ++++++++++++++++++ .../nrLDPC_coding_segment_encoder.c | 245 +++++++++++++ 3 files changed, 601 insertions(+), 3 deletions(-) create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c diff --git a/CMakeLists.txt b/CMakeLists.txt index d9a226aed4..b446d7fb41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -849,6 +849,12 @@ set(PHY_NR_CODINGIF ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c ) +set(PHY_NRLDPC_CODING_SEGMENT_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c + ${PHY_NR_CODINGIF} +) + set(PHY_NRLDPC_CODINGIF ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface_load.c ) @@ -873,6 +879,7 @@ add_library(coding MODULE ${PHY_TURBOSRC} ) add_library(dfts MODULE ${OPENAIR1_DIR}/PHY/TOOLS/oai_dfts.c ${OPENAIR1_DIR}/PHY/TOOLS/oai_dfts_neon.c) +add_library(ldpc_slot_segment MODULE ${PHY_NRLDPC_CODING_SEGMENT_SRC}) set(PHY_SRC_COMMON ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_tools_common.c @@ -2049,7 +2056,7 @@ if(E2_AGENT) endif() -add_dependencies(nr-softmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc) +add_dependencies(nr-softmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc ldpc_slot_segment) if (ENABLE_LDPC_T2) add_dependencies(nr-softmodem ldpc_t2) @@ -2106,7 +2113,7 @@ target_link_libraries(nr-uesoftmodem PRIVATE pthread m CONFIG_LIB rt nr_ue_phy_m target_link_libraries(nr-uesoftmodem PRIVATE ${T_LIB}) target_link_libraries(nr-uesoftmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) -add_dependencies( nr-uesoftmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc ) +add_dependencies( nr-uesoftmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc ldpc_slot_segment) if (ENABLE_LDPC_CUDA) add_dependencies(nr-uesoftmodem ldpc_cuda) add_dependencies(nr-softmodem ldpc_cuda) @@ -2269,6 +2276,7 @@ add_executable(nr_ulsim if (ENABLE_LDPC_T2) add_dependencies(nr_ulsim ldpc_t2) endif() +add_dependencies(nr_ulsim ldpc_slot_segment) target_link_libraries(nr_ulsim PRIVATE -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON nr_rrc CONFIG_LIB L2_NR HASHTABLE x2ap SECURITY ngap -lz -Wl,--end-group @@ -2335,7 +2343,8 @@ if (${T_TRACER}) PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU PHY_MEX L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE L2_UE_LTE_NR MAC_NR_COMMON MAC_UE_NR ngap CN_UTILS GTPV1U SCTP_CLIENT MME_APP LIB_NAS_UE NB_IoT SIMU OPENAIR0_LIB - ldpc_orig ldpc_optim ldpc_optim8seg ldpc_t2 ldpc_cl ldpc_cuda ldpc dfts config_internals nr_common) + ldpc_orig ldpc_optim ldpc_optim8seg ldpc_t2 ldpc_cl ldpc_cuda ldpc ldpc_slot_segment + dfts config_internals nr_common) if (TARGET ${i}) add_dependencies(${i} generate_T) endif() diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c new file mode 100644 index 0000000000..9264c7a5b6 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c @@ -0,0 +1,344 @@ +/* + * 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.0 (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 PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c +* \brief Top-level routines for decoding LDPC transport channels +*/ + + +// [from gNB coding] +#include "PHY/defs_gNB.h" +#include "PHY/CODING/coding_extern.h" +#include "PHY/CODING/coding_defs.h" +#include "PHY/CODING/lte_interleaver_inline.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" +#include "PHY/CODING/nrLDPC_extern.h" +#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" +#include "PHY/NR_TRANSPORT/nr_transport_proto.h" +#include "PHY/NR_TRANSPORT/nr_ulsch.h" +#include "PHY/NR_TRANSPORT/nr_dlsch.h" +#include "SCHED_NR/sched_nr.h" +#include "SCHED_NR/fapi_nr_l1.h" +#include "defs.h" +#include "common/utils/LOG/vcd_signal_dumper.h" +#include "common/utils/LOG/log.h" + +#include +#include +#include +#include +//#define gNB_DEBUG_TRACE + +#define OAI_LDPC_DECODER_MAX_NUM_LLR 27000 //26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX = 68*384 +//#define DEBUG_CRC +#ifdef DEBUG_CRC +#define PRINT_CRC_CHECK(a) a +#else +#define PRINT_CRC_CHECK(a) +#endif + +#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h" +#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h" + +/** + * \typedef nrLDPC_decoding_parameters_t + * \struct nrLDPC_decoding_parameters_s + * \brief decoding parameter of transport blocks + * \var decoderParms decoder parameters + * \var Qm modulation order + * \var Kc size of base graph input + * \var rv_index + * \var max_number_iterations maximum number of LDPC iterations + * \var abort_decode pointer to decode abort flag + * \var tbslbrm transport block size LBRM in bytes + * \var A Transport block size (This is A from 38.212 V15.4.0 section 5.1) + * \var K Code block size at decoder output + * \var Z lifting size + * \var F filler bits size + * \var r segment index in TB + * \var E input llr segment size + * \var C number of segments + * \var llr input llr segment array + * \var d Pointers to code blocks before LDPC decoding (38.212 V15.4.0 section 5.3.2) + * \var d_to_be_cleared + * pointer to the flag used to clear d properly + * when true, clear d after rate dematching + * \var c Pointers to code blocks after LDPC decoding (38.212 V15.4.0 section 5.2.2) + * \var decodeSuccess pointer to the flag indicating that the decoding of the segment was successful + * \var ans pointer to task answer used by the thread pool to detect task completion + * \var p_ts_deinterleave pointer to deinterleaving time stats + * \var p_ts_rate_unmatch pointer to rate unmatching time stats + * \var p_ts_ldpc_decode pointer to decoding time stats + */ +typedef struct nrLDPC_decoding_parameters_s{ + + t_nrLDPC_dec_params decoderParms; + + uint8_t Qm; + + uint8_t Kc; + uint8_t rv_index; + decode_abort_t *abort_decode; + + uint32_t tbslbrm; + uint32_t A; + uint32_t K; + uint32_t Z; + uint32_t F; + + uint32_t C; + + int E; + short *llr; + int16_t *d; + bool *d_to_be_cleared; + uint8_t *c; + bool *decodeSuccess; + + task_ans_t *ans; + + time_stats_t *p_ts_deinterleave; + time_stats_t *p_ts_rate_unmatch; + time_stats_t *p_ts_ldpc_decode; +} nrLDPC_decoding_parameters_t; + +// Global var to limit the rework of the dirty legacy code +ldpc_interface_t ldpc_interface_segment; + +static void nr_process_decode_segment(void *arg) +{ + nrLDPC_decoding_parameters_t *rdata = (nrLDPC_decoding_parameters_t *)arg; + t_nrLDPC_dec_params *p_decoderParms = &rdata->decoderParms; + const int Kr = rdata->K; + const int Kr_bytes = Kr >> 3; + const int K_bits_F = Kr - rdata->F; + const int A = rdata->A; + const int E = rdata->E; + const int Qm = rdata->Qm; + const int rv_index = rdata->rv_index; + const uint8_t kc = rdata->Kc; + short *ulsch_llr = rdata->llr; + int8_t llrProcBuf[OAI_LDPC_DECODER_MAX_NUM_LLR] __attribute__((aligned(32))); + + t_nrLDPC_time_stats procTime = {0}; + t_nrLDPC_time_stats *p_procTime = &procTime; + + //////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////// nr_deinterleaving_ldpc /////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////// ulsch_llr =====> ulsch_harq->e ////////////////////////////// + + start_meas(rdata->p_ts_deinterleave); + + /// code blocks after bit selection in rate matching for LDPC code (38.212 V15.4.0 section 5.4.2.1) + int16_t harq_e[E]; + + nr_deinterleaving_ldpc(E, Qm, harq_e, ulsch_llr); + + ////////////////////////////////////////////////////////////////////////////////////////// + + stop_meas(rdata->p_ts_deinterleave); + + start_meas(rdata->p_ts_rate_unmatch); + + ////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////// nr_rate_matching_ldpc_rx //////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////// ulsch_harq->e =====> ulsch_harq->d ///////////////////////// + + + if (nr_rate_matching_ldpc_rx(rdata->tbslbrm, + p_decoderParms->BG, + p_decoderParms->Z, + rdata->d, + harq_e, + rdata->C, + rv_index, + *rdata->d_to_be_cleared, + E, + rdata->F, + Kr - rdata->F - 2 * (p_decoderParms->Z)) + == -1) { + + stop_meas(rdata->p_ts_rate_unmatch); + LOG_E(PHY, "nrLDPC_coding_segment_decoder.c: Problem in rate_matching\n"); + + // Task completed + completed_task_ans(rdata->ans); + return; + } + stop_meas(rdata->p_ts_rate_unmatch); + + *rdata->d_to_be_cleared = false; + + memset(rdata->c, 0, Kr_bytes); + p_decoderParms->crc_type = crcType(rdata->C, A); + p_decoderParms->E = lenWithCrc(rdata->C, A); + + // set first 2*Z_c bits to zeros + + int16_t z[68 * 384 + 16] __attribute__((aligned(16))); + + start_meas(rdata->p_ts_ldpc_decode); + + memset(z, 0, 2 * rdata->Z * sizeof(*z)); + // set Filler bits + memset(z + K_bits_F, 127, rdata->F * sizeof(*z)); + // Move coded bits before filler bits + memcpy(z + 2 * rdata->Z, rdata->d, (K_bits_F - 2 * rdata->Z) * sizeof(*z)); + // skip filler bits + memcpy(z + Kr, rdata->d + (Kr - 2 * rdata->Z), (kc * rdata->Z - Kr) * sizeof(*z)); + // Saturate coded bits before decoding into 8 bits values + simde__m128i *pv = (simde__m128i *)&z; + int8_t l[68 * 384 + 16] __attribute__((aligned(16))); + simde__m128i *pl = (simde__m128i *)&l; + for (int i = 0, j = 0; j < ((kc * rdata->Z) >> 4) + 1; i += 2, j++) { + pl[j] = simde_mm_packs_epi16(pv[i], pv[i + 1]); + } + ////////////////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////// nrLDPC_decoder ///////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////// pl =====> llrProcBuf ////////////////////////////////// + int decodeIterations = + ldpc_interface_segment.LDPCdecoder(p_decoderParms, 0, 0, 0, l, llrProcBuf, p_procTime, rdata->abort_decode); + + if (decodeIterations <= p_decoderParms->numMaxIter) { + memcpy(rdata->c,llrProcBuf, Kr>>3); + *rdata->decodeSuccess = true; + } else { + *rdata->decodeSuccess = false; + } + stop_meas(rdata->p_ts_ldpc_decode); + + // Task completed + completed_task_ans(rdata->ans); +} + +int nrLDPC_prepare_TB_decoding(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters, int pusch_id, thread_info_tm_t *t_info) +{ + + nrLDPC_TB_decoding_parameters_t *nrLDPC_TB_decoding_parameters = &nrLDPC_slot_decoding_parameters->TBs[pusch_id]; + + *nrLDPC_TB_decoding_parameters->processedSegments = 0; + t_nrLDPC_dec_params decParams = {.check_crc = check_crc}; + decParams.BG = nrLDPC_TB_decoding_parameters->BG; + decParams.Z = nrLDPC_TB_decoding_parameters->Z; + decParams.numMaxIter = nrLDPC_TB_decoding_parameters->max_ldpc_iterations; + decParams.outMode = 0; + + for (int r = 0; r < nrLDPC_TB_decoding_parameters->C; r++) { + + nrLDPC_decoding_parameters_t *rdata = &((nrLDPC_decoding_parameters_t *)t_info->buf)[t_info->len]; + DevAssert(t_info->len < t_info->cap); + rdata->ans = &t_info->ans[t_info->len]; + t_info->len += 1; + + decParams.R = nrLDPC_TB_decoding_parameters->segments[r].R; + decParams.setCombIn = !nrLDPC_TB_decoding_parameters->segments[r].d_to_be_cleared; + rdata->decoderParms = decParams; + rdata->llr = nrLDPC_TB_decoding_parameters->segments[r].llr; + rdata->Kc = decParams.BG == 2 ? 52 : 68; + rdata->C = nrLDPC_TB_decoding_parameters->C; + rdata->E = nrLDPC_TB_decoding_parameters->segments[r].E; + rdata->A = nrLDPC_TB_decoding_parameters->A; + rdata->Qm = nrLDPC_TB_decoding_parameters->Qm; + rdata->K = nrLDPC_TB_decoding_parameters->K; + rdata->Z = nrLDPC_TB_decoding_parameters->Z; + rdata->F = nrLDPC_TB_decoding_parameters->F; + rdata->rv_index = nrLDPC_TB_decoding_parameters->rv_index; + rdata->tbslbrm = nrLDPC_TB_decoding_parameters->tbslbrm; + rdata->abort_decode = nrLDPC_TB_decoding_parameters->abort_decode; + rdata->d = nrLDPC_TB_decoding_parameters->segments[r].d; + rdata->d_to_be_cleared = nrLDPC_TB_decoding_parameters->segments[r].d_to_be_cleared; + rdata->c = nrLDPC_TB_decoding_parameters->segments[r].c; + rdata->decodeSuccess = &nrLDPC_TB_decoding_parameters->segments[r].decodeSuccess; + rdata->p_ts_deinterleave = &nrLDPC_TB_decoding_parameters->segments[r].ts_deinterleave; + rdata->p_ts_rate_unmatch = &nrLDPC_TB_decoding_parameters->segments[r].ts_rate_unmatch; + rdata->p_ts_ldpc_decode = &nrLDPC_TB_decoding_parameters->segments[r].ts_ldpc_decode; + + task_t t = {.func = &nr_process_decode_segment, .args = rdata}; + pushTpool(nrLDPC_slot_decoding_parameters->threadPool, t); + + LOG_D(PHY, "Added a block to decode, in pipe: %d\n", r); + } + return nrLDPC_TB_decoding_parameters->C; +} + +int32_t nrLDPC_coding_init(void){ + + char *segment_shlibversion = NULL; + paramdef_t LoaderParams[] = { + {"segment_shlibversion", NULL, 0, .strptr = &segment_shlibversion, .defstrval = "", TYPE_STRING, 0, NULL} + }; + config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "nrLDPC_coding_segment"); + load_LDPClib(segment_shlibversion, &ldpc_interface_segment); + + return 0; + +} + +int32_t nrLDPC_coding_shutdown(void){ + + free_LDPClib(&ldpc_interface_segment); + + return 0; + +} + +int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters){ + + int nbSegments = 0; + for (int pusch_id = 0; pusch_id < nrLDPC_slot_decoding_parameters->nb_TBs; pusch_id++) { + nrLDPC_TB_decoding_parameters_t *nrLDPC_TB_decoding_parameters = &nrLDPC_slot_decoding_parameters->TBs[pusch_id]; + nbSegments += nrLDPC_TB_decoding_parameters->C; + } + nrLDPC_decoding_parameters_t arr[nbSegments]; + task_ans_t ans[nbSegments]; + memset(ans, 0, nbSegments * sizeof(task_ans_t)); + thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .len = 0, .cap = nbSegments, .ans = ans}; + + int nbDecode = 0; + for (int pusch_id = 0; pusch_id < nrLDPC_slot_decoding_parameters->nb_TBs; pusch_id++) { + nbDecode += nrLDPC_prepare_TB_decoding(nrLDPC_slot_decoding_parameters, pusch_id, &t_info); + } + + DevAssert(nbDecode == t_info.len); + + // Execute thread poool tasks + join_task_ans(t_info.ans, t_info.len); + + for (int pusch_id = 0; pusch_id < nrLDPC_slot_decoding_parameters->nb_TBs; pusch_id++) { + nrLDPC_TB_decoding_parameters_t *nrLDPC_TB_decoding_parameters = &nrLDPC_slot_decoding_parameters->TBs[pusch_id]; + for (int r = 0; r < nrLDPC_TB_decoding_parameters->C; r++) { + if (nrLDPC_TB_decoding_parameters->segments[r].decodeSuccess) { + *nrLDPC_TB_decoding_parameters->processedSegments = *nrLDPC_TB_decoding_parameters->processedSegments + 1; + } + } + } + return 0; + +} + diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c new file mode 100644 index 0000000000..2a9682d585 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c @@ -0,0 +1,245 @@ +/* + * 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.0 (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 PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c +* \brief Top-level routines for implementing LDPC encoding of transport channels +*/ + +#include "PHY/defs_gNB.h" +#include "PHY/CODING/coding_extern.h" +#include "PHY/CODING/coding_defs.h" +#include "PHY/CODING/lte_interleaver_inline.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" +#include "PHY/CODING/nrLDPC_extern.h" +#include "PHY/NR_TRANSPORT/nr_transport_proto.h" +#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" +#include "PHY/NR_TRANSPORT/nr_dlsch.h" +#include "SCHED_NR/sched_nr.h" +#include "common/utils/LOG/vcd_signal_dumper.h" +#include "common/utils/LOG/log.h" +#include "common/utils/nr/nr_common.h" +#include + +#include + +//#define DEBUG_LDPC_ENCODING +//#define DEBUG_LDPC_ENCODING_FREE 1 + +extern ldpc_interface_t ldpc_interface_segment; + +typedef struct ldpc8blocks_args_s { + nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters; + encoder_implemparams_t impp; +} ldpc8blocks_args_t; + +static void ldpc8blocks_coding_segment(void *p) +{ + ldpc8blocks_args_t *args = (ldpc8blocks_args_t *)p; + nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = args->nrLDPC_TB_encoding_parameters; + encoder_implemparams_t *impp = &args->impp; + + uint8_t mod_order = nrLDPC_TB_encoding_parameters->Qm; + uint16_t nb_rb = nrLDPC_TB_encoding_parameters->nb_rb; + uint32_t A = nrLDPC_TB_encoding_parameters->A; + + unsigned int G = nrLDPC_TB_encoding_parameters->G; + LOG_D(PHY,"dlsch coding A %d Kr %d G %d (nb_rb %d, mod_order %d)\n", + A,impp->K,G, nb_rb,(int)mod_order); + + // nrLDPC_encoder output is in "d" + // let's make this interface happy! + uint8_t tmp[8][68 * 384]__attribute__((aligned(32))); + uint8_t *d[impp->n_segments]; + for (int rr=impp->macro_num*8, i=0; rr < impp->n_segments && rr < (impp->macro_num+1)*8; rr++,i++ ) + d[rr] = tmp[i]; + + uint8_t *c[nrLDPC_TB_encoding_parameters->C]; + for (int r = 0; r < nrLDPC_TB_encoding_parameters->C; r++) + c[r]=nrLDPC_TB_encoding_parameters->segments[r].c; + start_meas(&nrLDPC_TB_encoding_parameters->segments[impp->macro_num*8].ts_ldpc_encode); + ldpc_interface_segment.LDPCencoder(c, d, impp); + stop_meas(&nrLDPC_TB_encoding_parameters->segments[impp->macro_num*8].ts_ldpc_encode); + // Compute where to place in output buffer that is concatenation of all segments + + uint32_t r_offset=0; + for (int i=0; i < impp->macro_num*8; i++ ) + r_offset+=nrLDPC_TB_encoding_parameters->segments[i].E; + for (int rr=impp->macro_num*8; rr < impp->n_segments && rr < (impp->macro_num+1)*8; rr++ ) { + if (impp->F>0) { + // writing into positions d[r][k-2Zc] as in clause 5.3.2 step 2) in 38.212 + memset(&d[rr][impp->K - impp->F - 2 * impp->Zc], NR_NULL, impp->F); + } + +#ifdef DEBUG_LDPC_ENCODING + LOG_D(PHY,"rvidx in encoding = %d\n", rel15->rvIndex[0]); +#endif + uint32_t E = nrLDPC_TB_encoding_parameters->segments[rr].E; + LOG_D(NR_PHY, + "Rate Matching, Code segment %d/%d (coded bits (G) %u, E %d, Filler bits %d, Filler offset %d mod_order %d, nb_rb " + "%d,nrOfLayer %d)...\n", + rr, + impp->n_segments, + G, + E, + impp->F, + impp->K - impp->F - 2 * impp->Zc, + mod_order, + nb_rb, + nrLDPC_TB_encoding_parameters->nb_layers); + + uint32_t Tbslbrm = nrLDPC_TB_encoding_parameters->tbslbrm; + + uint8_t e[E]; + bzero (e, E); + start_meas(&nrLDPC_TB_encoding_parameters->segments[rr].ts_rate_match); + nr_rate_matching_ldpc(Tbslbrm, + impp->BG, + impp->Zc, + d[rr], + e, + impp->n_segments, + impp->F, + impp->K - impp->F - 2 * impp->Zc, + nrLDPC_TB_encoding_parameters->rv_index, + E); + stop_meas(&nrLDPC_TB_encoding_parameters->segments[rr].ts_rate_match); + if (impp->K - impp->F - 2 * impp->Zc > E) { + LOG_E(PHY, + "dlsch coding A %d Kr %d G %d (nb_rb %d, mod_order %d)\n", + A, + impp->K, + G, + nb_rb, + (int)mod_order); + + LOG_E(NR_PHY, + "Rate Matching, Code segment %d/%d (coded bits (G) %u, E %d, Kr %d, Filler bits %d, Filler offset %d mod_order %d, " + "nb_rb %d)...\n", + rr, + impp->n_segments, + G, + E, + impp->K, + impp->F, + impp->K - impp->F - 2 * impp->Zc, + mod_order, + nb_rb); + } +#ifdef DEBUG_LDPC_ENCODING + + for (int i =0; i<16; i++) + printf("output ratematching e[%d]= %d r_offset %u\n", i,e[i], r_offset); + +#endif + start_meas(&nrLDPC_TB_encoding_parameters->segments[rr].ts_interleave); + nr_interleaving_ldpc(E, + mod_order, + e, + impp->output+r_offset); + stop_meas(&nrLDPC_TB_encoding_parameters->segments[rr].ts_interleave); +#ifdef DEBUG_LDPC_ENCODING + + for (int i =0; i<16; i++) + printf("output interleaving f[%d]= %d r_offset %u\n", i,impp->output[i+r_offset], r_offset); + + if (r==impp->n_segments-1) + write_output("enc_output.m","enc",impp->output,G,1,4); + +#endif + r_offset += E; + } + + // Task running in // completed + completed_task_ans(impp->ans); +} + +static int nrLDPC_prepare_TB_encoding(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters, int dlsch_id, thread_info_tm_t *t_info) +{ + nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = &nrLDPC_slot_encoding_parameters->TBs[dlsch_id]; + + encoder_implemparams_t impp = {0}; + + impp.n_segments = nrLDPC_TB_encoding_parameters->C; + impp.tinput = nrLDPC_slot_encoding_parameters->tinput; + impp.tprep = nrLDPC_slot_encoding_parameters->tprep; + impp.tparity = nrLDPC_slot_encoding_parameters->tparity; + impp.toutput = nrLDPC_slot_encoding_parameters->toutput; + impp.Kb = nrLDPC_TB_encoding_parameters->Kb; + impp.Zc = nrLDPC_TB_encoding_parameters->Z; + NR_DL_gNB_HARQ_t harq; + impp.harq = &harq; + impp.BG = nrLDPC_TB_encoding_parameters->BG; + impp.output = nrLDPC_TB_encoding_parameters->segments->output; + impp.K = nrLDPC_TB_encoding_parameters->K; + impp.F = nrLDPC_TB_encoding_parameters->F; + impp.Qm = nrLDPC_TB_encoding_parameters->Qm; + impp.Tbslbrm = nrLDPC_TB_encoding_parameters->tbslbrm; + impp.G = nrLDPC_TB_encoding_parameters->G; + for (int r = 0; r < nrLDPC_TB_encoding_parameters->C; r++) { + impp.perCB[r].E_cb = nrLDPC_TB_encoding_parameters->segments[r].E; + } + impp.rv = nrLDPC_TB_encoding_parameters->rv_index; + + size_t const n_seg = (impp.n_segments / 8 + ((impp.n_segments & 7) == 0 ? 0 : 1)); + + for (int j = 0; j < n_seg; j++) { + ldpc8blocks_args_t *perJobImpp = &((ldpc8blocks_args_t *)t_info->buf)[t_info->len]; + DevAssert(t_info->len < t_info->cap); + impp.ans = &t_info->ans[t_info->len]; + t_info->len += 1; + + impp.macro_num = j; + perJobImpp->impp = impp; + perJobImpp->nrLDPC_TB_encoding_parameters = nrLDPC_TB_encoding_parameters; + + task_t t = {.func = ldpc8blocks_coding_segment, .args = perJobImpp}; + pushTpool(nrLDPC_slot_encoding_parameters->threadPool, t); + } + return n_seg; +} + +int nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) +{ + + int nbTasks = 0; + for (int dlsch_id = 0; dlsch_id < nrLDPC_slot_encoding_parameters->nb_TBs; dlsch_id++) { + nrLDPC_TB_encoding_parameters_t *nrLDPC_TB_encoding_parameters = &nrLDPC_slot_encoding_parameters->TBs[dlsch_id]; + size_t n_seg = (nrLDPC_TB_encoding_parameters->C / 8 + ((nrLDPC_TB_encoding_parameters->C & 7) == 0 ? 0 : 1)); + nbTasks += n_seg; + } + ldpc8blocks_args_t arr[nbTasks]; + task_ans_t ans[nbTasks]; + memset(ans, 0, nbTasks * sizeof(task_ans_t)); + thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .len = 0, .cap = nbTasks, .ans = ans}; + + int nbEncode = 0; + for (int dlsch_id = 0; dlsch_id < nrLDPC_slot_encoding_parameters->nb_TBs; dlsch_id++) { + nbEncode += nrLDPC_prepare_TB_encoding(nrLDPC_slot_encoding_parameters, dlsch_id, &t_info); + } + + DevAssert(nbEncode == t_info.len); + + // Execute thread poool tasks + join_task_ans(ans, nbEncode); + + return 0; + +} From c6bdde1244c741ab5deb055f6a443b67ab06e0e4 Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Wed, 9 Oct 2024 14:40:52 +0200 Subject: [PATCH 42/83] feat(nrLDPC_coding_interface): Add ldpc_slot_t2 coding library --- CMakeLists.txt | 16 +- .../nrLDPC_coding_t2/nrLDPC_coding_t2.c | 1105 +++++++++++++++++ .../nrLDPC_coding_t2/nrLDPC_coding_t2.h} | 0 .../PHY/CODING/nrLDPC_decoder/nrLDPC_types.h | 17 - 4 files changed, 1118 insertions(+), 20 deletions(-) create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c rename openair1/PHY/CODING/{nrLDPC_decoder/nrLDPC_offload.h => nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.h} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index b446d7fb41..45e5ba97dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -501,6 +501,12 @@ if (ENABLE_LDPC_T2) add_library(ldpc_t2 MODULE ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c) set_target_properties(ldpc_t2 PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API") target_link_libraries(ldpc_t2 ${LIBDPDK_T2_LDFLAGS} ${PMD_T2}) + set(PHY_NRLDPC_CODING_T2_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c + ) + add_library(ldpc_slot_t2 MODULE ${PHY_NRLDPC_CODING_T2_SRC}) + set_target_properties(ldpc_slot_t2 PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API") + target_link_libraries(ldpc_slot_t2 PRIVATE ldpc_gen_HEADERS ${LIBDPDK_T2_LDFLAGS} ${PMD_T2}) endif() ########################################################## @@ -2059,7 +2065,7 @@ endif() add_dependencies(nr-softmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc ldpc_slot_segment) if (ENABLE_LDPC_T2) - add_dependencies(nr-softmodem ldpc_t2) + add_dependencies(nr-softmodem ldpc_t2 ldpc_slot_t2) endif() # force the generation of ASN.1 so that we don't need to wait during the build @@ -2119,6 +2125,10 @@ if (ENABLE_LDPC_CUDA) add_dependencies(nr-softmodem ldpc_cuda) endif() +if (ENABLE_LDPC_T2) + add_dependencies(nr-uesoftmodem ldpc_t2 ldpc_slot_t2) +endif() + # force the generation of ASN.1 so that we don't need to wait during the build target_link_libraries(nr-uesoftmodem PRIVATE asn1_lte_rrc asn1_nr_rrc asn1_s1ap asn1_ngap asn1_m2ap asn1_m3ap asn1_x2ap asn1_f1ap asn1_lpp) @@ -2274,7 +2284,7 @@ add_executable(nr_ulsim ) if (ENABLE_LDPC_T2) - add_dependencies(nr_ulsim ldpc_t2) + add_dependencies(nr_ulsim ldpc_t2 ldpc_slot_t2) endif() add_dependencies(nr_ulsim ldpc_slot_segment) @@ -2343,7 +2353,7 @@ if (${T_TRACER}) PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU PHY_MEX L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE L2_UE_LTE_NR MAC_NR_COMMON MAC_UE_NR ngap CN_UTILS GTPV1U SCTP_CLIENT MME_APP LIB_NAS_UE NB_IoT SIMU OPENAIR0_LIB - ldpc_orig ldpc_optim ldpc_optim8seg ldpc_t2 ldpc_cl ldpc_cuda ldpc ldpc_slot_segment + ldpc_orig ldpc_optim ldpc_optim8seg ldpc_t2 ldpc_cl ldpc_cuda ldpc ldpc_slot_segment ldpc_slot_t2 dfts config_internals nr_common) if (TARGET ${i}) add_dependencies(${i} generate_T) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c new file mode 100644 index 0000000000..fa5aa2d482 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -0,0 +1,1105 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Intel Corporation + */ + +/*! \file PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c + * \note: based on testbbdev test_bbdev_perf.c functions. Harq buffer offset added. + * \mbuf and mempool allocated at the init step, LDPC parameters updated from OAI. + */ + +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.h" +#include "PHY/sse_intrin.h" +#include +#define NR_LDPC_ENABLE_PARITY_CHECK + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// this socket is the NUMA socket, so the hardware CPU id (numa is complex) +#define GET_SOCKET(socket_id) (((socket_id) == SOCKET_ID_ANY) ? 0 : (socket_id)) +#define MAX_QUEUES 32 +#define OPS_CACHE_SIZE 256U +#define OPS_POOL_SIZE_MIN 511U /* 0.5K per queue */ +#define SYNC_WAIT 0 +#define SYNC_START 1 +#define TIME_OUT_POLL 1e8 +/* Increment for next code block in external HARQ memory */ +#define HARQ_INCR 32768 +/* Headroom for filler LLRs insertion in HARQ buffer */ +#define FILLER_HEADROOM 1024 +/* Number of segments that could be stored in HARQ combined buffers */ +#define HARQ_CODEBLOCK_ID_MAX (16 << 5) + +pthread_mutex_t encode_mutex; +pthread_mutex_t decode_mutex; + +const char *typeStr[] = { + "RTE_BBDEV_OP_NONE", /**< Dummy operation that does nothing */ + "RTE_BBDEV_OP_TURBO_DEC", /**< Turbo decode */ + "RTE_BBDEV_OP_TURBO_ENC", /**< Turbo encode */ + "RTE_BBDEV_OP_LDPC_DEC", /**< LDPC decode */ + "RTE_BBDEV_OP_LDPC_ENC", /**< LDPC encode */ + "RTE_BBDEV_OP_TYPE_COUNT", /**< Count of different op types */ +}; + +/* Represents tested active devices */ +struct active_device { + const char *driver_name; + uint8_t dev_id; + int dec_queue; + int enc_queue; + uint16_t queue_ids[MAX_QUEUES]; + uint16_t nb_queues; + struct rte_mempool *bbdev_dec_op_pool; + struct rte_mempool *bbdev_enc_op_pool; + struct rte_mempool *in_mbuf_pool; + struct rte_mempool *hard_out_mbuf_pool; + struct rte_mempool *soft_out_mbuf_pool; + struct rte_mempool *harq_in_mbuf_pool; + struct rte_mempool *harq_out_mbuf_pool; +} active_devs[RTE_BBDEV_MAX_DEVS]; +static int nb_active_devs; + +/* Data buffers used by BBDEV ops */ +struct data_buffers { + struct rte_bbdev_op_data *inputs; + struct rte_bbdev_op_data *hard_outputs; + struct rte_bbdev_op_data *soft_outputs; + struct rte_bbdev_op_data *harq_inputs; + struct rte_bbdev_op_data *harq_outputs; +}; + +/* Operation parameters specific for given test case */ +struct test_op_params { + struct rte_mempool *mp_dec; + struct rte_mempool *mp_enc; + struct rte_bbdev_dec_op *ref_dec_op; + struct rte_bbdev_enc_op *ref_enc_op; + uint16_t burst_sz; + uint16_t num_to_process; + uint16_t num_lcores; + int vector_mask; + rte_atomic16_t sync; + struct data_buffers q_bufs[RTE_MAX_NUMA_NODES][MAX_QUEUES]; +}; + +/* Contains per lcore params */ +struct thread_params { + uint8_t dev_id; + uint16_t queue_id; + uint32_t lcore_id; + nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters; + nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters; + uint8_t iter_count; + rte_atomic16_t nb_dequeued; + rte_atomic16_t processing_status; + rte_atomic16_t burst_sz; + struct test_op_params *op_params; + struct rte_bbdev_dec_op *dec_ops[MAX_BURST]; + struct rte_bbdev_enc_op *enc_ops[MAX_BURST]; +}; + +static uint16_t nb_segments_decoding(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) { + uint16_t nb_segments = 0; + for (uint16_t h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h) + { + nb_segments+=nrLDPC_slot_decoding_parameters->TBs[h].C; + } + return nb_segments; +} + +static uint16_t nb_segments_encoding(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) { + uint16_t nb_segments = 0; + for (uint16_t h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h) + { + nb_segments+=nrLDPC_slot_encoding_parameters->TBs[h].C; + } + return nb_segments; +} + +// DPDK BBDEV copy +static inline void +mbuf_reset(struct rte_mbuf *m) +{ + m->pkt_len = 0; + + do { + m->data_len = 0; + m = m->next; + } while (m != NULL); +} + +/* Read flag value 0/1 from bitmap */ +// DPDK BBDEV copy +static inline bool +check_bit(uint32_t bitmap, uint32_t bitmask) +{ + return bitmap & bitmask; +} + +/* calculates optimal mempool size not smaller than the val */ +// DPDK BBDEV copy +static unsigned int +optimal_mempool_size(unsigned int val) +{ + return rte_align32pow2(val + 1) - 1; +} + +// based on DPDK BBDEV create_mempools +static int create_mempools(struct active_device *ad, int socket_id, uint16_t num_ops, int out_buff_sz, int in_max_sz) +{ + unsigned int ops_pool_size, mbuf_pool_size, data_room_size = 0; + num_ops = 1; + uint8_t nb_segments = 1; + ops_pool_size = optimal_mempool_size(RTE_MAX( + /* Ops used plus 1 reference op */ + RTE_MAX((unsigned int)(ad->nb_queues * num_ops + 1), + /* Minimal cache size plus 1 reference op */ + (unsigned int)(1.5 * rte_lcore_count() * OPS_CACHE_SIZE + 1)), + OPS_POOL_SIZE_MIN)); + + /* Decoder ops mempool */ + ad->bbdev_dec_op_pool = rte_bbdev_op_pool_create("bbdev_op_pool_dec", RTE_BBDEV_OP_LDPC_DEC, + /* Encoder ops mempool */ ops_pool_size, OPS_CACHE_SIZE, socket_id); + ad->bbdev_enc_op_pool = rte_bbdev_op_pool_create("bbdev_op_pool_enc", RTE_BBDEV_OP_LDPC_ENC, + ops_pool_size, OPS_CACHE_SIZE, socket_id); + + if ((ad->bbdev_dec_op_pool == NULL) || (ad->bbdev_enc_op_pool == NULL)) + AssertFatal(1 == 0, + "ERROR Failed to create %u items ops pool for dev %u on socket %d.", + ops_pool_size, + ad->dev_id, + socket_id); + + /* Inputs */ + mbuf_pool_size = optimal_mempool_size(ops_pool_size * nb_segments); + data_room_size = RTE_MAX(in_max_sz + RTE_PKTMBUF_HEADROOM + FILLER_HEADROOM, (unsigned int)RTE_MBUF_DEFAULT_BUF_SIZE); + ad->in_mbuf_pool = rte_pktmbuf_pool_create("in_mbuf_pool", mbuf_pool_size, 0, 0, data_room_size, socket_id); + AssertFatal(ad->in_mbuf_pool != NULL, + "ERROR Failed to create %u items input pktmbuf pool for dev %u on socket %d.", + mbuf_pool_size, + ad->dev_id, + socket_id); + + /* Hard outputs */ + data_room_size = RTE_MAX(out_buff_sz + RTE_PKTMBUF_HEADROOM + FILLER_HEADROOM, (unsigned int)RTE_MBUF_DEFAULT_BUF_SIZE); + ad->hard_out_mbuf_pool = rte_pktmbuf_pool_create("hard_out_mbuf_pool", mbuf_pool_size, 0, 0, data_room_size, socket_id); + AssertFatal(ad->hard_out_mbuf_pool != NULL, + "ERROR Failed to create %u items hard output pktmbuf pool for dev %u on socket %d.", + mbuf_pool_size, + ad->dev_id, + socket_id); + return 0; +} + +const char *ldpcenc_flag_bitmask[] = { + /** Set for bit-level interleaver bypass on output stream. */ + "RTE_BBDEV_LDPC_INTERLEAVER_BYPASS", + /** If rate matching is to be performed */ + "RTE_BBDEV_LDPC_RATE_MATCH", + /** Set for transport block CRC-24A attach */ + "RTE_BBDEV_LDPC_CRC_24A_ATTACH", + /** Set for code block CRC-24B attach */ + "RTE_BBDEV_LDPC_CRC_24B_ATTACH", + /** Set for code block CRC-16 attach */ + "RTE_BBDEV_LDPC_CRC_16_ATTACH", + /** Set if a device supports encoder dequeue interrupts. */ + "RTE_BBDEV_LDPC_ENC_INTERRUPTS", + /** Set if a device supports scatter-gather functionality. */ + "RTE_BBDEV_LDPC_ENC_SCATTER_GATHER", + /** Set if a device supports concatenation of non byte aligned output */ + "RTE_BBDEV_LDPC_ENC_CONCATENATION", +}; + +const char *ldpcdec_flag_bitmask[] = { + /** Set for transport block CRC-24A checking */ + "RTE_BBDEV_LDPC_CRC_TYPE_24A_CHECK", + /** Set for code block CRC-24B checking */ + "RTE_BBDEV_LDPC_CRC_TYPE_24B_CHECK", + /** Set to drop the last CRC bits decoding output */ + "RTE_BBDEV_LDPC_CRC_TYPE_24B_DROP" + /** Set for bit-level de-interleaver bypass on Rx stream. */ + "RTE_BBDEV_LDPC_DEINTERLEAVER_BYPASS", + /** Set for HARQ combined input stream enable. */ + "RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE", + /** Set for HARQ combined output stream enable. */ + "RTE_BBDEV_LDPC_HQ_COMBINE_OUT_ENABLE", + /** Set for LDPC decoder bypass. + * RTE_BBDEV_LDPC_HQ_COMBINE_OUT_ENABLE must be set. + */ + "RTE_BBDEV_LDPC_DECODE_BYPASS", + /** Set for soft-output stream enable */ + "RTE_BBDEV_LDPC_SOFT_OUT_ENABLE", + /** Set for Rate-Matching bypass on soft-out stream. */ + "RTE_BBDEV_LDPC_SOFT_OUT_RM_BYPASS", + /** Set for bit-level de-interleaver bypass on soft-output stream. */ + "RTE_BBDEV_LDPC_SOFT_OUT_DEINTERLEAVER_BYPASS", + /** Set for iteration stopping on successful decode condition + * i.e. a successful syndrome check. + */ + "RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE", + /** Set if a device supports decoder dequeue interrupts. */ + "RTE_BBDEV_LDPC_DEC_INTERRUPTS", + /** Set if a device supports scatter-gather functionality. */ + "RTE_BBDEV_LDPC_DEC_SCATTER_GATHER", + /** Set if a device supports input/output HARQ compression. */ + "RTE_BBDEV_LDPC_HARQ_6BIT_COMPRESSION", + /** Set if a device supports input LLR compression. */ + "RTE_BBDEV_LDPC_LLR_COMPRESSION", + /** Set if a device supports HARQ input from + * device's internal memory. + */ + "RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_IN_ENABLE", + /** Set if a device supports HARQ output to + * device's internal memory. + */ + "RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_OUT_ENABLE", + /** Set if a device supports loop-back access to + * HARQ internal memory. Intended for troubleshooting. + */ + "RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_LOOPBACK", + /** Set if a device includes LLR filler bits in the circular buffer + * for HARQ memory. If not set, it is assumed the filler bits are not + * in HARQ memory and handled directly by the LDPC decoder. + */ + "RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_FILLERS", +}; + +// based on DPDK BBDEV add_bbdev_dev +static int add_dev(uint8_t dev_id, struct rte_bbdev_info *info) +{ + int ret; + struct active_device *ad = &active_devs[nb_active_devs]; + unsigned int nb_queues; + nb_queues = RTE_MIN(rte_lcore_count(), info->drv.max_num_queues); + nb_queues = RTE_MIN(nb_queues, (unsigned int)MAX_QUEUES); + + /* Display for debug the capabilities of the card */ + for (int i = 0; info->drv.capabilities[i].type != RTE_BBDEV_OP_NONE; i++) { + printf("device: %d, capability[%d]=%s\n", dev_id, i, typeStr[info->drv.capabilities[i].type]); + if (info->drv.capabilities[i].type == RTE_BBDEV_OP_LDPC_ENC) { + const struct rte_bbdev_op_cap_ldpc_enc cap = info->drv.capabilities[i].cap.ldpc_enc; + printf(" buffers: src = %d, dst = %d\n capabilites: ", cap.num_buffers_src, cap.num_buffers_dst); + for (int j = 0; j < sizeof(cap.capability_flags) * 8; j++) + if (cap.capability_flags & (1ULL << j)) + printf("%s ", ldpcenc_flag_bitmask[j]); + printf("\n"); + } + if (info->drv.capabilities[i].type == RTE_BBDEV_OP_LDPC_DEC) { + const struct rte_bbdev_op_cap_ldpc_dec cap = info->drv.capabilities[i].cap.ldpc_dec; + printf(" buffers: src = %d, hard out = %d, soft_out %d, llr size %d, llr decimals %d \n capabilities: ", + cap.num_buffers_src, + cap.num_buffers_hard_out, + cap.num_buffers_soft_out, + cap.llr_size, + cap.llr_decimals); + for (int j = 0; j < sizeof(cap.capability_flags) * 8; j++) + if (cap.capability_flags & (1ULL << j)) + printf("%s ", ldpcdec_flag_bitmask[j]); + printf("\n"); + } + } + + /* setup device */ + ret = rte_bbdev_setup_queues(dev_id, nb_queues, info->socket_id); + if (ret < 0) { + printf("rte_bbdev_setup_queues(%u, %u, %d) ret %i\n", dev_id, nb_queues, info->socket_id, ret); + return -1; + } + + /* setup device queues */ + struct rte_bbdev_queue_conf qconf = { + .socket = info->socket_id, + .queue_size = info->drv.default_queue_conf.queue_size, + }; + + // Search a queue linked to HW capability ldpc decoding + qconf.op_type = RTE_BBDEV_OP_LDPC_ENC; + int queue_id; + for (queue_id = 0; queue_id < nb_queues; ++queue_id) { + ret = rte_bbdev_queue_configure(dev_id, queue_id, &qconf); + if (ret == 0) { + printf("Found LDCP encoding queue (id=%u) at prio%u on dev%u\n", queue_id, qconf.priority, dev_id); + qconf.priority++; + ad->enc_queue = queue_id; + ad->queue_ids[queue_id] = queue_id; + break; + } + } + AssertFatal(queue_id != nb_queues, "ERROR Failed to configure encoding queues on dev %u", dev_id); + + // Search a queue linked to HW capability ldpc encoding + qconf.op_type = RTE_BBDEV_OP_LDPC_DEC; + for (queue_id++; queue_id < nb_queues; ++queue_id) { + ret = rte_bbdev_queue_configure(dev_id, queue_id, &qconf); + if (ret == 0) { + printf("Found LDCP decoding queue (id=%u) at prio%u on dev%u\n", queue_id, qconf.priority, dev_id); + qconf.priority++; + ad->dec_queue = queue_id; + ad->queue_ids[queue_id] = queue_id; + break; + } + } + AssertFatal(queue_id != nb_queues, "ERROR Failed to configure encoding queues on dev %u", dev_id); + ad->nb_queues = 2; + return 0; +} + +// based on DPDK BBDEV init_op_data_objs +static int init_op_data_objs_dec(struct rte_bbdev_op_data *bufs, + uint8_t *input, + nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters, + struct rte_mempool *mbuf_pool, + enum op_data_type op_type, + uint16_t min_alignment) +{ + bool large_input = false; + uint16_t j = 0; + for (uint16_t h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h) { + for (uint16_t i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) { + uint32_t data_len = nrLDPC_slot_decoding_parameters->TBs[h].segments[i].E; + char *data; + struct rte_mbuf *m_head = rte_pktmbuf_alloc(mbuf_pool); + AssertFatal(m_head != NULL, + "Not enough mbufs in %d data type mbuf pool (needed %u, available %u)", + op_type, + nb_segments_decoding(nrLDPC_slot_decoding_parameters), + mbuf_pool->size); + + if (data_len > RTE_BBDEV_LDPC_E_MAX_MBUF) { + printf("Warning: Larger input size than DPDK mbuf %u\n", data_len); + large_input = true; + } + bufs[j].data = m_head; + bufs[j].offset = 0; + bufs[j].length = 0; + + if ((op_type == DATA_INPUT) || (op_type == DATA_HARQ_INPUT)) { + if ((op_type == DATA_INPUT) && large_input) { + /* Allocate a fake overused mbuf */ + data = rte_malloc(NULL, data_len, 0); + AssertFatal(data != NULL, "rte malloc failed with %u bytes", data_len); + memcpy(data, &input[j * LDPC_MAX_CB_SIZE], data_len); + m_head->buf_addr = data; + m_head->buf_iova = rte_malloc_virt2iova(data); + m_head->data_off = 0; + m_head->data_len = data_len; + } else { + rte_pktmbuf_reset(m_head); + data = rte_pktmbuf_append(m_head, data_len); + AssertFatal(data != NULL, "Couldn't append %u bytes to mbuf from %d data type mbuf pool", data_len, op_type); + AssertFatal(data == RTE_PTR_ALIGN(data, min_alignment), + "Data addr in mbuf (%p) is not aligned to device min alignment (%u)", + data, + min_alignment); + rte_memcpy(data, &input[j * LDPC_MAX_CB_SIZE], data_len); + } + bufs[j].length += data_len; + } + ++j; + } + } + return 0; +} + +// based on DPDK BBDEV init_op_data_objs +static int init_op_data_objs_enc(struct rte_bbdev_op_data *bufs, + nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters, + struct rte_mbuf *m_head, + struct rte_mempool *mbuf_pool, + enum op_data_type op_type, + uint16_t min_alignment) +{ + bool large_input = false; + uint16_t j = 0; + for (uint16_t h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h) { + for (int i = 0; i < nrLDPC_slot_encoding_parameters->TBs[h].C; ++i) { + uint32_t data_len = (nrLDPC_slot_encoding_parameters->TBs[h].K - nrLDPC_slot_encoding_parameters->TBs[h].F + 7) / 8; + char *data; + struct rte_mbuf *m_head = rte_pktmbuf_alloc(mbuf_pool); + AssertFatal(m_head != NULL, + "Not enough mbufs in %d data type mbuf pool (needed %u, available %u)", + op_type, + nb_segments_encoding(nrLDPC_slot_encoding_parameters), + mbuf_pool->size); + + if (data_len > RTE_BBDEV_LDPC_E_MAX_MBUF) { + printf("Warning: Larger input size than DPDK mbuf %u\n", data_len); + large_input = true; + } + bufs[j].data = m_head; + bufs[j].offset = 0; + bufs[j].length = 0; + + if ((op_type == DATA_INPUT) || (op_type == DATA_HARQ_INPUT)) { + if ((op_type == DATA_INPUT) && large_input) { + /* Allocate a fake overused mbuf */ + data = rte_malloc(NULL, data_len, 0); + AssertFatal(data != NULL, "rte malloc failed with %u bytes", data_len); + memcpy(data, nrLDPC_slot_encoding_parameters->TBs[h].segments[i].c, data_len); + m_head->buf_addr = data; + m_head->buf_iova = rte_malloc_virt2iova(data); + m_head->data_off = 0; + m_head->data_len = data_len; + } else { + rte_pktmbuf_reset(m_head); + data = rte_pktmbuf_append(m_head, data_len); + AssertFatal(data != NULL, "Couldn't append %u bytes to mbuf from %d data type mbuf pool", data_len, op_type); + AssertFatal(data == RTE_PTR_ALIGN(data, min_alignment), + "Data addr in mbuf (%p) is not aligned to device min alignment (%u)", + data, + min_alignment); + rte_memcpy(data, nrLDPC_slot_encoding_parameters->TBs[h].segments[i].c, data_len); + } + bufs[j].length += data_len; + } + ++j; + } + } + return 0; +} + + +// DPDK BBEV copy +static int allocate_buffers_on_socket(struct rte_bbdev_op_data **buffers, const int len, const int socket) +{ + int i; + + *buffers = rte_zmalloc_socket(NULL, len, 0, socket); + if (*buffers == NULL) { + printf("WARNING: Failed to allocate op_data on socket %d\n", socket); + /* try to allocate memory on other detected sockets */ + for (i = 0; i < socket; i++) { + *buffers = rte_zmalloc_socket(NULL, len, 0, i); + if (*buffers != NULL) + break; + } + } + + return (*buffers == NULL) ? -1 : 0; +} + +// DPDK BBDEV copy +static void +free_buffers(struct active_device *ad, struct test_op_params *op_params) +{ + rte_mempool_free(ad->bbdev_dec_op_pool); + rte_mempool_free(ad->bbdev_enc_op_pool); + rte_mempool_free(ad->in_mbuf_pool); + rte_mempool_free(ad->hard_out_mbuf_pool); + rte_mempool_free(ad->soft_out_mbuf_pool); + rte_mempool_free(ad->harq_in_mbuf_pool); + rte_mempool_free(ad->harq_out_mbuf_pool); + + for (int i = 2; i < rte_lcore_count(); ++i) { + for (int j = 0; j < RTE_MAX_NUMA_NODES; ++j) { + rte_free(op_params->q_bufs[j][i].inputs); + rte_free(op_params->q_bufs[j][i].hard_outputs); + rte_free(op_params->q_bufs[j][i].soft_outputs); + rte_free(op_params->q_bufs[j][i].harq_inputs); + rte_free(op_params->q_bufs[j][i].harq_outputs); + } + } +} + +// based on DPDK BBDEV copy_reference_ldpc_dec_op +static void +set_ldpc_dec_op(struct rte_bbdev_dec_op **ops, + unsigned int start_idx, + struct data_buffers *bufs, + nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) +{ + unsigned int h; + unsigned int i; + unsigned int j = 0; + for (h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){ + for (i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) { + ops[j]->ldpc_dec.cb_params.e = nrLDPC_slot_decoding_parameters->TBs[h].segments[i].E; + ops[j]->ldpc_dec.basegraph = nrLDPC_slot_decoding_parameters->TBs[h].BG; + ops[j]->ldpc_dec.z_c = nrLDPC_slot_decoding_parameters->TBs[h].Z; + ops[j]->ldpc_dec.q_m = nrLDPC_slot_decoding_parameters->TBs[h].Qm; + ops[j]->ldpc_dec.n_filler = nrLDPC_slot_decoding_parameters->TBs[h].F; + ops[j]->ldpc_dec.n_cb = (nrLDPC_slot_decoding_parameters->TBs[h].BG == 1) ? (66 * nrLDPC_slot_decoding_parameters->TBs[h].Z) : (50 * nrLDPC_slot_decoding_parameters->TBs[h].Z); + ops[j]->ldpc_dec.iter_max = nrLDPC_slot_decoding_parameters->TBs[h].max_ldpc_iterations; + ops[j]->ldpc_dec.rv_index = nrLDPC_slot_decoding_parameters->TBs[h].rv_index; + ops[j]->ldpc_dec.op_flags = RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE | + RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_IN_ENABLE | + RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_OUT_ENABLE | + RTE_BBDEV_LDPC_HQ_COMBINE_OUT_ENABLE; + if (*nrLDPC_slot_decoding_parameters->TBs[h].segments[i].d_to_be_cleared) { + *nrLDPC_slot_decoding_parameters->TBs[h].segments[i].d_to_be_cleared = false; + *nrLDPC_slot_decoding_parameters->TBs[h].processedSegments = 0; + } else { + ops[j]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE; + } + if (nrLDPC_slot_decoding_parameters->TBs[h].C > 1) { + ops[j]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_CRC_TYPE_24B_DROP; + ops[j]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_CRC_TYPE_24B_CHECK; + } + ops[j]->ldpc_dec.code_block_mode = 1; + ops[j]->ldpc_dec.harq_combined_input.offset = (((nrLDPC_slot_decoding_parameters->TBs[h].harq_unique_pid * NR_LDPC_MAX_NUM_CB) % HARQ_CODEBLOCK_ID_MAX) + i) * LDPC_MAX_CB_SIZE; + ops[j]->ldpc_dec.harq_combined_output.offset = (((nrLDPC_slot_decoding_parameters->TBs[h].harq_unique_pid * NR_LDPC_MAX_NUM_CB) % HARQ_CODEBLOCK_ID_MAX) + i) * LDPC_MAX_CB_SIZE; + if (bufs->hard_outputs != NULL) + ops[j]->ldpc_dec.hard_output = bufs->hard_outputs[start_idx + j]; + if (bufs->inputs != NULL) + ops[j]->ldpc_dec.input = bufs->inputs[start_idx + j]; + if (bufs->soft_outputs != NULL) + ops[j]->ldpc_dec.soft_output = bufs->soft_outputs[start_idx + j]; + if (bufs->harq_inputs != NULL) + ops[j]->ldpc_dec.harq_combined_input = bufs->harq_inputs[start_idx + j]; + if (bufs->harq_outputs != NULL) + ops[j]->ldpc_dec.harq_combined_output = bufs->harq_outputs[start_idx + j]; + ++j; + } + } +} + +// based on DPDK BBDEV copy_reference_ldpc_enc_op +static void +set_ldpc_enc_op(struct rte_bbdev_enc_op **ops, + unsigned int start_idx, + struct rte_bbdev_op_data *inputs, + struct rte_bbdev_op_data *outputs, + nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) +{ + unsigned int h; + unsigned int i; + unsigned int j = 0; + for (h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h){ + for (i = 0; i < nrLDPC_slot_encoding_parameters->TBs[h].C; ++i) { + ops[j]->ldpc_enc.cb_params.e = nrLDPC_slot_encoding_parameters->TBs[h].segments[i].E; + ops[j]->ldpc_enc.basegraph = nrLDPC_slot_encoding_parameters->TBs[h].BG; + ops[j]->ldpc_enc.z_c = nrLDPC_slot_encoding_parameters->TBs[h].Z; + ops[j]->ldpc_enc.q_m = nrLDPC_slot_encoding_parameters->TBs[h].Qm; + ops[j]->ldpc_enc.n_filler = nrLDPC_slot_encoding_parameters->TBs[h].F; + ops[j]->ldpc_enc.n_cb = (nrLDPC_slot_encoding_parameters->TBs[h].BG == 1) ? (66 * nrLDPC_slot_encoding_parameters->TBs[h].Z) : (50 * nrLDPC_slot_encoding_parameters->TBs[h].Z); + if (nrLDPC_slot_encoding_parameters->TBs[h].tbslbrm != 0) { + uint32_t Nref = 3 * nrLDPC_slot_encoding_parameters->TBs[h].tbslbrm / (2 * nrLDPC_slot_encoding_parameters->TBs[h].C); + ops[j]->ldpc_enc.n_cb = min(ops[j]->ldpc_enc.n_cb, Nref); + } + ops[j]->ldpc_enc.rv_index = nrLDPC_slot_encoding_parameters->TBs[h].rv_index; + ops[j]->ldpc_enc.op_flags = RTE_BBDEV_LDPC_RATE_MATCH; + ops[j]->ldpc_enc.code_block_mode = 1; + ops[j]->ldpc_enc.output = outputs[start_idx + j]; + ops[j]->ldpc_enc.input = inputs[start_idx + j]; + ++j; + } + } +} + +static int +retrieve_ldpc_dec_op(struct rte_bbdev_dec_op **ops, + const int vector_mask, + nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) +{ + struct rte_bbdev_op_data *hard_output; + uint16_t data_len = 0; + struct rte_mbuf *m; + char *data; + unsigned int h; + unsigned int i; + unsigned int j = 0; + for (h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){ + for (i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) { + hard_output = &ops[j]->ldpc_dec.hard_output; + m = hard_output->data; + data_len = rte_pktmbuf_data_len(m) - hard_output->offset; + data = m->buf_addr; + memcpy(nrLDPC_slot_decoding_parameters->TBs[h].segments[i].c, data + m->data_off, data_len); + rte_pktmbuf_free(ops[j]->ldpc_dec.hard_output.data); + rte_pktmbuf_free(ops[j]->ldpc_dec.input.data); + ++j; + } + } + return 0; +} + +static int +retrieve_ldpc_enc_op(struct rte_bbdev_enc_op **ops, + nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) +{ + unsigned int j = 0; + for (unsigned int h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h){ + for (unsigned int i = 0; i < nrLDPC_slot_encoding_parameters->TBs[h].C; ++i) { + struct rte_bbdev_op_data *output = &ops[j]->ldpc_enc.output; + struct rte_mbuf *m = output->data; + uint16_t data_len = rte_pktmbuf_data_len(m) - output->offset; + uint8_t *out = nrLDPC_slot_encoding_parameters->TBs[h].segments[i].output; + const char *data = m->buf_addr + m->data_off; + const char *end = data + data_len; + while (data < end) { + uint8_t byte = *data++; // get the current byte + for (int bit = 7; bit >= 0; --bit) { + *out++ = (byte >> bit) & 1; // extract each bit + } + } + rte_pktmbuf_free(m); + rte_pktmbuf_free(ops[j]->ldpc_enc.input.data); + ++j; + } + } + return 0; +} + +// based on DPDK BBDEV init_test_op_params +static int init_test_op_params(struct test_op_params *op_params, + enum rte_bbdev_op_type op_type, + struct rte_mempool *ops_mp, + uint16_t burst_sz, + uint16_t num_to_process, + uint16_t num_lcores) +{ + int ret = 0; + if (op_type == RTE_BBDEV_OP_LDPC_DEC) { + ret = rte_bbdev_dec_op_alloc_bulk(ops_mp, &op_params->ref_dec_op, num_to_process); + op_params->mp_dec = ops_mp; + } else { + ret = rte_bbdev_enc_op_alloc_bulk(ops_mp, &op_params->ref_enc_op, 1); + op_params->mp_enc = ops_mp; + } + + AssertFatal(ret == 0, "rte_bbdev_op_alloc_bulk() failed"); + + op_params->burst_sz = burst_sz; + op_params->num_to_process = num_to_process; + op_params->num_lcores = num_lcores; + return 0; +} + +// based on DPDK BBDEV throughput_pmd_lcore_ldpc_dec +static int +pmd_lcore_ldpc_dec(void *arg) +{ + struct thread_params *tp = arg; + nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters = tp->nrLDPC_slot_decoding_parameters; + uint16_t enq, deq; + int time_out = 0; + const uint16_t queue_id = tp->queue_id; + const uint16_t num_segments = nb_segments_decoding(nrLDPC_slot_decoding_parameters); + struct rte_bbdev_dec_op **ops_enq; + struct rte_bbdev_dec_op **ops_deq; + ops_enq = (struct rte_bbdev_dec_op **)rte_calloc("struct rte_bbdev_dec_op **ops_enq", num_segments, sizeof(struct rte_bbdev_dec_op *), RTE_CACHE_LINE_SIZE); + ops_deq = (struct rte_bbdev_dec_op **)rte_calloc("struct rte_bbdev_dec_op **ops_dec", num_segments, sizeof(struct rte_bbdev_dec_op *), RTE_CACHE_LINE_SIZE); + struct data_buffers *bufs = NULL; + uint16_t h, i, j; + int ret; + struct rte_bbdev_info info; + uint16_t num_to_enq; + + AssertFatal((num_segments < MAX_BURST), "BURST_SIZE should be <= %u", MAX_BURST); + rte_bbdev_info_get(tp->dev_id, &info); + + bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id]; + while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT) + rte_pause(); + + ret = rte_bbdev_dec_op_alloc_bulk(tp->op_params->mp_dec, ops_enq, num_segments); + AssertFatal(ret == 0, "Allocation failed for %d ops", num_segments); + set_ldpc_dec_op(ops_enq, 0, bufs, nrLDPC_slot_decoding_parameters); + + for (enq = 0, deq = 0; enq < num_segments;) { + num_to_enq = num_segments; + if (unlikely(num_segments - enq < num_to_enq)) + num_to_enq = num_segments - enq; + + enq += rte_bbdev_enqueue_ldpc_dec_ops(tp->dev_id, queue_id, &ops_enq[enq], num_to_enq); + deq += rte_bbdev_dequeue_ldpc_dec_ops(tp->dev_id, queue_id, &ops_deq[deq], enq - deq); + } + + /* dequeue the remaining */ + while (deq < enq) { + deq += rte_bbdev_dequeue_ldpc_dec_ops(tp->dev_id, queue_id, &ops_deq[deq], enq - deq); + time_out++; + DevAssert(time_out <= TIME_OUT_POLL); + } + if (deq == enq) { + ret = retrieve_ldpc_dec_op(ops_deq, tp->op_params->vector_mask, nrLDPC_slot_decoding_parameters); + AssertFatal(ret == 0, "LDPC offload decoder failed!"); + tp->iter_count = 0; + /* get the max of iter_count for all dequeued ops */ + j = 0; + for (h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){ + for (i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) { + bool *status = &nrLDPC_slot_decoding_parameters->TBs[h].segments[i].decodeSuccess; + tp->iter_count = RTE_MAX(ops_enq[j]->ldpc_dec.iter_count, tp->iter_count); + + // Check if CRC is available otherwise rely on ops_enq[j]->status to detect decoding success + // CRC is NOT available if the CRC type is 24_B which is when C is greater than 1 + + if (nrLDPC_slot_decoding_parameters->TBs[h].C > 1) { + + *status = (ops_enq[j]->status == 0); + + } else { + + uint8_t *decoded_bytes = nrLDPC_slot_decoding_parameters->TBs[h].segments[i].c; + uint8_t crc_type = crcType(nrLDPC_slot_decoding_parameters->TBs[h].C, nrLDPC_slot_decoding_parameters->TBs[h].A); + uint32_t len_with_crc = lenWithCrc(nrLDPC_slot_decoding_parameters->TBs[h].C, nrLDPC_slot_decoding_parameters->TBs[h].A); + *status = check_crc(decoded_bytes, len_with_crc, crc_type); + + } + + if (*status) { + *nrLDPC_slot_decoding_parameters->TBs[h].processedSegments = *nrLDPC_slot_decoding_parameters->TBs[h].processedSegments + 1; + } + + ++j; + } + } + } + + rte_bbdev_dec_op_free_bulk(ops_enq, num_segments); + rte_free(ops_enq); + rte_free(ops_deq); + // Return the worst decoding number of iterations for all segments + return tp->iter_count; +} + +// based on DPDK BBDEV throughput_pmd_lcore_ldpc_enc +static int pmd_lcore_ldpc_enc(void *arg) +{ + struct thread_params *tp = arg; + nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters = tp->nrLDPC_slot_encoding_parameters; + uint16_t enq, deq; + int time_out = 0; + const uint16_t queue_id = tp->queue_id; + const uint16_t num_segments = nb_segments_encoding(nrLDPC_slot_encoding_parameters); + struct rte_bbdev_enc_op **ops_enq; + struct rte_bbdev_enc_op **ops_deq; + ops_enq = (struct rte_bbdev_enc_op **)rte_calloc("struct rte_bbdev_dec_op **ops_enq", num_segments, sizeof(struct rte_bbdev_enc_op *), RTE_CACHE_LINE_SIZE); + ops_deq = (struct rte_bbdev_enc_op **)rte_calloc("struct rte_bbdev_dec_op **ops_dec", num_segments, sizeof(struct rte_bbdev_enc_op *), RTE_CACHE_LINE_SIZE); + struct rte_bbdev_info info; + int ret; + struct data_buffers *bufs = NULL; + uint16_t num_to_enq; + + AssertFatal((num_segments < MAX_BURST), "BURST_SIZE should be <= %u", MAX_BURST); + + rte_bbdev_info_get(tp->dev_id, &info); + bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id]; + while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT) + rte_pause(); + ret = rte_bbdev_enc_op_alloc_bulk(tp->op_params->mp_enc, ops_enq, num_segments); + AssertFatal(ret == 0, "Allocation failed for %d ops", num_segments); + + set_ldpc_enc_op(ops_enq, 0, bufs->inputs, bufs->hard_outputs, nrLDPC_slot_encoding_parameters); + for (enq = 0, deq = 0; enq < num_segments;) { + num_to_enq = num_segments; + if (unlikely(num_segments - enq < num_to_enq)) + num_to_enq = num_segments - enq; + enq += rte_bbdev_enqueue_ldpc_enc_ops(tp->dev_id, queue_id, &ops_enq[enq], num_to_enq); + deq += rte_bbdev_dequeue_ldpc_enc_ops(tp->dev_id, queue_id, &ops_deq[deq], enq - deq); + } + /* dequeue the remaining */ + while (deq < enq) { + deq += rte_bbdev_dequeue_ldpc_enc_ops(tp->dev_id, queue_id, &ops_deq[deq], enq - deq); + time_out++; + DevAssert(time_out <= TIME_OUT_POLL); + } + + ret = retrieve_ldpc_enc_op(ops_deq, nrLDPC_slot_encoding_parameters); + AssertFatal(ret == 0, "Failed to retrieve LDPC encoding op!"); + + rte_bbdev_enc_op_free_bulk(ops_enq, num_segments); + rte_free(ops_enq); + rte_free(ops_deq); + return ret; +} + +// based on DPDK BBDEV throughput_pmd_lcore_dec +int start_pmd_dec(struct active_device *ad, + struct test_op_params *op_params, + nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) +{ + int ret; + unsigned int lcore_id, used_cores = 0; + uint16_t num_lcores; + /* Set number of lcores */ + num_lcores = (ad->nb_queues < (op_params->num_lcores)) ? ad->nb_queues : op_params->num_lcores; + /* Allocate memory for thread parameters structure */ + struct thread_params *t_params = rte_zmalloc(NULL, num_lcores * sizeof(struct thread_params), RTE_CACHE_LINE_SIZE); + AssertFatal(t_params != 0, + "Failed to alloc %zuB for t_params", + RTE_ALIGN(sizeof(struct thread_params) * num_lcores, RTE_CACHE_LINE_SIZE)); + rte_atomic16_set(&op_params->sync, SYNC_WAIT); + /* Master core is set at first entry */ + t_params[0].dev_id = ad->dev_id; + t_params[0].lcore_id = rte_lcore_id(); + t_params[0].op_params = op_params; + t_params[0].queue_id = ad->dec_queue; + t_params[0].iter_count = 0; + t_params[0].nrLDPC_slot_decoding_parameters = nrLDPC_slot_decoding_parameters; + used_cores++; + // For now, we never enter here, we don't use the DPDK thread pool + RTE_LCORE_FOREACH_WORKER(lcore_id) { + if (used_cores >= num_lcores) + break; + t_params[used_cores].dev_id = ad->dev_id; + t_params[used_cores].lcore_id = lcore_id; + t_params[used_cores].op_params = op_params; + t_params[used_cores].queue_id = ad->queue_ids[used_cores]; + t_params[used_cores].iter_count = 0; + t_params[used_cores].nrLDPC_slot_decoding_parameters = nrLDPC_slot_decoding_parameters; + rte_eal_remote_launch(pmd_lcore_ldpc_dec, &t_params[used_cores++], lcore_id); + } + rte_atomic16_set(&op_params->sync, SYNC_START); + ret = pmd_lcore_ldpc_dec(&t_params[0]); + /* Master core is always used */ + // for (used_cores = 1; used_cores < num_lcores; used_cores++) + // ret |= rte_eal_wait_lcore(t_params[used_cores].lcore_id); + rte_free(t_params); + return ret; +} + +// based on DPDK BBDEV throughput_pmd_lcore_enc +int32_t start_pmd_enc(struct active_device *ad, + struct test_op_params *op_params, + nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) +{ + unsigned int lcore_id, used_cores = 0; + uint16_t num_lcores; + int ret; + num_lcores = (ad->nb_queues < (op_params->num_lcores)) ? ad->nb_queues : op_params->num_lcores; + struct thread_params *t_params = rte_zmalloc(NULL, num_lcores * sizeof(struct thread_params), RTE_CACHE_LINE_SIZE); + rte_atomic16_set(&op_params->sync, SYNC_WAIT); + t_params[0].dev_id = ad->dev_id; + t_params[0].lcore_id = rte_lcore_id() + 1; + t_params[0].op_params = op_params; + t_params[0].queue_id = ad->enc_queue; + t_params[0].iter_count = 0; + t_params[0].nrLDPC_slot_encoding_parameters = nrLDPC_slot_encoding_parameters; + used_cores++; + // For now, we never enter here, we don't use the DPDK thread pool + RTE_LCORE_FOREACH_WORKER(lcore_id) { + if (used_cores >= num_lcores) + break; + t_params[used_cores].dev_id = ad->dev_id; + t_params[used_cores].lcore_id = lcore_id; + t_params[used_cores].op_params = op_params; + t_params[used_cores].queue_id = ad->queue_ids[1]; + t_params[used_cores].iter_count = 0; + t_params[used_cores].nrLDPC_slot_encoding_parameters = nrLDPC_slot_encoding_parameters; + rte_eal_remote_launch(pmd_lcore_ldpc_enc, &t_params[used_cores++], lcore_id); + } + rte_atomic16_set(&op_params->sync, SYNC_START); + ret = pmd_lcore_ldpc_enc(&t_params[0]); + rte_free(t_params); + return ret; +} + +struct test_op_params *op_params = NULL; + +struct rte_mbuf *m_head[DATA_NUM_TYPES]; + +// OAI CODE +int32_t nrLDPC_coding_init() +{ + pthread_mutex_init(&encode_mutex, NULL); + pthread_mutex_init(&decode_mutex, NULL); + int ret; + int dev_id = 0; + struct rte_bbdev_info info; + struct active_device *ad = active_devs; + char *dpdk_dev = NULL; //PCI address of the card + char *dpdk_core_list = NULL; // cores used by DPDK for T2 + char *dpdk_file_prefix = NULL; + paramdef_t LoaderParams[] = { + {"dpdk_dev", NULL, 0, .strptr = &dpdk_dev, .defstrval = NULL, TYPE_STRING, 0, NULL}, + {"dpdk_core_list", NULL, 0, .strptr = &dpdk_core_list, .defstrval = NULL, TYPE_STRING, 0, NULL}, + {"dpdk_file_prefix", NULL, 0, .strptr = &dpdk_file_prefix, .defstrval = "b6", TYPE_STRING, 0, NULL} + }; + config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "nrLDPC_coding_t2"); + AssertFatal(dpdk_dev!=NULL, "nrLDPC_coding_t2.dpdk_dev was not provided"); + AssertFatal(dpdk_core_list!=NULL, "nrLDPC_coding_t2.dpdk_core_list was not provided"); + char *argv_re[] = {"bbdev", "-a", dpdk_dev, "-l", dpdk_core_list, "--file-prefix", dpdk_file_prefix, "--"}; + // EAL initialization, if already initialized (init in xran lib) try to probe DPDK device + ret = rte_eal_init(sizeofArray(argv_re), argv_re); + if (ret < 0) { + printf("EAL initialization failed, probing DPDK device %s\n", dpdk_dev); + if (rte_dev_probe(dpdk_dev) != 0) { + LOG_E(PHY, "T2 card %s not found\n", dpdk_dev); + return (-1); + } + } + // Use only device 0 - first detected device + rte_bbdev_info_get(0, &info); + // Set number of queues based on number of initialized cores (-l option) and driver + // capabilities + AssertFatal(add_dev(dev_id, &info)== 0, "Failed to setup bbdev"); + AssertFatal(rte_bbdev_stats_reset(dev_id) == 0, "Failed to reset stats of bbdev %u", dev_id); + AssertFatal(rte_bbdev_start(dev_id) == 0, "Failed to start bbdev %u", dev_id); + + //the previous calls have populated this global variable (beurk) + // One more global to remove, not thread safe global op_params + op_params = rte_zmalloc(NULL, sizeof(struct test_op_params), RTE_CACHE_LINE_SIZE); + AssertFatal(op_params != NULL, + "Failed to alloc %zuB for op_params", + RTE_ALIGN(sizeof(struct test_op_params), RTE_CACHE_LINE_SIZE)); + + int socket_id = GET_SOCKET(info.socket_id); + int out_max_sz = 8448; // max code block size (for BG1), 22 * 384 + int in_max_sz = LDPC_MAX_CB_SIZE; // max number of encoded bits (for BG2 and MCS0) + int num_queues = 1; + int f_ret = create_mempools(ad, socket_id, num_queues, out_max_sz, in_max_sz); + if (f_ret != 0) { + printf("Couldn't create mempools"); + return -1; + } + f_ret = init_test_op_params(op_params, RTE_BBDEV_OP_LDPC_DEC, ad->bbdev_dec_op_pool, num_queues, num_queues, 1); + f_ret = init_test_op_params(op_params, RTE_BBDEV_OP_LDPC_ENC, ad->bbdev_enc_op_pool, num_queues, num_queues, 1); + if (f_ret != 0) { + printf("Couldn't init test op params"); + return -1; + } + return 0; +} + +int32_t nrLDPC_coding_shutdown() +{ + struct active_device *ad = active_devs; + int dev_id = 0; + struct rte_bbdev_stats stats; + free_buffers(ad, op_params); + rte_free(op_params); + rte_bbdev_stats_get(dev_id, &stats); + rte_bbdev_stop(dev_id); + rte_bbdev_close(dev_id); + memset(active_devs, 0, sizeof(active_devs)); + nb_active_devs = 0; + return 0; +} + +int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters){ + + pthread_mutex_lock(&decode_mutex); + + uint16_t num_blocks = 0; + for(uint16_t h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){ + num_blocks += nrLDPC_slot_decoding_parameters->TBs[h].C; + } + uint16_t z_ol[LDPC_MAX_CB_SIZE] __attribute__((aligned(16))); + /* It is not unlikely that l_ol becomes big enough to overflow the stack + * If you observe this behavior then move it to the heap + * Then you would better do a persistent allocation to limit the overhead + */ + uint8_t l_ol[num_blocks * LDPC_MAX_CB_SIZE] __attribute__((aligned(16))); + + // hardcoded we use first device + struct active_device *ad = active_devs; + struct rte_bbdev_info info; + int ret; + rte_bbdev_info_get(ad->dev_id, &info); + int socket_id = GET_SOCKET(info.socket_id); + // fill_queue_buffers -> init_op_data_objs + struct rte_mempool *in_mp = ad->in_mbuf_pool; + struct rte_mempool *hard_out_mp = ad->hard_out_mbuf_pool; + struct rte_mempool *soft_out_mp = ad->soft_out_mbuf_pool; + struct rte_mempool *harq_in_mp = ad->harq_in_mbuf_pool; + struct rte_mempool *harq_out_mp = ad->harq_out_mbuf_pool; + struct rte_mempool *mbuf_pools[DATA_NUM_TYPES] = {in_mp, soft_out_mp, hard_out_mp, harq_in_mp, harq_out_mp}; + uint8_t queue_id = ad->dec_queue; + struct rte_bbdev_op_data **queue_ops[DATA_NUM_TYPES] = {&op_params->q_bufs[socket_id][queue_id].inputs, + &op_params->q_bufs[socket_id][queue_id].soft_outputs, + &op_params->q_bufs[socket_id][queue_id].hard_outputs, + &op_params->q_bufs[socket_id][queue_id].harq_inputs, + &op_params->q_bufs[socket_id][queue_id].harq_outputs}; + + int offset = 0; + for(uint16_t h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){ + for (int r = 0; r < nrLDPC_slot_decoding_parameters->TBs[h].C; r++) { + memcpy(z_ol, nrLDPC_slot_decoding_parameters->TBs[h].segments[r].llr, nrLDPC_slot_decoding_parameters->TBs[h].segments[r].E * sizeof(uint16_t)); + simde__m128i *pv_ol128 = (simde__m128i *)z_ol; + simde__m128i *pl_ol128 = (simde__m128i *)&l_ol[offset]; + int kc = nrLDPC_slot_decoding_parameters->TBs[h].BG == 2 ? 52 : 68; + for (int i = 0, j = 0; j < ((kc * nrLDPC_slot_decoding_parameters->TBs[h].Z) >> 4) + 1; i += 2, j++) { + pl_ol128[j] = simde_mm_packs_epi16(pv_ol128[i], pv_ol128[i + 1]); + } + offset += LDPC_MAX_CB_SIZE; + } + } + + for (enum op_data_type type = DATA_INPUT; type < 3; type += 2) { + ret = allocate_buffers_on_socket(queue_ops[type], num_blocks * sizeof(struct rte_bbdev_op_data), socket_id); + AssertFatal(ret == 0, "Couldn't allocate memory for rte_bbdev_op_data structs"); + ret = init_op_data_objs_dec(*queue_ops[type], + l_ol, + nrLDPC_slot_decoding_parameters, + mbuf_pools[type], + type, + info.drv.min_alignment); + AssertFatal(ret == 0, "Couldn't init rte_bbdev_op_data structs"); + } + + ret = start_pmd_dec(ad, op_params, nrLDPC_slot_decoding_parameters); + if (ret < 0) { + LOG_E(PHY, "Couldn't start pmd dec\n"); + } + + pthread_mutex_unlock(&decode_mutex); + return 0; +} + +int32_t nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) +{ + pthread_mutex_lock(&encode_mutex); + // hardcoded to use the first found board + struct active_device *ad = active_devs; + int ret; + struct rte_bbdev_info info; + rte_bbdev_info_get(ad->dev_id, &info); + int socket_id = GET_SOCKET(info.socket_id); + // fill_queue_buffers -> init_op_data_objs + struct rte_mempool *in_mp = ad->in_mbuf_pool; + struct rte_mempool *hard_out_mp = ad->hard_out_mbuf_pool; + struct rte_mempool *soft_out_mp = ad->soft_out_mbuf_pool; + struct rte_mempool *harq_in_mp = ad->harq_in_mbuf_pool; + struct rte_mempool *harq_out_mp = ad->harq_out_mbuf_pool; + struct rte_mempool *mbuf_pools[DATA_NUM_TYPES] = {in_mp, soft_out_mp, hard_out_mp, harq_in_mp, harq_out_mp}; + uint8_t queue_id = ad->enc_queue; + struct rte_bbdev_op_data **queue_ops[DATA_NUM_TYPES] = {&op_params->q_bufs[socket_id][queue_id].inputs, + &op_params->q_bufs[socket_id][queue_id].soft_outputs, + &op_params->q_bufs[socket_id][queue_id].hard_outputs, + &op_params->q_bufs[socket_id][queue_id].harq_inputs, + &op_params->q_bufs[socket_id][queue_id].harq_outputs}; + uint16_t num_blocks = 0; + for(uint16_t h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h){ + num_blocks += nrLDPC_slot_encoding_parameters->TBs[h].C; + } + for (enum op_data_type type = DATA_INPUT; type < 3; type += 2) { + ret = allocate_buffers_on_socket(queue_ops[type], num_blocks * sizeof(struct rte_bbdev_op_data), socket_id); + AssertFatal(ret == 0, "Couldn't allocate memory for rte_bbdev_op_data structs"); + ret = init_op_data_objs_enc(*queue_ops[type], + nrLDPC_slot_encoding_parameters, + m_head[type], + mbuf_pools[type], + type, + info.drv.min_alignment); + AssertFatal(ret == 0, "Couldn't init rte_bbdev_op_data structs"); + } + ret = start_pmd_enc(ad, op_params, nrLDPC_slot_encoding_parameters); + pthread_mutex_unlock(&encode_mutex); + return ret; +} + diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_offload.h b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.h similarity index 100% rename from openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_offload.h rename to openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.h diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h index f8d31c8fcd..053f7ebf16 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h @@ -106,23 +106,6 @@ typedef struct nrLDPC_dec_params { nrLDPC_params_per_cb_t perCB[NR_LDPC_MAX_NUM_CB]; } t_nrLDPC_dec_params; -/** - Structure containing LDPC offload parameters. - */ -typedef struct nrLDPCoffload_params { - uint8_t BG; /**< Base graph */ - uint16_t Z; - uint16_t Kr; - uint8_t rv; - uint16_t n_cb; - uint16_t F; /**< Filler bits */ - uint8_t Qm; /**< Modulation */ - uint8_t C; - uint8_t numMaxIter; - uint8_t setCombIn; - nrLDPC_params_per_cb_t perCB[NR_LDPC_MAX_NUM_CB]; -} t_nrLDPCoffload_params; - /** Structure containing LDPC decoder processing time statistics. */ From 73770da52cd2b2e4d36e217ca9a0a37da7d5bccf Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Fri, 8 Nov 2024 15:22:19 +0100 Subject: [PATCH 43/83] fix(nrLDPC_coding_t2): remove legacy T2 coding and rename libldpc_slot_t2.so in libldpc_t2.so --- CMakeLists.txt | 17 +- .../nrLDPC_decoder/nrLDPC_decoder_offload.c | 1041 ----------------- 2 files changed, 7 insertions(+), 1051 deletions(-) delete mode 100644 openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 45e5ba97dc..44a2d0d487 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -498,15 +498,12 @@ if (ENABLE_LDPC_T2) message(FATAL_ERROR "could not find poll-mode driver for AccelerComm T2 LDPC Offload (rte_baseband_accl_ldpc.so)") endif() message(STATUS "T2 build: use ${PMD_T2}") - add_library(ldpc_t2 MODULE ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c) - set_target_properties(ldpc_t2 PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API") - target_link_libraries(ldpc_t2 ${LIBDPDK_T2_LDFLAGS} ${PMD_T2}) set(PHY_NRLDPC_CODING_T2_SRC ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c ) - add_library(ldpc_slot_t2 MODULE ${PHY_NRLDPC_CODING_T2_SRC}) - set_target_properties(ldpc_slot_t2 PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API") - target_link_libraries(ldpc_slot_t2 PRIVATE ldpc_gen_HEADERS ${LIBDPDK_T2_LDFLAGS} ${PMD_T2}) + add_library(ldpc_t2 MODULE ${PHY_NRLDPC_CODING_T2_SRC}) + set_target_properties(ldpc_t2 PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API") + target_link_libraries(ldpc_t2 PRIVATE ldpc_gen_HEADERS ${LIBDPDK_T2_LDFLAGS} ${PMD_T2}) endif() ########################################################## @@ -2065,7 +2062,7 @@ endif() add_dependencies(nr-softmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc ldpc_slot_segment) if (ENABLE_LDPC_T2) - add_dependencies(nr-softmodem ldpc_t2 ldpc_slot_t2) + add_dependencies(nr-softmodem ldpc_t2) endif() # force the generation of ASN.1 so that we don't need to wait during the build @@ -2126,7 +2123,7 @@ if (ENABLE_LDPC_CUDA) endif() if (ENABLE_LDPC_T2) - add_dependencies(nr-uesoftmodem ldpc_t2 ldpc_slot_t2) + add_dependencies(nr-uesoftmodem ldpc_t2) endif() # force the generation of ASN.1 so that we don't need to wait during the build @@ -2284,7 +2281,7 @@ add_executable(nr_ulsim ) if (ENABLE_LDPC_T2) - add_dependencies(nr_ulsim ldpc_t2 ldpc_slot_t2) + add_dependencies(nr_ulsim ldpc_t2) endif() add_dependencies(nr_ulsim ldpc_slot_segment) @@ -2353,7 +2350,7 @@ if (${T_TRACER}) PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU PHY_MEX L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE L2_UE_LTE_NR MAC_NR_COMMON MAC_UE_NR ngap CN_UTILS GTPV1U SCTP_CLIENT MME_APP LIB_NAS_UE NB_IoT SIMU OPENAIR0_LIB - ldpc_orig ldpc_optim ldpc_optim8seg ldpc_t2 ldpc_cl ldpc_cuda ldpc ldpc_slot_segment ldpc_slot_t2 + ldpc_orig ldpc_optim ldpc_optim8seg ldpc_cl ldpc_cuda ldpc ldpc_slot_segment ldpc_t2 dfts config_internals nr_common) if (TARGET ${i}) add_dependencies(${i} generate_T) diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c deleted file mode 100644 index fd222f40b4..0000000000 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c +++ /dev/null @@ -1,1041 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2017 Intel Corporation - */ - -/*!\file nrLDPC_decoder_offload.c - * \note: based on testbbdev test_bbdev_perf.c functions. Harq buffer offset added. - * \mbuf and mempool allocated at the init step, LDPC parameters updated from OAI. - */ - -#include -#include "PHY/sse_intrin.h" -#include "nrLDPCdecoder_defs.h" -#include "nrLDPC_types.h" -#include "nrLDPC_init.h" -#include "nrLDPC_mPass.h" -#include "nrLDPC_cnProc.h" -#include "nrLDPC_bnProc.h" -#include -#define NR_LDPC_ENABLE_PARITY_CHECK - -#ifdef NR_LDPC_DEBUG_MODE -#include "nrLDPC_tools/nrLDPC_debug.h" -#endif - -#include "openair1/PHY/CODING/nrLDPC_extern.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include "nrLDPC_offload.h" - -#include - -#include -#include -#include -#include -#include -#include -#include - -// this socket is the NUMA socket, so the hardware CPU id (numa is complex) -#define GET_SOCKET(socket_id) (((socket_id) == SOCKET_ID_ANY) ? 0 : (socket_id)) -#define MAX_QUEUES 32 -#define OPS_CACHE_SIZE 256U -#define OPS_POOL_SIZE_MIN 511U /* 0.5K per queue */ -#define SYNC_WAIT 0 -#define SYNC_START 1 -#define TIME_OUT_POLL 1e8 -/* Increment for next code block in external HARQ memory */ -#define HARQ_INCR 32768 -/* Headroom for filler LLRs insertion in HARQ buffer */ -#define FILLER_HEADROOM 1024 - -pthread_mutex_t encode_mutex; -pthread_mutex_t decode_mutex; - -const char *typeStr[] = { - "RTE_BBDEV_OP_NONE", /**< Dummy operation that does nothing */ - "RTE_BBDEV_OP_TURBO_DEC", /**< Turbo decode */ - "RTE_BBDEV_OP_TURBO_ENC", /**< Turbo encode */ - "RTE_BBDEV_OP_LDPC_DEC", /**< LDPC decode */ - "RTE_BBDEV_OP_LDPC_ENC", /**< LDPC encode */ - "RTE_BBDEV_OP_TYPE_COUNT", /**< Count of different op types */ -}; - -/* Represents tested active devices */ -struct active_device { - const char *driver_name; - uint8_t dev_id; - int dec_queue; - int enc_queue; - uint16_t queue_ids[MAX_QUEUES]; - uint16_t nb_queues; - struct rte_mempool *bbdev_dec_op_pool; - struct rte_mempool *bbdev_enc_op_pool; - struct rte_mempool *in_mbuf_pool; - struct rte_mempool *hard_out_mbuf_pool; - struct rte_mempool *soft_out_mbuf_pool; - struct rte_mempool *harq_in_mbuf_pool; - struct rte_mempool *harq_out_mbuf_pool; -} active_devs[RTE_BBDEV_MAX_DEVS]; -static int nb_active_devs; - -/* Data buffers used by BBDEV ops */ -struct data_buffers { - struct rte_bbdev_op_data *inputs; - struct rte_bbdev_op_data *hard_outputs; - struct rte_bbdev_op_data *soft_outputs; - struct rte_bbdev_op_data *harq_inputs; - struct rte_bbdev_op_data *harq_outputs; -}; - -/* Operation parameters specific for given test case */ -struct test_op_params { - struct rte_mempool *mp_dec; - struct rte_mempool *mp_enc; - struct rte_bbdev_dec_op *ref_dec_op; - struct rte_bbdev_enc_op *ref_enc_op; - uint16_t burst_sz; - uint16_t num_to_process; - uint16_t num_lcores; - int vector_mask; - rte_atomic16_t sync; - struct data_buffers q_bufs[RTE_MAX_NUMA_NODES][MAX_QUEUES]; -}; - -/* Contains per lcore params */ -struct thread_params { - uint8_t dev_id; - uint16_t queue_id; - uint32_t lcore_id; - struct nrLDPCoffload_params *p_offloadParams; - uint8_t iter_count; - uint8_t *p_out; - uint8_t ulsch_id; - rte_atomic16_t nb_dequeued; - rte_atomic16_t processing_status; - rte_atomic16_t burst_sz; - struct test_op_params *op_params; - struct rte_bbdev_dec_op *dec_ops[MAX_BURST]; - struct rte_bbdev_enc_op *enc_ops[MAX_BURST]; -}; - -// DPDK BBDEV copy -static inline void -mbuf_reset(struct rte_mbuf *m) -{ - m->pkt_len = 0; - - do { - m->data_len = 0; - m = m->next; - } while (m != NULL); -} - -/* Read flag value 0/1 from bitmap */ -// DPDK BBDEV copy -static inline bool -check_bit(uint32_t bitmap, uint32_t bitmask) -{ - return bitmap & bitmask; -} - -/* calculates optimal mempool size not smaller than the val */ -// DPDK BBDEV copy -static unsigned int -optimal_mempool_size(unsigned int val) -{ - return rte_align32pow2(val + 1) - 1; -} - -// based on DPDK BBDEV create_mempools -static int create_mempools(struct active_device *ad, int socket_id, uint16_t num_ops, int out_buff_sz, int in_max_sz) -{ - unsigned int ops_pool_size, mbuf_pool_size, data_room_size = 0; - num_ops = 1; - uint8_t nb_segments = 1; - ops_pool_size = optimal_mempool_size(RTE_MAX( - /* Ops used plus 1 reference op */ - RTE_MAX((unsigned int)(ad->nb_queues * num_ops + 1), - /* Minimal cache size plus 1 reference op */ - (unsigned int)(1.5 * rte_lcore_count() * OPS_CACHE_SIZE + 1)), - OPS_POOL_SIZE_MIN)); - - /* Decoder ops mempool */ - ad->bbdev_dec_op_pool = rte_bbdev_op_pool_create("bbdev_op_pool_dec", RTE_BBDEV_OP_LDPC_DEC, - /* Encoder ops mempool */ ops_pool_size, OPS_CACHE_SIZE, socket_id); - ad->bbdev_enc_op_pool = rte_bbdev_op_pool_create("bbdev_op_pool_enc", RTE_BBDEV_OP_LDPC_ENC, - ops_pool_size, OPS_CACHE_SIZE, socket_id); - - if ((ad->bbdev_dec_op_pool == NULL) || (ad->bbdev_enc_op_pool == NULL)) - AssertFatal(1 == 0, "ERROR Failed to create %u items ops pool for dev %u on socket %d.", ops_pool_size, ad->dev_id, socket_id); - - /* Inputs */ - mbuf_pool_size = optimal_mempool_size(ops_pool_size * nb_segments); - data_room_size = RTE_MAX(in_max_sz + RTE_PKTMBUF_HEADROOM + FILLER_HEADROOM, (unsigned int)RTE_MBUF_DEFAULT_BUF_SIZE); - ad->in_mbuf_pool = rte_pktmbuf_pool_create("in_mbuf_pool", mbuf_pool_size, 0, 0, data_room_size, socket_id); - AssertFatal(ad->in_mbuf_pool != NULL, - "ERROR Failed to create %u items input pktmbuf pool for dev %u on socket %d.", - mbuf_pool_size, - ad->dev_id, - socket_id); - - /* Hard outputs */ - data_room_size = RTE_MAX(out_buff_sz + RTE_PKTMBUF_HEADROOM + FILLER_HEADROOM, (unsigned int)RTE_MBUF_DEFAULT_BUF_SIZE); - ad->hard_out_mbuf_pool = rte_pktmbuf_pool_create("hard_out_mbuf_pool", mbuf_pool_size, 0, 0, data_room_size, socket_id); - AssertFatal(ad->hard_out_mbuf_pool != NULL, - "ERROR Failed to create %u items hard output pktmbuf pool for dev %u on socket %d.", - mbuf_pool_size, - ad->dev_id, - socket_id); - return 0; -} - -const char *ldpcenc_flag_bitmask[] = { - /** Set for bit-level interleaver bypass on output stream. */ - "RTE_BBDEV_LDPC_INTERLEAVER_BYPASS", - /** If rate matching is to be performed */ - "RTE_BBDEV_LDPC_RATE_MATCH", - /** Set for transport block CRC-24A attach */ - "RTE_BBDEV_LDPC_CRC_24A_ATTACH", - /** Set for code block CRC-24B attach */ - "RTE_BBDEV_LDPC_CRC_24B_ATTACH", - /** Set for code block CRC-16 attach */ - "RTE_BBDEV_LDPC_CRC_16_ATTACH", - /** Set if a device supports encoder dequeue interrupts. */ - "RTE_BBDEV_LDPC_ENC_INTERRUPTS", - /** Set if a device supports scatter-gather functionality. */ - "RTE_BBDEV_LDPC_ENC_SCATTER_GATHER", - /** Set if a device supports concatenation of non byte aligned output */ - "RTE_BBDEV_LDPC_ENC_CONCATENATION", -}; - -const char *ldpcdec_flag_bitmask[] = { - /** Set for transport block CRC-24A checking */ - "RTE_BBDEV_LDPC_CRC_TYPE_24A_CHECK", - /** Set for code block CRC-24B checking */ - "RTE_BBDEV_LDPC_CRC_TYPE_24B_CHECK", - /** Set to drop the last CRC bits decoding output */ - "RTE_BBDEV_LDPC_CRC_TYPE_24B_DROP" - /** Set for bit-level de-interleaver bypass on Rx stream. */ - "RTE_BBDEV_LDPC_DEINTERLEAVER_BYPASS", - /** Set for HARQ combined input stream enable. */ - "RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE", - /** Set for HARQ combined output stream enable. */ - "RTE_BBDEV_LDPC_HQ_COMBINE_OUT_ENABLE", - /** Set for LDPC decoder bypass. - * RTE_BBDEV_LDPC_HQ_COMBINE_OUT_ENABLE must be set. - */ - "RTE_BBDEV_LDPC_DECODE_BYPASS", - /** Set for soft-output stream enable */ - "RTE_BBDEV_LDPC_SOFT_OUT_ENABLE", - /** Set for Rate-Matching bypass on soft-out stream. */ - "RTE_BBDEV_LDPC_SOFT_OUT_RM_BYPASS", - /** Set for bit-level de-interleaver bypass on soft-output stream. */ - "RTE_BBDEV_LDPC_SOFT_OUT_DEINTERLEAVER_BYPASS", - /** Set for iteration stopping on successful decode condition - * i.e. a successful syndrome check. - */ - "RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE", - /** Set if a device supports decoder dequeue interrupts. */ - "RTE_BBDEV_LDPC_DEC_INTERRUPTS", - /** Set if a device supports scatter-gather functionality. */ - "RTE_BBDEV_LDPC_DEC_SCATTER_GATHER", - /** Set if a device supports input/output HARQ compression. */ - "RTE_BBDEV_LDPC_HARQ_6BIT_COMPRESSION", - /** Set if a device supports input LLR compression. */ - "RTE_BBDEV_LDPC_LLR_COMPRESSION", - /** Set if a device supports HARQ input from - * device's internal memory. - */ - "RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_IN_ENABLE", - /** Set if a device supports HARQ output to - * device's internal memory. - */ - "RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_OUT_ENABLE", - /** Set if a device supports loop-back access to - * HARQ internal memory. Intended for troubleshooting. - */ - "RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_LOOPBACK", - /** Set if a device includes LLR filler bits in the circular buffer - * for HARQ memory. If not set, it is assumed the filler bits are not - * in HARQ memory and handled directly by the LDPC decoder. - */ - "RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_FILLERS", -}; - -// based on DPDK BBDEV add_bbdev_dev -static int add_dev(uint8_t dev_id, struct rte_bbdev_info *info) -{ - int ret; - struct active_device *ad = &active_devs[nb_active_devs]; - unsigned int nb_queues; - nb_queues = RTE_MIN(rte_lcore_count(), info->drv.max_num_queues); - nb_queues = RTE_MIN(nb_queues, (unsigned int)MAX_QUEUES); - - /* Display for debug the capabilities of the card */ - for (int i = 0; info->drv.capabilities[i].type != RTE_BBDEV_OP_NONE; i++) { - printf("device: %d, capability[%d]=%s\n", dev_id, i, typeStr[info->drv.capabilities[i].type]); - if (info->drv.capabilities[i].type == RTE_BBDEV_OP_LDPC_ENC) { - const struct rte_bbdev_op_cap_ldpc_enc cap = info->drv.capabilities[i].cap.ldpc_enc; - printf(" buffers: src = %d, dst = %d\n capabilites: ", cap.num_buffers_src, cap.num_buffers_dst); - for (int j = 0; j < sizeof(cap.capability_flags) * 8; j++) - if (cap.capability_flags & (1ULL << j)) - printf("%s ", ldpcenc_flag_bitmask[j]); - printf("\n"); - } - if (info->drv.capabilities[i].type == RTE_BBDEV_OP_LDPC_DEC) { - const struct rte_bbdev_op_cap_ldpc_dec cap = info->drv.capabilities[i].cap.ldpc_dec; - printf(" buffers: src = %d, hard out = %d, soft_out %d, llr size %d, llr decimals %d \n capabilities: ", - cap.num_buffers_src, - cap.num_buffers_hard_out, - cap.num_buffers_soft_out, - cap.llr_size, - cap.llr_decimals); - for (int j = 0; j < sizeof(cap.capability_flags) * 8; j++) - if (cap.capability_flags & (1ULL << j)) - printf("%s ", ldpcdec_flag_bitmask[j]); - printf("\n"); - } - } - - /* setup device */ - ret = rte_bbdev_setup_queues(dev_id, nb_queues, info->socket_id); - if (ret < 0) { - printf("rte_bbdev_setup_queues(%u, %u, %d) ret %i\n", dev_id, nb_queues, info->socket_id, ret); - return -1; - } - - /* setup device queues */ - struct rte_bbdev_queue_conf qconf = { - .socket = info->socket_id, - .queue_size = info->drv.default_queue_conf.queue_size, - }; - - // Search a queue linked to HW capability ldpc decoding - qconf.op_type = RTE_BBDEV_OP_LDPC_ENC; - int queue_id; - for (queue_id = 0; queue_id < nb_queues; ++queue_id) { - ret = rte_bbdev_queue_configure(dev_id, queue_id, &qconf); - if (ret == 0) { - printf("Found LDCP encoding queue (id=%d) at prio%u on dev%u\n", queue_id, qconf.priority, dev_id); - qconf.priority++; - ad->enc_queue = queue_id; - ad->queue_ids[queue_id] = queue_id; - break; - } - } - AssertFatal(queue_id != nb_queues, "ERROR Failed to configure encoding queues on dev %u", dev_id); - - // Search a queue linked to HW capability ldpc encoding - qconf.op_type = RTE_BBDEV_OP_LDPC_DEC; - for (queue_id++; queue_id < nb_queues; ++queue_id) { - ret = rte_bbdev_queue_configure(dev_id, queue_id, &qconf); - if (ret == 0) { - printf("Found LDCP decoding queue (id=%d) at prio%u on dev%u\n", queue_id, qconf.priority, dev_id); - qconf.priority++; - ad->dec_queue = queue_id; - ad->queue_ids[queue_id] = queue_id; - break; - } - } - AssertFatal(queue_id != nb_queues, "ERROR Failed to configure encoding queues on dev %u", dev_id); - ad->nb_queues = 2; - return 0; -} - -// based on DPDK BBDEV init_op_data_objs -static int init_op_data_objs_dec(struct rte_bbdev_op_data *bufs, - uint8_t *input, - t_nrLDPCoffload_params *offloadParams, - struct rte_mempool *mbuf_pool, - const uint16_t n, - enum op_data_type op_type, - uint16_t min_alignment) -{ - bool large_input = false; - for (int i = 0; i < n; ++i) { - uint32_t data_len = offloadParams->perCB[i].E_cb; - char *data; - struct rte_mbuf *m_head = rte_pktmbuf_alloc(mbuf_pool); - AssertFatal(m_head != NULL, - "Not enough mbufs in %d data type mbuf pool (needed %u, available %u)", - op_type, - n, - mbuf_pool->size); - - if (data_len > RTE_BBDEV_LDPC_E_MAX_MBUF) { - printf("Warning: Larger input size than DPDK mbuf %u\n", data_len); - large_input = true; - } - bufs[i].data = m_head; - bufs[i].offset = 0; - bufs[i].length = 0; - - if ((op_type == DATA_INPUT) || (op_type == DATA_HARQ_INPUT)) { - if ((op_type == DATA_INPUT) && large_input) { - /* Allocate a fake overused mbuf */ - data = rte_malloc(NULL, data_len, 0); - AssertFatal(data != NULL, "rte malloc failed with %u bytes", data_len); - memcpy(data, &input[i * LDPC_MAX_CB_SIZE], data_len); - m_head->buf_addr = data; - m_head->buf_iova = rte_malloc_virt2iova(data); - m_head->data_off = 0; - m_head->data_len = data_len; - } else { - rte_pktmbuf_reset(m_head); - data = rte_pktmbuf_append(m_head, data_len); - AssertFatal(data != NULL, "Couldn't append %u bytes to mbuf from %d data type mbuf pool", data_len, op_type); - AssertFatal(data == RTE_PTR_ALIGN(data, min_alignment), - "Data addr in mbuf (%p) is not aligned to device min alignment (%u)", - data, - min_alignment); - rte_memcpy(data, &input[i * LDPC_MAX_CB_SIZE], data_len); - } - bufs[i].length += data_len; - } - } - return 0; -} - -// based on DPDK BBDEV init_op_data_objs -static int init_op_data_objs_enc(struct rte_bbdev_op_data *bufs, - uint8_t **input_enc, - t_nrLDPCoffload_params *offloadParams, - struct rte_mbuf *m_head, - struct rte_mempool *mbuf_pool, - const uint16_t n, - enum op_data_type op_type, - uint16_t min_alignment) -{ - bool large_input = false; - for (int i = 0; i < n; ++i) { - uint32_t data_len = offloadParams->Kr; - char *data; - struct rte_mbuf *m_head = rte_pktmbuf_alloc(mbuf_pool); - AssertFatal(m_head != NULL, - "Not enough mbufs in %d data type mbuf pool (needed %u, available %u)", - op_type, - n, - mbuf_pool->size); - - if (data_len > RTE_BBDEV_LDPC_E_MAX_MBUF) { - printf("Warning: Larger input size than DPDK mbuf %u\n", data_len); - large_input = true; - } - bufs[i].data = m_head; - bufs[i].offset = 0; - bufs[i].length = 0; - - if ((op_type == DATA_INPUT) || (op_type == DATA_HARQ_INPUT)) { - if ((op_type == DATA_INPUT) && large_input) { - /* Allocate a fake overused mbuf */ - data = rte_malloc(NULL, data_len, 0); - AssertFatal(data != NULL, "rte malloc failed with %u bytes", data_len); - memcpy(data, &input_enc[0], data_len); - m_head->buf_addr = data; - m_head->buf_iova = rte_malloc_virt2iova(data); - m_head->data_off = 0; - m_head->data_len = data_len; - } else { - rte_pktmbuf_reset(m_head); - data = rte_pktmbuf_append(m_head, data_len); - AssertFatal(data != NULL, "Couldn't append %u bytes to mbuf from %d data type mbuf pool", data_len, op_type); - AssertFatal(data == RTE_PTR_ALIGN(data, min_alignment), - "Data addr in mbuf (%p) is not aligned to device min alignment (%u)", - data, - min_alignment); - rte_memcpy(data, input_enc[i], data_len); - } - bufs[i].length += data_len; - } - } - return 0; -} - -// DPDK BBEV copy -static int allocate_buffers_on_socket(struct rte_bbdev_op_data **buffers, const int len, const int socket) -{ - int i; - - *buffers = rte_zmalloc_socket(NULL, len, 0, socket); - if (*buffers == NULL) { - printf("WARNING: Failed to allocate op_data on socket %d\n", socket); - /* try to allocate memory on other detected sockets */ - for (i = 0; i < socket; i++) { - *buffers = rte_zmalloc_socket(NULL, len, 0, i); - if (*buffers != NULL) - break; - } - } - - return (*buffers == NULL) ? -1 : 0; -} - -// DPDK BBDEV copy -static void -free_buffers(struct active_device *ad, struct test_op_params *op_params) -{ - rte_mempool_free(ad->bbdev_dec_op_pool); - rte_mempool_free(ad->bbdev_enc_op_pool); - rte_mempool_free(ad->in_mbuf_pool); - rte_mempool_free(ad->hard_out_mbuf_pool); - rte_mempool_free(ad->soft_out_mbuf_pool); - rte_mempool_free(ad->harq_in_mbuf_pool); - rte_mempool_free(ad->harq_out_mbuf_pool); - - for (int i = 2; i < rte_lcore_count(); ++i) { - for (int j = 0; j < RTE_MAX_NUMA_NODES; ++j) { - rte_free(op_params->q_bufs[j][i].inputs); - rte_free(op_params->q_bufs[j][i].hard_outputs); - rte_free(op_params->q_bufs[j][i].soft_outputs); - rte_free(op_params->q_bufs[j][i].harq_inputs); - rte_free(op_params->q_bufs[j][i].harq_outputs); - } - } -} - -// based on DPDK BBDEV copy_reference_ldpc_dec_op -static void set_ldpc_dec_op(struct rte_bbdev_dec_op **ops, - unsigned int start_idx, - struct data_buffers *bufs, - uint8_t ulsch_id, - t_nrLDPCoffload_params *p_offloadParams) -{ - unsigned int i; - for (i = 0; i < p_offloadParams->C; ++i) { - ops[i]->ldpc_dec.cb_params.e = p_offloadParams->perCB[i].E_cb; - ops[i]->ldpc_dec.basegraph = p_offloadParams->BG; - ops[i]->ldpc_dec.z_c = p_offloadParams->Z; - ops[i]->ldpc_dec.q_m = p_offloadParams->Qm; - ops[i]->ldpc_dec.n_filler = p_offloadParams->F; - ops[i]->ldpc_dec.n_cb = p_offloadParams->n_cb; - ops[i]->ldpc_dec.iter_max = p_offloadParams->numMaxIter; - ops[i]->ldpc_dec.rv_index = p_offloadParams->rv; - ops[i]->ldpc_dec.op_flags = RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE | - RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_IN_ENABLE | - RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_OUT_ENABLE | - RTE_BBDEV_LDPC_HQ_COMBINE_OUT_ENABLE; - if (p_offloadParams->setCombIn) { - ops[i]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE; - } - if (p_offloadParams->C > 1) { - ops[i]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_CRC_TYPE_24B_DROP; - ops[i]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_CRC_TYPE_24B_CHECK; - } - ops[i]->ldpc_dec.code_block_mode = 1; - ops[i]->ldpc_dec.harq_combined_input.offset = ulsch_id * NR_LDPC_MAX_NUM_CB * LDPC_MAX_CB_SIZE + i * LDPC_MAX_CB_SIZE; - ops[i]->ldpc_dec.harq_combined_output.offset = ulsch_id * NR_LDPC_MAX_NUM_CB * LDPC_MAX_CB_SIZE + i * LDPC_MAX_CB_SIZE; - if (bufs->hard_outputs != NULL) - ops[i]->ldpc_dec.hard_output = bufs->hard_outputs[start_idx + i]; - if (bufs->inputs != NULL) - ops[i]->ldpc_dec.input = bufs->inputs[start_idx + i]; - if (bufs->soft_outputs != NULL) - ops[i]->ldpc_dec.soft_output = bufs->soft_outputs[start_idx + i]; - if (bufs->harq_inputs != NULL) - ops[i]->ldpc_dec.harq_combined_input = bufs->harq_inputs[start_idx + i]; - if (bufs->harq_outputs != NULL) - ops[i]->ldpc_dec.harq_combined_output = bufs->harq_outputs[start_idx + i]; - } -} - -// based on DPDK BBDEV copy_reference_ldpc_enc_op -static void set_ldpc_enc_op(struct rte_bbdev_enc_op **ops, - unsigned int start_idx, - struct rte_bbdev_op_data *inputs, - struct rte_bbdev_op_data *outputs, - t_nrLDPCoffload_params *p_offloadParams) -{ - for (int i = 0; i < p_offloadParams->C; ++i) { - ops[i]->ldpc_enc.cb_params.e = p_offloadParams->perCB[i].E_cb; - ops[i]->ldpc_enc.basegraph = p_offloadParams->BG; - ops[i]->ldpc_enc.z_c = p_offloadParams->Z; - ops[i]->ldpc_enc.q_m = p_offloadParams->Qm; - ops[i]->ldpc_enc.n_filler = p_offloadParams->F; - ops[i]->ldpc_enc.n_cb = p_offloadParams->n_cb; - ops[i]->ldpc_enc.rv_index = p_offloadParams->rv; - ops[i]->ldpc_enc.op_flags = RTE_BBDEV_LDPC_RATE_MATCH; - ops[i]->ldpc_enc.code_block_mode = 1; - ops[i]->ldpc_enc.output = outputs[start_idx + i]; - ops[i]->ldpc_enc.input = inputs[start_idx + i]; - } -} - -static int retrieve_ldpc_dec_op(struct rte_bbdev_dec_op **ops, const uint16_t n, const int vector_mask, uint8_t *p_out) -{ - struct rte_bbdev_op_data *hard_output; - uint16_t data_len = 0; - struct rte_mbuf *m; - unsigned int i; - char *data; - int offset = 0; - for (i = 0; i < n; ++i) { - hard_output = &ops[i]->ldpc_dec.hard_output; - m = hard_output->data; - data_len = rte_pktmbuf_data_len(m) - hard_output->offset; - data = m->buf_addr; - memcpy(&p_out[offset], data + m->data_off, data_len); - offset += data_len; - rte_pktmbuf_free(ops[i]->ldpc_dec.hard_output.data); - rte_pktmbuf_free(ops[i]->ldpc_dec.input.data); - } - return 0; -} - -static int retrieve_ldpc_enc_op(struct rte_bbdev_enc_op **ops, const uint16_t n, uint8_t *p_out, nrLDPC_params_per_cb_t *perCB) -{ - int offset = 0; - for (int i = 0; i < n; ++i) { - struct rte_bbdev_op_data *output = &ops[i]->ldpc_enc.output; - struct rte_mbuf *m = output->data; - uint16_t data_len = rte_pktmbuf_data_len(m) - output->offset; - uint8_t *out = &p_out[offset]; - const char *data = m->buf_addr + m->data_off; - const char *end = data + data_len; - while (data < end) { - uint8_t byte = *data++; // get the current byte - for (int bit = 7; bit >= 0; --bit) { - *out++ = (byte >> bit) & 1; // extract each bit - } - } - offset += perCB[i].E_cb; - rte_pktmbuf_free(m); - rte_pktmbuf_free(ops[i]->ldpc_enc.input.data); - } - return 0; -} - -// based on DPDK BBDEV init_test_op_params -static int init_test_op_params(struct test_op_params *op_params, - enum rte_bbdev_op_type op_type, - struct rte_mempool *ops_mp, - uint16_t burst_sz, - uint16_t num_to_process, - uint16_t num_lcores) -{ - int ret = 0; - if (op_type == RTE_BBDEV_OP_LDPC_DEC) { - ret = rte_bbdev_dec_op_alloc_bulk(ops_mp, &op_params->ref_dec_op, num_to_process); - op_params->mp_dec = ops_mp; - } else { - ret = rte_bbdev_enc_op_alloc_bulk(ops_mp, &op_params->ref_enc_op, num_to_process); - op_params->mp_enc = ops_mp; - } - - AssertFatal(ret == 0, "rte_bbdev_op_alloc_bulk() failed"); - - op_params->burst_sz = burst_sz; - op_params->num_to_process = num_to_process; - op_params->num_lcores = num_lcores; - return 0; -} - -// based on DPDK BBDEV throughput_pmd_lcore_ldpc_dec -static int -pmd_lcore_ldpc_dec(void *arg) -{ - struct thread_params *tp = arg; - uint16_t enq, deq; - int time_out = 0; - const uint16_t queue_id = tp->queue_id; - const uint16_t num_segments = tp->p_offloadParams->C; - struct rte_bbdev_dec_op *ops_enq[num_segments]; - struct rte_bbdev_dec_op *ops_deq[num_segments]; - uint8_t ulsch_id = tp->ulsch_id; - struct data_buffers *bufs = NULL; - int i, ret; - struct rte_bbdev_info info; - uint16_t num_to_enq; - uint8_t *p_out = tp->p_out; - t_nrLDPCoffload_params *p_offloadParams = tp->p_offloadParams; - - AssertFatal((num_segments < MAX_BURST), "BURST_SIZE should be <= %u", MAX_BURST); - rte_bbdev_info_get(tp->dev_id, &info); - bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id]; - while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT) - rte_pause(); - - ret = rte_bbdev_dec_op_alloc_bulk(tp->op_params->mp_dec, ops_enq, num_segments); - AssertFatal(ret == 0, "Allocation failed for %d ops", num_segments); - set_ldpc_dec_op(ops_enq, 0, bufs, ulsch_id, p_offloadParams); - - for (enq = 0, deq = 0; enq < num_segments;) { - num_to_enq = num_segments; - if (unlikely(num_segments - enq < num_to_enq)) - num_to_enq = num_segments - enq; - - enq += rte_bbdev_enqueue_ldpc_dec_ops(tp->dev_id, queue_id, &ops_enq[enq], num_to_enq); - deq += rte_bbdev_dequeue_ldpc_dec_ops(tp->dev_id, queue_id, &ops_deq[deq], enq - deq); - } - - /* dequeue the remaining */ - while (deq < enq) { - deq += rte_bbdev_dequeue_ldpc_dec_ops(tp->dev_id, queue_id, &ops_deq[deq], enq - deq); - time_out++; - DevAssert(time_out <= TIME_OUT_POLL); - } - if (deq == enq) { - tp->iter_count = 0; - /* get the max of iter_count for all dequeued ops */ - for (i = 0; i < num_segments; ++i) { - uint8_t *status = tp->p_offloadParams->perCB[i].p_status_cb; - tp->iter_count = RTE_MAX(ops_enq[i]->ldpc_dec.iter_count, tp->iter_count); - *status = ops_enq[i]->status; - } - ret = retrieve_ldpc_dec_op(ops_deq, num_segments, tp->op_params->vector_mask, p_out); - AssertFatal(ret == 0, "LDPC offload decoder failed!"); - } - - rte_bbdev_dec_op_free_bulk(ops_enq, num_segments); - // Return the max number of iterations accross all segments - return tp->iter_count; -} - -// based on DPDK BBDEV throughput_pmd_lcore_ldpc_enc -static int pmd_lcore_ldpc_enc(void *arg) -{ - struct thread_params *tp = arg; - uint16_t enq, deq; - int time_out = 0; - const uint16_t queue_id = tp->queue_id; - const uint16_t num_segments = tp->p_offloadParams->C; - tp->op_params->num_to_process = num_segments; - struct rte_bbdev_enc_op *ops_enq[num_segments]; - struct rte_bbdev_enc_op *ops_deq[num_segments]; - struct rte_bbdev_info info; - int ret; - struct data_buffers *bufs = NULL; - uint16_t num_to_enq; - uint8_t *p_out = tp->p_out; - t_nrLDPCoffload_params *p_offloadParams = tp->p_offloadParams; - - AssertFatal((num_segments < MAX_BURST), "BURST_SIZE should be <= %u", MAX_BURST); - - rte_bbdev_info_get(tp->dev_id, &info); - bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id]; - while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT) - rte_pause(); - ret = rte_bbdev_enc_op_alloc_bulk(tp->op_params->mp_enc, ops_enq, num_segments); - AssertFatal(ret == 0, "Allocation failed for %d ops", num_segments); - - set_ldpc_enc_op(ops_enq, 0, bufs->inputs, bufs->hard_outputs, p_offloadParams); - for (enq = 0, deq = 0; enq < num_segments;) { - num_to_enq = num_segments; - if (unlikely(num_segments - enq < num_to_enq)) - num_to_enq = num_segments - enq; - enq += rte_bbdev_enqueue_ldpc_enc_ops(tp->dev_id, queue_id, &ops_enq[enq], num_to_enq); - deq += rte_bbdev_dequeue_ldpc_enc_ops(tp->dev_id, queue_id, &ops_deq[deq], enq - deq); - } - /* dequeue the remaining */ - while (deq < enq) { - deq += rte_bbdev_dequeue_ldpc_enc_ops(tp->dev_id, queue_id, &ops_deq[deq], enq - deq); - time_out++; - DevAssert(time_out <= TIME_OUT_POLL); - } - - ret = retrieve_ldpc_enc_op(ops_deq, num_segments, p_out, tp->p_offloadParams->perCB); - AssertFatal(ret == 0, "Failed to retrieve LDPC encoding op!"); - rte_bbdev_enc_op_free_bulk(ops_enq, num_segments); - return ret; -} - -// based on DPDK BBDEV throughput_pmd_lcore_dec -int start_pmd_dec(struct active_device *ad, - struct test_op_params *op_params, - t_nrLDPCoffload_params *p_offloadParams, - uint8_t ulsch_id, - uint8_t *p_out) -{ - int ret; - unsigned int lcore_id, used_cores = 0; - uint16_t num_lcores; - /* Set number of lcores */ - num_lcores = (ad->nb_queues < (op_params->num_lcores)) ? ad->nb_queues : op_params->num_lcores; - /* Allocate memory for thread parameters structure */ - struct thread_params *t_params = rte_zmalloc(NULL, num_lcores * sizeof(struct thread_params), RTE_CACHE_LINE_SIZE); - AssertFatal(t_params != NULL, - "Failed to alloc %zuB for t_params", - RTE_ALIGN(sizeof(struct thread_params) * num_lcores, RTE_CACHE_LINE_SIZE)); - rte_atomic16_set(&op_params->sync, SYNC_WAIT); - /* Master core is set at first entry */ - t_params[0].dev_id = ad->dev_id; - t_params[0].lcore_id = rte_lcore_id(); - t_params[0].op_params = op_params; - t_params[0].queue_id = ad->dec_queue; - t_params[0].iter_count = 0; - t_params[0].p_out = p_out; - t_params[0].p_offloadParams = p_offloadParams; - t_params[0].ulsch_id = ulsch_id; - used_cores++; - // For now, we never enter here, we don't use the DPDK thread pool - RTE_LCORE_FOREACH_WORKER(lcore_id) { - if (used_cores >= num_lcores) - break; - t_params[used_cores].dev_id = ad->dev_id; - t_params[used_cores].lcore_id = lcore_id; - t_params[used_cores].op_params = op_params; - t_params[used_cores].queue_id = ad->queue_ids[used_cores]; - t_params[used_cores].iter_count = 0; - t_params[used_cores].p_out = p_out; - t_params[used_cores].p_offloadParams = p_offloadParams; - t_params[used_cores].ulsch_id = ulsch_id; - rte_eal_remote_launch(pmd_lcore_ldpc_dec, &t_params[used_cores++], lcore_id); - } - rte_atomic16_set(&op_params->sync, SYNC_START); - ret = pmd_lcore_ldpc_dec(&t_params[0]); - /* Master core is always used */ - // for (used_cores = 1; used_cores < num_lcores; used_cores++) - // ret |= rte_eal_wait_lcore(t_params[used_cores].lcore_id); - rte_free(t_params); - return ret; -} - -// based on DPDK BBDEV throughput_pmd_lcore_enc -int32_t start_pmd_enc(struct active_device *ad, - struct test_op_params *op_params, - t_nrLDPCoffload_params *p_offloadParams, - uint8_t *p_out) -{ - unsigned int lcore_id, used_cores = 0; - uint16_t num_lcores; - int ret; - num_lcores = (ad->nb_queues < (op_params->num_lcores)) ? ad->nb_queues : op_params->num_lcores; - struct thread_params *t_params = rte_zmalloc(NULL, num_lcores * sizeof(struct thread_params), RTE_CACHE_LINE_SIZE); - rte_atomic16_set(&op_params->sync, SYNC_WAIT); - t_params[0].dev_id = ad->dev_id; - t_params[0].lcore_id = rte_lcore_id() + 1; - t_params[0].op_params = op_params; - t_params[0].queue_id = ad->enc_queue; - t_params[0].iter_count = 0; - t_params[0].p_out = p_out; - t_params[0].p_offloadParams = p_offloadParams; - used_cores++; - // For now, we never enter here, we don't use the DPDK thread pool - RTE_LCORE_FOREACH_WORKER(lcore_id) { - if (used_cores >= num_lcores) - break; - t_params[used_cores].dev_id = ad->dev_id; - t_params[used_cores].lcore_id = lcore_id; - t_params[used_cores].op_params = op_params; - t_params[used_cores].queue_id = ad->queue_ids[1]; - t_params[used_cores].iter_count = 0; - rte_eal_remote_launch(pmd_lcore_ldpc_enc, &t_params[used_cores++], lcore_id); - } - rte_atomic16_set(&op_params->sync, SYNC_START); - ret = pmd_lcore_ldpc_enc(&t_params[0]); - rte_free(t_params); - return ret; -} - -struct test_op_params *op_params = NULL; - -struct rte_mbuf *m_head[DATA_NUM_TYPES]; - -// OAI CODE -int32_t LDPCinit() -{ - pthread_mutex_init(&encode_mutex, NULL); - pthread_mutex_init(&decode_mutex, NULL); - int ret; - int dev_id = 0; - struct rte_bbdev_info info; - struct active_device *ad = active_devs; - char *dpdk_dev = NULL; // PCI address of the card - char *dpdk_core_list = NULL; // cores used by DPDK for T2 - char *dpdk_file_prefix = NULL; - paramdef_t LoaderParams[] = { - {"dpdk_dev", NULL, 0, .strptr = &dpdk_dev, .defstrval = NULL, TYPE_STRING, 0, NULL}, - {"dpdk_core_list", NULL, 0, .strptr = &dpdk_core_list, .defstrval = "11-12", TYPE_STRING, 0, NULL}, - {"dpdk_file_prefix", NULL, 0, .strptr = &dpdk_file_prefix, .defstrval = "b6", TYPE_STRING, 0, NULL} - }; - config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "ldpc_offload"); - AssertFatal(dpdk_dev != NULL, "ldpc_offload.dpdk_dev was not provided"); - char *argv_re[] = {"bbdev", "-a", dpdk_dev, "-l", dpdk_core_list, "--file-prefix", dpdk_file_prefix, "--"}; - // EAL initialization, if already initialized (init in xran lib) try to probe DPDK device - ret = rte_eal_init(sizeofArray(argv_re), argv_re); - if (ret < 0) { - printf("EAL initialization failed, probing DPDK device %s\n", dpdk_dev); - if (rte_dev_probe(dpdk_dev) != 0) { - LOG_E(PHY, "T2 card %s not found\n", dpdk_dev); - return (-1); - } - } - // Use only device 0 - first detected device - rte_bbdev_info_get(0, &info); - // Set number of queues based on number of initialized cores (-l option) and driver - // capabilities - AssertFatal(add_dev(dev_id, &info) == 0, "Failed to setup bbdev"); - AssertFatal(rte_bbdev_stats_reset(dev_id) == 0, "Failed to reset stats of bbdev %d", dev_id); - AssertFatal(rte_bbdev_start(dev_id) == 0, "Failed to start bbdev %d", dev_id); - - //the previous calls have populated this global variable (beurk) - // One more global to remove, not thread safe global op_params - op_params = rte_zmalloc(NULL, sizeof(struct test_op_params), RTE_CACHE_LINE_SIZE); - AssertFatal(op_params != NULL, - "Failed to alloc %zuB for op_params", - RTE_ALIGN(sizeof(struct test_op_params), RTE_CACHE_LINE_SIZE)); - - int socket_id = GET_SOCKET(info.socket_id); - int out_max_sz = 8448; // max code block size (for BG1), 22 * 384 - int in_max_sz = LDPC_MAX_CB_SIZE; // max number of encoded bits (for BG2 and MCS0) - int num_queues = 1; - int f_ret = create_mempools(ad, socket_id, num_queues, out_max_sz, in_max_sz); - if (f_ret != 0) { - printf("Couldn't create mempools"); - return -1; - } - f_ret = init_test_op_params(op_params, RTE_BBDEV_OP_LDPC_DEC, ad->bbdev_dec_op_pool, num_queues, num_queues, 1); - f_ret = init_test_op_params(op_params, RTE_BBDEV_OP_LDPC_ENC, ad->bbdev_enc_op_pool, num_queues, num_queues, 1); - if (f_ret != 0) { - printf("Couldn't init test op params"); - return -1; - } - return 0; -} - -int32_t LDPCshutdown() -{ - struct active_device *ad = active_devs; - int dev_id = 0; - struct rte_bbdev_stats stats; - free_buffers(ad, op_params); - rte_free(op_params); - rte_bbdev_stats_get(dev_id, &stats); - rte_bbdev_stop(dev_id); - rte_bbdev_close(dev_id); - memset(active_devs, 0, sizeof(active_devs)); - nb_active_devs = 0; - return 0; -} - -int32_t LDPCdecoder(struct nrLDPC_dec_params *p_decParams, - uint8_t harq_pid, - uint8_t ulsch_id, - uint8_t C, - int8_t *p_llr, - int8_t *p_out, - t_nrLDPC_time_stats *p_profiler, - decode_abort_t *ab) -{ - pthread_mutex_lock(&decode_mutex); - // hardcoded we use first device - struct active_device *ad = active_devs; - t_nrLDPCoffload_params offloadParams = {.n_cb = (p_decParams->BG == 1) ? (66 * p_decParams->Z) : (50 * p_decParams->Z), - .BG = p_decParams->BG, - .Z = p_decParams->Z, - .rv = p_decParams->rv, - .F = p_decParams->F, - .Qm = p_decParams->Qm, - .numMaxIter = p_decParams->numMaxIter, - .C = C, - .setCombIn = p_decParams->setCombIn}; - - for (int r = 0; r < C; r++) { - offloadParams.perCB[r].E_cb = p_decParams->perCB[r].E_cb; - offloadParams.perCB[r].p_status_cb = &(p_decParams->perCB[r].status_cb); - } - struct rte_bbdev_info info; - int ret; - rte_bbdev_info_get(ad->dev_id, &info); - int socket_id = GET_SOCKET(info.socket_id); - // fill_queue_buffers -> init_op_data_objs - struct rte_mempool *in_mp = ad->in_mbuf_pool; - struct rte_mempool *hard_out_mp = ad->hard_out_mbuf_pool; - struct rte_mempool *soft_out_mp = ad->soft_out_mbuf_pool; - struct rte_mempool *harq_in_mp = ad->harq_in_mbuf_pool; - struct rte_mempool *harq_out_mp = ad->harq_out_mbuf_pool; - struct rte_mempool *mbuf_pools[DATA_NUM_TYPES] = {in_mp, soft_out_mp, hard_out_mp, harq_in_mp, harq_out_mp}; - uint8_t queue_id = ad->dec_queue; - struct rte_bbdev_op_data **queue_ops[DATA_NUM_TYPES] = {&op_params->q_bufs[socket_id][queue_id].inputs, - &op_params->q_bufs[socket_id][queue_id].soft_outputs, - &op_params->q_bufs[socket_id][queue_id].hard_outputs, - &op_params->q_bufs[socket_id][queue_id].harq_inputs, - &op_params->q_bufs[socket_id][queue_id].harq_outputs}; - for (enum op_data_type type = DATA_INPUT; type < 3; type += 2) { - ret = allocate_buffers_on_socket(queue_ops[type], C * sizeof(struct rte_bbdev_op_data), socket_id); - AssertFatal(ret == 0, "Couldn't allocate memory for rte_bbdev_op_data structs"); - ret = init_op_data_objs_dec(*queue_ops[type], - (uint8_t *)p_llr, - &offloadParams, - mbuf_pools[type], - C, - type, - info.drv.min_alignment); - AssertFatal(ret == 0, "Couldn't init rte_bbdev_op_data structs"); - } - ret = start_pmd_dec(ad, op_params, &offloadParams, ulsch_id, (uint8_t *)p_out); - if (ret < 0) { - printf("Couldn't start pmd dec\n"); - pthread_mutex_unlock(&decode_mutex); - return (p_decParams->numMaxIter); - } - pthread_mutex_unlock(&decode_mutex); - return ret; -} - -int32_t LDPCencoder(unsigned char **input, unsigned char **output, encoder_implemparams_t *impp) -{ - pthread_mutex_lock(&encode_mutex); - // hardcoded to use the first found board - struct active_device *ad = active_devs; - int ret; - uint32_t Nref = 0; - t_nrLDPCoffload_params offloadParams = {.n_cb = (impp->BG == 1) ? (66 * impp->Zc) : (50 * impp->Zc), - .BG = impp->BG, - .Z = impp->Zc, - .rv = impp->rv, - .F = impp->F, - .Qm = impp->Qm, - .C = impp->n_segments, - .Kr = (impp->K - impp->F + 7) / 8}; - for (int r = 0; r < impp->n_segments; r++) { - offloadParams.perCB[r].E_cb = impp->perCB[r].E_cb; - } - if (impp->Tbslbrm != 0) { - Nref = 3 * impp->Tbslbrm / (2 * impp->n_segments); - offloadParams.n_cb = min(offloadParams.n_cb, Nref); - } - struct rte_bbdev_info info; - rte_bbdev_info_get(ad->dev_id, &info); - int socket_id = GET_SOCKET(info.socket_id); - // fill_queue_buffers -> init_op_data_objs - struct rte_mempool *in_mp = ad->in_mbuf_pool; - struct rte_mempool *hard_out_mp = ad->hard_out_mbuf_pool; - struct rte_mempool *soft_out_mp = ad->soft_out_mbuf_pool; - struct rte_mempool *harq_in_mp = ad->harq_in_mbuf_pool; - struct rte_mempool *harq_out_mp = ad->harq_out_mbuf_pool; - struct rte_mempool *mbuf_pools[DATA_NUM_TYPES] = {in_mp, soft_out_mp, hard_out_mp, harq_in_mp, harq_out_mp}; - uint8_t queue_id = ad->enc_queue; - struct rte_bbdev_op_data **queue_ops[DATA_NUM_TYPES] = {&op_params->q_bufs[socket_id][queue_id].inputs, - &op_params->q_bufs[socket_id][queue_id].soft_outputs, - &op_params->q_bufs[socket_id][queue_id].hard_outputs, - &op_params->q_bufs[socket_id][queue_id].harq_inputs, - &op_params->q_bufs[socket_id][queue_id].harq_outputs}; - for (enum op_data_type type = DATA_INPUT; type < 3; type += 2) { - ret = allocate_buffers_on_socket(queue_ops[type], impp->n_segments * sizeof(struct rte_bbdev_op_data), socket_id); - AssertFatal(ret == 0, "Couldn't allocate memory for rte_bbdev_op_data structs"); - ret = init_op_data_objs_enc(*queue_ops[type], - input, - &offloadParams, - m_head[type], - mbuf_pools[type], - impp->n_segments, - type, - info.drv.min_alignment); - AssertFatal(ret == 0, "Couldn't init rte_bbdev_op_data structs"); - } - ret = start_pmd_enc(ad, op_params, &offloadParams, *output); - pthread_mutex_unlock(&encode_mutex); - return ret; -} From 8756afdb5ad640595b40fcaff58687305a000448 Mon Sep 17 00:00:00 2001 From: Yi-Hung Chang Date: Wed, 9 Oct 2024 14:45:31 +0200 Subject: [PATCH 44/83] feat(nrLDPC_coding_interface): Add ldpc_xdma coding library --- CMakeLists.txt | 26 +- cmake_targets/build_oai | 2 +- .../nrLDPC_coding_xdma/nrLDPC_coding_xdma.c | 455 ++++++++++ .../nrLDPC_coding_xdma_offload.c | 783 ++++++++++++++++++ .../nrLDPC_coding_xdma_offload.h | 67 ++ .../nrLDPC_coding_xdma/xdma_diag.h | 119 +++ 6 files changed, 1450 insertions(+), 2 deletions(-) create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.c create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.h create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/xdma_diag.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 44a2d0d487..e1528d1a62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -508,6 +508,19 @@ endif() ########################################################## +# LDPC offload library - XDMA +########################################################## +add_boolean_option(ENABLE_LDPC_XDMA OFF "Build support for LDPC Offload to XDMA library" OFF) +if (ENABLE_LDPC_XDMA) + set(PHY_NRLDPC_CODING_XDMA_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c + ) + add_library(ldpc_xdma MODULE ${PHY_NRLDPC_CODING_XDMA_SRC}) +endif() + include_directories ("${OPENAIR_DIR}/radio/COMMON") ############################################################## @@ -2065,6 +2078,10 @@ if (ENABLE_LDPC_T2) add_dependencies(nr-softmodem ldpc_t2) endif() +if (ENABLE_LDPC_XDMA) + add_dependencies(nr-softmodem ldpc_xdma) +endif() + # force the generation of ASN.1 so that we don't need to wait during the build target_link_libraries(nr-softmodem PRIVATE asn1_lte_rrc asn1_nr_rrc asn1_s1ap asn1_ngap asn1_m2ap asn1_m3ap asn1_x2ap asn1_f1ap asn1_lpp) @@ -2126,6 +2143,10 @@ if (ENABLE_LDPC_T2) add_dependencies(nr-uesoftmodem ldpc_t2) endif() +if (ENABLE_LDPC_XDMA) + add_dependencies(nr-uesoftmodem ldpc_xdma) +endif() + # force the generation of ASN.1 so that we don't need to wait during the build target_link_libraries(nr-uesoftmodem PRIVATE asn1_lte_rrc asn1_nr_rrc asn1_s1ap asn1_ngap asn1_m2ap asn1_m3ap asn1_x2ap asn1_f1ap asn1_lpp) @@ -2283,6 +2304,9 @@ add_executable(nr_ulsim if (ENABLE_LDPC_T2) add_dependencies(nr_ulsim ldpc_t2) endif() +if (ENABLE_LDPC_XDMA) + add_dependencies(nr_ulsim ldpc_xdma) +endif() add_dependencies(nr_ulsim ldpc_slot_segment) target_link_libraries(nr_ulsim PRIVATE @@ -2350,7 +2374,7 @@ if (${T_TRACER}) PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU PHY_MEX L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE L2_UE_LTE_NR MAC_NR_COMMON MAC_UE_NR ngap CN_UTILS GTPV1U SCTP_CLIENT MME_APP LIB_NAS_UE NB_IoT SIMU OPENAIR0_LIB - ldpc_orig ldpc_optim ldpc_optim8seg ldpc_cl ldpc_cuda ldpc ldpc_slot_segment ldpc_t2 + ldpc_orig ldpc_optim ldpc_optim8seg ldpc_cl ldpc_cuda ldpc ldpc_slot_segment ldpc_t2 ldpc_xdma dfts config_internals nr_common) if (TARGET ${i}) add_dependencies(${i} generate_T) diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 5e1ad1467e..d6d3720bca 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -46,7 +46,7 @@ BUILD_DOXYGEN=0 DISABLE_HARDWARE_DEPENDENCY="False" CMAKE_BUILD_TYPE="RelWithDebInfo" CMAKE_CMD="$CMAKE" -OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope ldpc_cuda ldpc_t2 websrv oai_iqplayer imscope" +OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope ldpc_cuda ldpc_t2 ldpc_xdma websrv oai_iqplayer imscope" TARGET_LIST="" BUILD_TOOL_OPT="-j$(nproc)" diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c new file mode 100644 index 0000000000..613c999042 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c @@ -0,0 +1,455 @@ +/* + * 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.0 (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 PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c + * \brief Top-level routines for decoding LDPC (ULSCH) transport channels + * decoding implemented using a FEC IP core on FPGA through XDMA driver + */ + +// [from gNB coding] +#include + +#include "PHY/CODING/coding_defs.h" +#include "PHY/CODING/coding_extern.h" +#include "PHY/CODING/lte_interleaver_inline.h" +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.h" +#include "PHY/CODING/nrLDPC_extern.h" +#include "PHY/NR_TRANSPORT/nr_dlsch.h" +#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" +#include "PHY/NR_TRANSPORT/nr_transport_proto.h" +#include "PHY/NR_TRANSPORT/nr_ulsch.h" +#include "PHY/defs_gNB.h" +#include "SCHED_NR/fapi_nr_l1.h" +#include "SCHED_NR/sched_nr.h" +#include "common/utils/LOG/log.h" +#include "common/utils/LOG/vcd_signal_dumper.h" +#include "defs.h" +// #define DEBUG_ULSCH_DECODING +// #define gNB_DEBUG_TRACE + +#define OAI_UL_LDPC_MAX_NUM_LLR 27000 // 26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX = 68*384 +// #define DEBUG_CRC +#ifdef DEBUG_CRC +#define PRINT_CRC_CHECK(a) a +#else +#define PRINT_CRC_CHECK(a) +#endif + +// extern double cpuf; + +#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h" +#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h" + +#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" + +// Global var to limit the rework of the dirty legacy code +ldpc_interface_t ldpc_interface_segment; +int num_threads_prepare_max = 0; +char *user_device = NULL; +char *enc_read_device = NULL; +char *enc_write_device = NULL; +char *dec_read_device = NULL; +char *dec_write_device = NULL; + +/*! + * \typedef args_fpga_decode_prepare_t + * \struct args_fpga_decode_prepare_s + * \brief arguments structure for passing arguments to the nr_ulsch_FPGA_decoding_prepare_blocks function + */ +typedef struct args_fpga_decode_prepare_s { + nrLDPC_TB_decoding_parameters_t *TB_params; /*!< transport blocks parameters */ + + uint8_t *multi_indata; /*!< pointer to the head of the block destination array that is then passed to the FPGA decoding */ + int no_iteration_ldpc; /*!< pointer to the number of iteration set by this function */ + uint32_t r_first; /*!< index of the first block to be prepared within this function */ + uint32_t r_span; /*!< number of blocks to be prepared within this function */ + int r_offset; /*!< r index expressed in bits */ + int input_CBoffset; /*!< */ + int kc; /*!< */ + int K_bits_F; /*!< */ + task_ans_t *ans; /*!< pointer to the answer that is used by thread pool to detect job completion */ +} args_fpga_decode_prepare_t; + +int32_t nrLDPC_coding_init(void); +int32_t nrLDPC_coding_shutdown(void); +int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *slot_params, int frame_rx, int slot_rx); +// int32_t nrLDPC_coding_encoder(void); +int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params, + int frame_rx, + int slot_rx, + tpool_t *ldpc_threadPool); +void nr_ulsch_FPGA_decoding_prepare_blocks(void *args); + +int32_t nrLDPC_coding_init(void) +{ + char *encoder_shlibversion = NULL; + paramdef_t LoaderParams[] = { + {"num_threads_prepare", NULL, 0, .iptr = &num_threads_prepare_max, .defintval = 0, TYPE_INT, 0, NULL}, + {"encoder_shlibversion", NULL, 0, .strptr = &encoder_shlibversion, .defstrval = "", TYPE_STRING, 0, NULL}, + {"user_device", NULL, 0, .strptr = &user_device, .defstrval = DEVICE_NAME_DEFAULT_USER, TYPE_STRING, 0, NULL}, + {"enc_read_device", NULL, 0, .strptr = &enc_read_device, .defstrval = DEVICE_NAME_DEFAULT_ENC_READ, TYPE_STRING, 0, NULL}, + {"enc_write_device", NULL, 0, .strptr = &enc_write_device, .defstrval = DEVICE_NAME_DEFAULT_ENC_WRITE, TYPE_STRING, 0, NULL}, + {"dec_read_device", NULL, 0, .strptr = &dec_read_device, .defstrval = DEVICE_NAME_DEFAULT_DEC_READ, TYPE_STRING, 0, NULL}, + {"dec_write_device", NULL, 0, .strptr = &dec_write_device, .defstrval = DEVICE_NAME_DEFAULT_DEC_WRITE, TYPE_STRING, 0, NULL} + }; + config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "nrLDPC_coding_xdma"); + AssertFatal(num_threads_prepare_max != 0, "nrLDPC_coding_xdma.num_threads_prepare was not provided"); + + load_LDPClib(encoder_shlibversion, &ldpc_interface_segment); + return 0; +} + +int32_t nrLDPC_coding_shutdown(void) +{ + free_LDPClib(&ldpc_interface_segment); + return 0; +} + +int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *slot_params, int frame_rx, int slot_rx) +{ + int nbDecode = 0; + for (int ULSCH_id = 0; ULSCH_id < slot_params->nb_TBs; ULSCH_id++) + nbDecode += decoder_xdma(&slot_params->TBs[ULSCH_id], frame_rx, slot_rx, slot_params->threadPool); + return nbDecode; +} + +/* +int32_t nrLDPC_coding_encoder(void) +{ + return 0; +} +*/ + +int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params, + int frame_rx, + int slot_rx, + tpool_t *ldpc_threadPool) +{ + const uint32_t Kr = TB_params->K; + const uint32_t Kr_bytes = Kr >> 3; + const int kc = TB_params->BG == 2 ? 52 : 68; + int r_offset = 0, offset = 0; + int K_bits_F = Kr - TB_params->F; + + // FPGA parameter preprocessing + static uint8_t multi_indata[27000 * 25]; // FPGA input data + static uint8_t multi_outdata[1100 * 25]; // FPGA output data + + int bg_len = TB_params->BG == 1 ? 22 : 10; + + // Calc input CB offset + int input_CBoffset = TB_params->Z * kc * 8; + if ((input_CBoffset & 0x7F) == 0) + input_CBoffset = input_CBoffset / 8; + else + input_CBoffset = 16 * ((input_CBoffset / 128) + 1); + + DecIFConf dec_conf = {0}; + dec_conf.Zc = TB_params->Z; + dec_conf.BG = TB_params->BG; + dec_conf.max_iter = TB_params->max_ldpc_iterations; + dec_conf.numCB = TB_params->C; + // input soft bits length, Zc x 66 - length of filler bits + dec_conf.numChannelLls = (K_bits_F - 2 * TB_params->Z) + (kc * TB_params->Z - Kr); + // filler bits length + dec_conf.numFillerBits = TB_params->F; + dec_conf.max_schedule = 0; + dec_conf.SetIdx = 12; + dec_conf.nRows = (dec_conf.BG == 1) ? 46 : 42; + + dec_conf.user_device = user_device; + dec_conf.enc_read_device = enc_read_device; + dec_conf.enc_write_device = enc_write_device; + dec_conf.dec_read_device = dec_read_device; + dec_conf.dec_write_device = dec_write_device; + + int out_CBoffset = dec_conf.Zc * bg_len; + if ((out_CBoffset & 0x7F) == 0) + out_CBoffset = out_CBoffset / 8; + else + out_CBoffset = 16 * ((out_CBoffset / 128) + 1); + +#ifdef LDPC_DATA + printf("\n------------------------\n"); + printf("BG:\t\t%d\n", dec_conf.BG); + printf("TB_params->C: %d\n", TB_params->C); + printf("TB_params->K: %d\n", TB_params->K); + printf("TB_params->Z: %d\n", TB_params->Z); + printf("TB_params->F: %d\n", TB_params->F); + printf("numChannelLls:\t %d = (%d - 2 * %d) + (%d * %d - %d)\n", + dec_conf.numChannelLls, + K_bits_F, + TB_params->Z, + kc, + TB_params->Z, + Kr); + printf("numFillerBits:\t %d\n", TB_params->F); + printf("------------------------\n"); + // =================================== + // debug mode + // =================================== + FILE *fptr_llr, *fptr_ldpc; + fptr_llr = fopen("../../../cmake_targets/log/ulsim_ldpc_llr.txt", "w"); + fptr_ldpc = fopen("../../../cmake_targets/log/ulsim_ldpc_output.txt", "w"); + // =================================== +#endif + + int length_dec = lenWithCrc(TB_params->C, TB_params->A); + uint8_t crc_type = crcType(TB_params->C, TB_params->A); + int no_iteration_ldpc = 2; + + uint32_t num_threads_prepare = 0; + + // calculate required number of jobs + uint32_t r_while = 0; + while (r_while < TB_params->C) { + + // calculate number of segments processed in the new job + uint32_t modulus = (TB_params->C - r_while) % (num_threads_prepare_max - num_threads_prepare); + uint32_t quotient = (TB_params->C - r_while) / (num_threads_prepare_max - num_threads_prepare); + uint32_t r_span_max = modulus == 0 ? quotient : quotient + 1; + + // saturate to be sure to not go above C + uint32_t r_span = TB_params->C - r_while < r_span_max ? TB_params->C - r_while : r_span_max; + + // increment + num_threads_prepare++; + r_while += r_span; + } + + args_fpga_decode_prepare_t arr[num_threads_prepare]; + task_ans_t ans[num_threads_prepare]; + memset(ans, 0, num_threads_prepare * sizeof(task_ans_t)); + thread_info_tm_t t_info = {.buf = (uint8_t *)arr, .len = 0, .cap = num_threads_prepare, .ans = ans}; + + // start the prepare jobs + uint32_t r_remaining = 0; + for (uint32_t r = 0; r < TB_params->C; r++) { + nrLDPC_segment_decoding_parameters_t *segment_params = &TB_params->segments[r]; + if (r_remaining == 0) { + // TODO: int nr_tti_rx = 0; + + args_fpga_decode_prepare_t *args = &((args_fpga_decode_prepare_t *)t_info.buf)[t_info.len]; + DevAssert(t_info.len < t_info.cap); + args->ans = &t_info.ans[t_info.len]; + t_info.len += 1; + + args->TB_params = TB_params; + args->multi_indata = multi_indata; + args->no_iteration_ldpc = no_iteration_ldpc; + args->r_first = r; + + uint32_t modulus = (TB_params->C - r) % (num_threads_prepare_max - num_threads_prepare); + uint32_t quotient = (TB_params->C - r) / (num_threads_prepare_max - num_threads_prepare); + uint32_t r_span_max = modulus == 0 ? quotient : quotient + 1; + + uint32_t r_span = TB_params->C - r < r_span_max ? TB_params->C - r : r_span_max; + args->r_span = r_span; + args->r_offset = r_offset; + args->input_CBoffset = input_CBoffset; + args->kc = kc; + args->K_bits_F = K_bits_F; + + r_remaining = r_span; + + task_t t = {.func = &nr_ulsch_FPGA_decoding_prepare_blocks, .args = args}; + pushTpool(ldpc_threadPool, t); + + LOG_D(PHY, "Added %d block(s) to prepare for decoding, in pipe: %d to %d\n", r_span, r, r + r_span - 1); + } + r_offset += segment_params->E; + offset += (Kr_bytes - (TB_params->F >> 3) - ((TB_params->C > 1) ? 3 : 0)); + r_remaining -= 1; + } + + // reset offset in order to properly fill the output array later + offset = 0; + + DevAssert(num_threads_prepare == t_info.len); + + // wait for the prepare jobs to complete + join_task_ans(t_info.ans, t_info.len); + + for (uint32_t job = 0; job < num_threads_prepare; job++) { + args_fpga_decode_prepare_t *args = &arr[job]; + if (args->no_iteration_ldpc > TB_params->max_ldpc_iterations) + no_iteration_ldpc = TB_params->max_ldpc_iterations + 1; + } + + // launch decode with FPGA + LOG_I(PHY, "Run the LDPC ------[FPGA version]------\n"); + //================================================================== + // Xilinx FPGA LDPC decoding function -> nrLDPC_decoder_FPGA_PYM() + //================================================================== + start_meas(&TB_params->segments[0].ts_ldpc_decode); + nrLDPC_decoder_FPGA_PYM(&multi_indata[0], &multi_outdata[0], dec_conf); + // printf("Xilinx FPGA -> CB = %d\n", harq_process->C); + stop_meas(&TB_params->segments[0].ts_ldpc_decode); + + *TB_params->processedSegments = 0; + for (uint32_t r = 0; r < TB_params->C; r++) { + // ------------------------------------------------------------ + // --------------------- copy FPGA output --------------------- + // ------------------------------------------------------------ + nrLDPC_segment_decoding_parameters_t *segment_params = &TB_params->segments[r]; + if (check_crc(multi_outdata, length_dec, crc_type)) { +#ifdef DEBUG_CRC + LOG_I(PHY, "Segment %d CRC OK\n", r); +#endif + no_iteration_ldpc = 2; + } else { +#ifdef DEBUG_CRC + LOG_I(PHY, "segment %d CRC NOK\n", r); +#endif + no_iteration_ldpc = TB_params->max_ldpc_iterations + 1; + } + for (int i = 0; i < out_CBoffset; i++) { + segment_params->c[i] = multi_outdata[i + r * out_CBoffset]; + } + segment_params->decodeSuccess = (no_iteration_ldpc <= TB_params->max_ldpc_iterations); + if (segment_params->decodeSuccess) { + *TB_params->processedSegments = *TB_params->processedSegments + 1; + } + } + + return 0; +} + +/*! + * \fn nr_ulsch_FPGA_decoding_prepare_blocks(void *args) + * \brief prepare blocks for LDPC decoding on FPGA + * + * \param args pointer to the arguments of the function in a structure of type args_fpga_decode_prepare_t + */ +void nr_ulsch_FPGA_decoding_prepare_blocks(void *args) +{ + // extract the arguments + args_fpga_decode_prepare_t *arguments = (args_fpga_decode_prepare_t *)args; + + nrLDPC_TB_decoding_parameters_t *TB_params = arguments->TB_params; + + uint8_t Qm = TB_params->Qm; + + uint8_t BG = TB_params->BG; + uint8_t rv_index = TB_params->rv_index; + uint8_t max_ldpc_iterations = TB_params->max_ldpc_iterations; + + uint32_t tbslbrm = TB_params->tbslbrm; + uint32_t Kr = TB_params->K; + uint32_t Z = TB_params->Z; + uint32_t F = TB_params->F; + + uint32_t C = TB_params->C; + + nrLDPC_segment_decoding_parameters_t *segment_params = &TB_params->segments[0]; + + short *ulsch_llr = segment_params->llr; + + uint8_t *multi_indata = arguments->multi_indata; + int no_iteration_ldpc = arguments->no_iteration_ldpc; + uint32_t r_first = arguments->r_first; + uint32_t r_span = arguments->r_span; + int r_offset = arguments->r_offset; + int input_CBoffset = arguments->input_CBoffset; + int kc = arguments->kc; + int K_bits_F = arguments->K_bits_F; + + int16_t z[68 * 384 + 16] __attribute__((aligned(16))); + simde__m128i *pv = (simde__m128i *)&z; + + // the function processes r_span blocks starting from block at index r_first in ulsch_llr + for (uint32_t r = r_first; r < (r_first + r_span); r++) { + nrLDPC_segment_decoding_parameters_t *segment_params = &TB_params->segments[r]; + // ----------------------- FPGA pre process ------------------------ + simde__m128i ones = simde_mm_set1_epi8(255); // Generate a vector with all elements set to 255 + simde__m128i *temp_multi_indata = (simde__m128i *)&multi_indata[r * input_CBoffset]; + // ----------------------------------------------------------------- + + // code blocks after bit selection in rate matching for LDPC code (38.212 V15.4.0 section 5.4.2.1) + int16_t harq_e[segment_params->E]; + // ------------------------------------------------------------------------------------------- + // deinterleaving + // ------------------------------------------------------------------------------------------- + start_meas(&segment_params->ts_deinterleave); + nr_deinterleaving_ldpc(segment_params->E, Qm, harq_e, ulsch_llr + r_offset); + stop_meas(&segment_params->ts_deinterleave); + // ------------------------------------------------------------------------------------------- + // dematching + // ------------------------------------------------------------------------------------------- + start_meas(&segment_params->ts_rate_unmatch); + if (nr_rate_matching_ldpc_rx(tbslbrm, + BG, + Z, + segment_params->d, + harq_e, + C, + rv_index, + *segment_params->d_to_be_cleared, + segment_params->E, + F, + Kr - F - 2 * Z) + == -1) { + stop_meas(&segment_params->ts_rate_unmatch); + LOG_E(PHY, "ulsch_decoding.c: Problem in rate_matching\n"); + no_iteration_ldpc = max_ldpc_iterations + 1; + arguments->no_iteration_ldpc = no_iteration_ldpc; + return; + } else { + stop_meas(&segment_params->ts_rate_unmatch); + } + + *segment_params->d_to_be_cleared = false; + + memset(segment_params->c, 0, Kr >> 3); + + // set first 2*Z_c bits to zeros + memset(&z[0], 0, 2 * Z * sizeof(int16_t)); + // set Filler bits + memset((&z[0] + K_bits_F), 127, F * sizeof(int16_t)); + // Move coded bits before filler bits + memcpy((&z[0] + 2 * Z), segment_params->d, (K_bits_F - 2 * Z) * sizeof(int16_t)); + // skip filler bits + memcpy((&z[0] + Kr), segment_params->d + (Kr - 2 * Z), (kc * Z - Kr) * sizeof(int16_t)); + + // Saturate coded bits before decoding into 8 bits values + for (int i = 0, j = 0; j < ((kc * Z) >> 4); i += 2, j++) { + temp_multi_indata[j] = + simde_mm_xor_si128(simde_mm_packs_epi16(pv[i], pv[i + 1]), + simde_mm_cmpeq_epi32(ones, + ones)); // Perform NOT operation and write the result to temp_multi_indata[j] + } + + // the last bytes before reaching "kc * harq_process->Z" should not be written 128 bits at a time to avoid overwritting the + // following block in multi_indata + simde__m128i tmp = + simde_mm_xor_si128(simde_mm_packs_epi16(pv[2 * ((kc * Z) >> 4)], pv[2 * ((kc * Z) >> 4) + 1]), + simde_mm_cmpeq_epi32(ones, + ones)); // Perform NOT operation and write the result to temp_multi_indata[j] + uint8_t *tmp_p = (uint8_t *)&tmp; + for (int i = 0, j = ((kc * Z) & 0xfffffff0); j < kc * Z; i++, j++) { + multi_indata[r * input_CBoffset + j] = tmp_p[i]; + } + + r_offset += segment_params->E; + } + + arguments->no_iteration_ldpc = no_iteration_ldpc; +} diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.c new file mode 100644 index 0000000000..0673ad2c73 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.c @@ -0,0 +1,783 @@ +/* + * Copyright (c) 2016-present, Xilinx, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license + * the terms of the BSD Licence are reported below: + * + * BSD License + * + * For Xilinx DMA IP software + * + * Copyright (c) 2016-present, Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name Xilinx nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define _DEFAULT_SOURCE +#define _XOPEN_SOURCE 500 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "xdma_diag.h" +#include "nrLDPC_coding_xdma_offload.h" + +#include "common/utils/assertions.h" + +typedef unsigned long long U64; +void* map_base; +int fd; +int fd_enc_write, fd_enc_read; +char *dev_enc_write, *dev_enc_read; +int fd_dec_write, fd_dec_read; +char *dev_dec_write, *dev_dec_read; +char allocated_write[24 * 1024] __attribute__((aligned(4096))); +char allocated_read[24 * 1024 * 3] __attribute__((aligned(4096))); + +// dma_from_device.c + +// [Start] #include "dma_utils.c" =================================== + +/* + * man 2 write: + * On Linux, write() (and similar system calls) will transfer at most + * 0x7ffff000 (2,147,479,552) bytes, returning the number of bytes + * actually transferred. (This is true on both 32-bit and 64-bit + * systems.) + */ + +#define RW_MAX_SIZE 0x7ffff000 + +int verbose = 0; + +uint64_t getopt_integer(char* optarg) +{ + int rc; + uint64_t value; + + rc = sscanf(optarg, "0x%lx", &value); + if (rc <= 0) + rc = sscanf(optarg, "%lu", &value); + + return value; +} + +ssize_t read_to_buffer(char* fname, int fd, char* buffer, uint64_t size, uint64_t base) +{ + ssize_t rc; + uint64_t count = 0; + char* buf = buffer; + off_t offset = base; + + while (count < size) { + uint64_t bytes = size - count; + + if (bytes > RW_MAX_SIZE) + bytes = RW_MAX_SIZE; + + if (offset) { + rc = lseek(fd, offset, SEEK_SET); + if (rc != offset) { + fprintf(stderr, "%s, seek off 0x%lx != 0x%lx.\n", fname, rc, offset); + perror("seek file"); + return -EIO; + } + } + /* read data from file into memory buffer */ + rc = read(fd, buf, bytes); + + if (rc != bytes) { + fprintf(stderr, "%s, R off 0x%lx, 0x%lx != 0x%lx.\n", fname, count, rc, bytes); + perror("read file"); + return -EIO; + } + + count += bytes; + buf += bytes; + offset += bytes; + } + + if (count != size) { + fprintf(stderr, "%s, R failed 0x%lx != 0x%lx.\n", fname, count, size); + return -EIO; + } + return count; +} + +ssize_t write_from_buffer(char* fname, int fd, char* buffer, uint64_t size, uint64_t base) +{ + ssize_t rc; + uint64_t count = 0; + char* buf = buffer; + off_t offset = base; + + while (count < size) { + uint64_t bytes = size - count; + + if (bytes > RW_MAX_SIZE) + bytes = RW_MAX_SIZE; + + if (offset) { + rc = lseek(fd, offset, SEEK_SET); + if (rc != offset) { + fprintf(stderr, "%s, seek off 0x%lx != 0x%lx.\n", fname, rc, offset); + perror("seek file"); + return -EIO; + } + } + + /* write data to file from memory buffer */ + rc = write(fd, buf, bytes); + if (rc != bytes) { + fprintf(stderr, "%s, W off 0x%lx, 0x%lx != 0x%lx.\n", fname, offset, rc, bytes); + perror("write file"); + return -EIO; + } + + count += bytes; + buf += bytes; + offset += bytes; + } + + if (count != size) { + fprintf(stderr, "%s, R failed 0x%lx != 0x%lx.\n", fname, count, size); + return -EIO; + } + return count; +} + +// [End] #include "dma_utils.c" =================================== + +int test_dma_enc_read(char* EncOut, EncIPConf Confparam) +{ + ssize_t rc; + + void* virt_addr; + + uint64_t size; + uint32_t writeval; + + uint32_t Z_val; + + uint16_t max_schedule, mb, id, bg, z_j, kb, z_a; + uint16_t z_set; + uint32_t ctrl_data; + uint32_t CB_num = CB_PROCESS_NUMBER; + + // this values should be given by Shane + max_schedule = 0; + mb = Confparam.mb; + id = CB_num; + bg = Confparam.BGSel - 1; + z_set = Confparam.z_set - 1; + z_j = Confparam.z_j; + + if (z_set == 0) + z_a = 2; + else if (z_set == 1) + z_a = 3; + else if (z_set == 2) + z_a = 5; + else if (z_set == 3) + z_a = 7; + else if (z_set == 4) + z_a = 9; + else if (z_set == 5) + z_a = 11; + else if (z_set == 6) + z_a = 13; + else + z_a = 15; + + if (bg == 0) + kb = 22; + else if (bg == 1) + kb = 10; + else if (bg == 2) + kb = 9; + else if (bg == 3) + kb = 8; + else + kb = 6; + mb = Confparam.kb_1 + kb; + Z_val = (unsigned int)(z_a << z_j); + ctrl_data = (max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (bg << 6) | (z_set << 3) | z_j; + uint32_t OutDataNUM = Z_val * mb; + uint32_t Out_dwNumItems_p128; + uint32_t Out_dwNumItems; + + if ((OutDataNUM & 0x7F) == 0) + Out_dwNumItems_p128 = OutDataNUM >> 5; + else + Out_dwNumItems_p128 = ((OutDataNUM >> 7) + 1) << 2; + Out_dwNumItems = ((Out_dwNumItems_p128 << 2) * CB_num); + size = Out_dwNumItems; + writeval = ctrl_data; + + /* calculate the virtual address to be accessed */ + virt_addr = map_base + OFFSET_ENC_OUT; + + /* swap 32-bit endianess if host is not little-endian */ + writeval = htoll(writeval); + *((uint32_t*)virt_addr) = writeval; + if (fd_enc_read < 0) { + fprintf(stderr, "unable to open device %s, %d.\n", dev_enc_read, fd_enc_read); + perror("open device"); + return -EINVAL; + } + + /* lseek & read data from AXI MM into buffer using SGDMA */ + rc = read_to_buffer(dev_enc_read, fd_enc_read, EncOut, size, 0); + if (rc < 0) + goto out; + + rc = 0; + +out: + + return rc; +} + +int test_dma_enc_write(char* data, EncIPConf Confparam) +{ + ssize_t rc; + void* virt_addr; + + uint64_t size; + uint32_t writeval; + + uint32_t Z_val; + uint16_t max_schedule, mb, id, bg, z_j, kb, z_a; + uint16_t z_set; + uint32_t ctrl_data; + uint32_t CB_num = CB_PROCESS_NUMBER; + + // this values should be given by Shane + max_schedule = 0; + + mb = Confparam.mb; + id = CB_num; + bg = Confparam.BGSel - 1; + z_set = Confparam.z_set - 1; + z_j = Confparam.z_j; + + if (z_set == 0) + z_a = 2; + else if (z_set == 1) + z_a = 3; + else if (z_set == 2) + z_a = 5; + else if (z_set == 3) + z_a = 7; + else if (z_set == 4) + z_a = 9; + else if (z_set == 5) + z_a = 11; + else if (z_set == 6) + z_a = 13; + else + z_a = 15; + + if (bg == 0) + kb = 22; + else if (bg == 1) + kb = 10; + else if (bg == 2) + kb = 9; + else if (bg == 3) + kb = 8; + else + kb = 6; + mb = Confparam.kb_1 + kb; + Z_val = (unsigned int)(z_a << z_j); + ctrl_data = (max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (bg << 6) | (z_set << 3) | z_j; + uint32_t InDataNUM = Z_val * kb; + uint32_t In_dwNumItems_p128; + uint32_t In_dwNumItems; + + if ((InDataNUM & 0x7F) == 0) + In_dwNumItems_p128 = InDataNUM >> 5; + else + In_dwNumItems_p128 = ((InDataNUM >> 7) + 1) << 2; + + In_dwNumItems = ((In_dwNumItems_p128 << 2) * CB_num); + size = In_dwNumItems; + writeval = ctrl_data; + + /* calculate the virtual address to be accessed */ + virt_addr = map_base + OFFSET_ENC_IN; + + /* swap 32-bit endianess if host is not little-endian */ + writeval = htoll(writeval); + *((uint32_t*)virt_addr) = writeval; + if (fd_enc_write < 0) { + fprintf(stderr, "unable to open device %s, %d.\n", dev_enc_write, fd_enc_write); + perror("open device"); + return -EINVAL; + } + + rc = write_from_buffer(dev_enc_write, fd_enc_write, data, size, 0); + if (rc < 0) + goto out; + rc = 0; + +out: + + return rc; +} + +// int test_dma_dec_read(unsigned int *DecOut, DecIPConf Confparam) +int test_dma_dec_read(char* DecOut, DecIPConf Confparam) +{ + ssize_t rc; + + void* virt_addr; + + uint64_t size; + uint32_t writeval; + + uint32_t Z_val; + + uint16_t max_schedule, mb, id, bg, z_j, kb, z_a, max_iter, sc_idx; + uint16_t z_set; + uint32_t ctrl_data; + uint32_t CB_num = Confparam.CB_num; + + // this values should be given by Shane + max_schedule = 0; + mb = Confparam.mb; + id = CB_num; + bg = Confparam.BGSel - 1; + z_set = Confparam.z_set - 1; + z_j = Confparam.z_j; + max_iter = 8; + sc_idx = 12; + + if (z_set == 0) + z_a = 2; + else if (z_set == 1) + z_a = 3; + else if (z_set == 2) + z_a = 5; + else if (z_set == 3) + z_a = 7; + else if (z_set == 4) + z_a = 9; + else if (z_set == 5) + z_a = 11; + else if (z_set == 6) + z_a = 13; + else + z_a = 15; + + if (bg == 0) + kb = 22; + else if (bg == 1) + kb = 10; + else if (bg == 2) + kb = 9; + else if (bg == 3) + kb = 8; + else + kb = 6; + + Z_val = (unsigned int)(z_a << z_j); + ctrl_data = + (max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (max_iter << 13) | (sc_idx << 9) | (bg << 6) | (z_set) << 3 | z_j; + + uint32_t OutDataNUM = Z_val * kb; + uint32_t Out_dwNumItems_p128; + uint32_t Out_dwNumItems; + + if (CB_num & 0x01) // odd cb number + { + if ((OutDataNUM & 0xFF) == 0) + Out_dwNumItems_p128 = OutDataNUM; + else + Out_dwNumItems_p128 = 256 * ((OutDataNUM / 256) + 1); + + Out_dwNumItems = (Out_dwNumItems_p128 * CB_num) >> 3; + } else { + if ((OutDataNUM & 0x7F) == 0) + Out_dwNumItems_p128 = OutDataNUM; + else + Out_dwNumItems_p128 = 128 * ((OutDataNUM / 128) + 1); + + Out_dwNumItems = (Out_dwNumItems_p128 * CB_num) >> 3; + if ((Out_dwNumItems & 0x1f) != 0) + Out_dwNumItems = ((Out_dwNumItems + 31) >> 5) << 5; + + } + size = Out_dwNumItems; + writeval = ctrl_data; + + /* calculate the virtual address to be accessed */ + virt_addr = map_base + OFFSET_DEC_OUT; + + /* swap 32-bit endianess if host is not little-endian */ + writeval = htoll(writeval); + *((uint32_t*)virt_addr) = writeval; + + if (fd_dec_read < 0) { + fprintf(stderr, "unable to open device %s, %d.\n", dev_dec_read, fd_dec_read); + perror("open device"); + return -EINVAL; + } + + /* lseek & read data from AXI MM into buffer using SGDMA */ + rc = read_to_buffer(dev_dec_read, fd_dec_read, DecOut, size, 0); + if (rc < 0) + goto out; + + rc = 0; + +out: + + return rc; +} + +// int test_dma_dec_write(unsigned int *data, DecIPConf Confparam) +int test_dma_dec_write(char* data, DecIPConf Confparam) +{ + ssize_t rc; + + void* virt_addr; + + uint64_t size; + uint32_t writeval; + + uint32_t Z_val; + uint16_t max_schedule, mb, id, bg, z_j, kb, z_a, max_iter, sc_idx; + uint16_t z_set; + uint32_t ctrl_data; + uint32_t CB_num = Confparam.CB_num; // CB_PROCESS_NUMBER_Dec;// + + // this values should be given by Shane + max_schedule = 0; + mb = Confparam.mb; + id = CB_num; + bg = Confparam.BGSel - 1; + z_set = Confparam.z_set - 1; + z_j = Confparam.z_j; + + max_iter = 8; + sc_idx = 12; + + if (z_set == 0) + z_a = 2; + else if (z_set == 1) + z_a = 3; + else if (z_set == 2) + z_a = 5; + else if (z_set == 3) + z_a = 7; + else if (z_set == 4) + z_a = 9; + else if (z_set == 5) + z_a = 11; + else if (z_set == 6) + z_a = 13; + else + z_a = 15; + + if (bg == 0) + kb = 22; + else if (bg == 1) + kb = 10; + else if (bg == 2) + kb = 9; + else if (bg == 3) + kb = 8; + else + kb = 6; + + Z_val = (unsigned int)(z_a << z_j); + ctrl_data = + (max_schedule << 30) | ((mb - kb) << 24) | (id << 19) | (max_iter << 13) | (sc_idx << 9) | (bg << 6) | (z_set) << 3 | z_j; + + uint32_t InDataNUM = Z_val * mb; + uint32_t In_dwNumItems_p128; + uint32_t In_dwNumItems; + + InDataNUM = Z_val * mb * 8; + if ((InDataNUM & 0x7F) == 0) + In_dwNumItems_p128 = InDataNUM; + else + In_dwNumItems_p128 = 128 * ((InDataNUM / 128) + 1); + + In_dwNumItems = (In_dwNumItems_p128 * CB_num) >> 3; + if ((In_dwNumItems & 0x1f) != 0) + In_dwNumItems = ((In_dwNumItems + 31) >> 5) << 5; + + size = In_dwNumItems; + writeval = ctrl_data; + + /* calculate the virtual address to be accessed */ + virt_addr = map_base + OFFSET_DEC_IN; + + /* swap 32-bit endianess if host is not little-endian */ + writeval = htoll(writeval); + *((uint32_t*)virt_addr) = writeval; + + if (fd_dec_write < 0) { + fprintf(stderr, "unable to open device %s, %d.\n", dev_dec_write, fd_dec_write); + perror("open device"); + return -EINVAL; + } + + rc = write_from_buffer(dev_dec_write, fd_dec_write, data, size, 0); + if (rc < 0) + goto out; + + rc = 0; + +out: + + return rc; +} + +void test_dma_init(devices_t devices) +{ + /* access width */ + char* device2 = devices.user_device; + + AssertFatal((fd = open(device2, O_RDWR | O_SYNC)) != -1, "CHARACTER DEVICE %s OPEN FAILURE\n", device2); + fflush(stdout); + + /* map one page */ + map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + AssertFatal(map_base != (void*)-1, "MEMORY MAP AT ADDRESS %p FAILED\n", map_base); + + void* virt_addr; + virt_addr = map_base + OFFSET_RESET; + *((uint32_t*)virt_addr) = 1; + + dev_enc_write = devices.enc_write_device; + dev_enc_read = devices.enc_read_device; + dev_dec_write = devices.dec_write_device; + dev_dec_read = devices.dec_read_device; + + fd_enc_write = open(dev_enc_write, O_RDWR); + fd_enc_read = open(dev_enc_read, O_RDWR); + fd_dec_write = open(dev_dec_write, O_RDWR); + fd_dec_read = open(dev_dec_read, O_RDWR); + + fflush(stdout); + +} + +void dma_reset(devices_t devices) +{ + char* device2 = devices.user_device; + + void* virt_addr; + virt_addr = map_base + PCIE_OFF; + *((uint32_t*)virt_addr) = 1; + + AssertFatal(munmap(map_base, MAP_SIZE) != -1, "munmap failure"); + close(fd_enc_write); + close(fd_enc_read); + close(fd_dec_write); + close(fd_dec_read); + close(fd); + + AssertFatal((fd = open(device2, O_RDWR | O_SYNC)) != -1, "CHARACTER DEVICE %s OPEN FAILURE\n", device2); + fflush(stdout); + + /* map one page */ + map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + AssertFatal(map_base != (void*)-1, "MEMORY MAP AT ADDRESS %p FAILED\n", map_base); + + virt_addr = map_base + PCIE_OFF; + *((uint32_t*)virt_addr) = 1; + + virt_addr = map_base + OFFSET_RESET; + *((uint32_t*)virt_addr) = 1; + + dev_enc_write = devices.enc_write_device; + dev_enc_read = devices.enc_read_device; + dev_dec_write = devices.dec_write_device; + dev_dec_read = devices.dec_read_device; + + fd_enc_write = open(dev_enc_write, O_RDWR); + fd_enc_read = open(dev_enc_read, O_RDWR); + fd_dec_write = open(dev_dec_write, O_RDWR); + fd_dec_read = open(dev_dec_read, O_RDWR); + + fflush(stdout); +} + +void test_dma_shutdown() +{ + + void* virt_addr; + virt_addr = map_base + PCIE_OFF; + *((uint32_t*)virt_addr) = 1; + + AssertFatal(munmap(map_base, MAP_SIZE) != -1, "munmap failure"); + close(fd_enc_write); + close(fd_enc_read); + close(fd_dec_write); + close(fd_dec_read); + close(fd); + +} + +// reg_rx.c +int nrLDPC_decoder_FPGA_PYM(uint8_t* buf_in, uint8_t* buf_out, DecIFConf dec_conf) +{ + struct timespec ts_start0; // evaluate time from input setting to output setting including xdma + + int Zc; + int nRows; + int baseGraph; + int CB_num; + + DecIPConf Confparam; + int z_a, z_tmp; + int z_j = 0; + + + int input_CBoffset, output_CBoffset; + + uint8_t i_LS; + + devices_t devices = { + .user_device = dec_conf.user_device, + .enc_write_device = dec_conf.enc_write_device, + .enc_read_device = dec_conf.enc_read_device, + .dec_write_device = dec_conf.dec_write_device, + .dec_read_device = dec_conf.dec_read_device + }; + + static int init_flag = 0; + if (init_flag == 0) { + /*Init*/ + test_dma_init(devices); + init_flag = 1; + } else { + dma_reset(devices); + } + + clock_gettime(CLOCK_MONOTONIC, &ts_start0); // time start0 + // LDPC input parameter + Zc = dec_conf.Zc; // shifting size + nRows = dec_conf.nRows; // number of Rows + baseGraph = dec_conf.BG; // base graph + CB_num = dec_conf.numCB; // 31 number of code block + + // calc xdma LDPC parameter + // calc i_LS + if ((Zc % 15) == 0) + i_LS = 7; + else if ((Zc % 13) == 0) + i_LS = 6; + else if ((Zc % 11) == 0) + i_LS = 5; + else if ((Zc % 9) == 0) + i_LS = 4; + else if ((Zc % 7) == 0) + i_LS = 3; + else if ((Zc % 5) == 0) + i_LS = 2; + else if ((Zc % 3) == 0) + i_LS = 1; + else + i_LS = 0; + + // calc z_a + if (i_LS == 0) + z_a = 2; + else + z_a = i_LS * 2 + 1; + + // calc z_j + z_tmp = Zc / z_a; + while (z_tmp % 2 == 0) { + z_j = z_j + 1; + z_tmp = z_tmp / 2; + } + + // calc CB_num and mb + Confparam.CB_num = CB_num; + if (baseGraph == 1) + Confparam.mb = 22 + nRows; + else + Confparam.mb = 10 + nRows; + + // set BGSel, z_set, z_j + Confparam.BGSel = baseGraph; + Confparam.z_set = i_LS + 1; + Confparam.z_j = z_j; + + // Calc input CB offset + input_CBoffset = Zc * Confparam.mb * 8; + if ((input_CBoffset & 0x7F) == 0) + input_CBoffset = input_CBoffset / 8; + else + input_CBoffset = 16 * ((input_CBoffset / 128) + 1); + + // Calc output CB offset + output_CBoffset = Zc * (Confparam.mb - nRows); + if ((output_CBoffset & 0x7F) == 0) + output_CBoffset = output_CBoffset / 8; + else + output_CBoffset = 16 * ((output_CBoffset / 128) + 1); + + // LDPC accelerator start + // write into accelerator + if (test_dma_dec_write((char *)buf_in, Confparam) != 0) { + exit(1); + printf("write exit!!\n"); + } + + // read output of accelerator + if (test_dma_dec_read((char *)buf_out, Confparam) != 0) { + exit(1); + printf("read exit!!\n"); + } + + return 0; +} + diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.h b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.h new file mode 100644 index 0000000000..e908051156 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.h @@ -0,0 +1,67 @@ +/* + * 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.0 (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 PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.h + * \briefFPGA accelerator integrated into OAI (for one and multi code block) + * \author Sendren Xu, SY Yeh(fdragon), Hongming, Terng-Yin Hsu + * \date 2022-05-31 + * \version 5.0 + * \email: summery19961210@gmail.com + */ + +#ifndef __NRLDPC_CODING_XDMA_OFFLOAD__H_ + +#define __NRLDPC_CODING_XDMA_OFFLOAD__H_ + +#include + +#define DEVICE_NAME_DEFAULT_USER "/dev/xdma0_user" +#define DEVICE_NAME_DEFAULT_ENC_READ "/dev/xdma0_c2h_1" +#define DEVICE_NAME_DEFAULT_ENC_WRITE "/dev/xdma0_h2c_1" +#define DEVICE_NAME_DEFAULT_DEC_READ "/dev/xdma0_c2h_0" +#define DEVICE_NAME_DEFAULT_DEC_WRITE "/dev/xdma0_h2c_0" + +/** + \brief LDPC input parameter + \param Zc shifting size + \param Rows + \param baseGraph base graph + \param CB_num number of code block + \param numChannelLlrs input soft bits length, Zc x 66 - length of filler bits + \param numFillerBits filler bits length +*/ +typedef struct { + char *user_device, *enc_write_device, *enc_read_device, *dec_write_device, *dec_read_device; + unsigned char max_schedule; + unsigned char SetIdx; + int Zc; + unsigned char numCB; + unsigned char BG; + unsigned char max_iter; + int nRows; + int numChannelLls; + int numFillerBits; +} DecIFConf; + +int nrLDPC_decoder_FPGA_PYM(uint8_t *buf_in, uint8_t *buf_out, DecIFConf dec_conf); + +#endif // __NRLDPC_CODING_XDMA_OFFLOAD__H_ + diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/xdma_diag.h b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/xdma_diag.h new file mode 100644 index 0000000000..8ef498c770 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/xdma_diag.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2016-present, Xilinx, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license + * the terms of the BSD Licence are reported below: + * + * BSD License + * + * For Xilinx DMA IP software + * + * Copyright (c) 2016-present, Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name Xilinx nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MODULES_TXCTRL_INC_XDMA_DIAG_H_ +#define MODULES_TXCTRL_INC_XDMA_DIAG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + unsigned char max_schedule; // max_schedule = 0; + unsigned char mb; // mb = 32; + unsigned char CB_num; // id = CB_num; + unsigned char BGSel; // bg = 1; + unsigned char z_set; // z_set = 0; + unsigned char z_j; // z_j = 6; + unsigned char max_iter; // max_iter = 8; + unsigned char SetIdx; // sc_idx = 12; +} DecIPConf; + +typedef struct { + int SetIdx; + int NumCBSegm; + int PayloadLen; + int Z; + int z_set; + int z_j; + int Kbmax; + int BGSel; + unsigned mb; + unsigned char CB_num; + unsigned char kb_1; +} EncIPConf; + +typedef struct { + char *user_device, *enc_write_device, *enc_read_device, *dec_write_device, *dec_read_device; +} devices_t; + +/* ltoh: little to host */ +/* htol: little to host */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define ltohl(x) (x) +#define ltohs(x) (x) +#define htoll(x) (x) +#define htols(x) (x) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define ltohl(x) __bswap_32(x) +#define ltohs(x) __bswap_16(x) +#define htoll(x) __bswap_32(x) +#define htols(x) __bswap_16(x) +#endif + +#define MAP_SIZE (32 * 1024UL) +#define MAP_MASK (MAP_SIZE - 1) + +#define SIZE_DEFAULT (32) +#define COUNT_DEFAULT (1) + +#define OFFSET_DEC_IN 0x0000 +#define OFFSET_DEC_OUT 0x0004 +#define OFFSET_ENC_IN 0x0008 +#define OFFSET_ENC_OUT 0x000c +#define OFFSET_RESET 0x0020 +#define PCIE_OFF 0x0030 + +#define CB_PROCESS_NUMBER 24 // add by JW +#define CB_PROCESS_NUMBER_Dec 24 + +// dma_from_device.c + +int test_dma_enc_read(char *EncOut, EncIPConf Confparam); +int test_dma_enc_write(char *data, EncIPConf Confparam); +int test_dma_dec_read(char *DecOut, DecIPConf Confparam); +int test_dma_dec_write(char *data, DecIPConf Confparam); +void test_dma_init(devices_t devices); +void test_dma_shutdown(); +void dma_reset(devices_t devices); + +#ifdef __cplusplus +} +#endif +#endif From 52d1d7b6e7b815ee93743fdaedf9e953da73625a Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Fri, 18 Oct 2024 15:25:52 +0200 Subject: [PATCH 45/83] chore(ci): explicitly support BSD-3-Clause as legit license in OAI Signed-off-by: Raphael Defosseux --- ci-scripts/checkCodingFormattingRules.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ci-scripts/checkCodingFormattingRules.sh b/ci-scripts/checkCodingFormattingRules.sh index b454ed4e91..f2e0c59a2d 100755 --- a/ci-scripts/checkCodingFormattingRules.sh +++ b/ci-scripts/checkCodingFormattingRules.sh @@ -73,9 +73,9 @@ then do IS_NFAPI=`echo $FILE | grep -E -c "nfapi/open-nFAPI|nfapi/oai_integration/vendor_ext" || true` IS_OAI_LICENCE_PRESENT=`grep -E -c "OAI Public License" $FILE || true` - IS_BSD_LICENCE_PRESENT=`grep -E -c "the terms of the BSD Licence|License-Identifier: BSD-2-Clause" $FILE || true` + IS_BSD_LICENCE_PRESENT=`grep -E -c "the terms of the BSD Licence|License-Identifier: BSD-2-Clause|License-Identifier: BSD-3-Clause" $FILE || true` IS_MIT_LICENCE_PRESENT=`grep -E -c "MIT License" $FILE || true` - IS_EXCEPTION=`echo $FILE | grep -E -c "common/utils/collection/tree.h|common/utils/collection/queue.h|openair2/UTIL/OPT/packet-rohc.h|openair3/NAS/COMMON/milenage.h|openair1/PHY/CODING/crc.h|openair1/PHY/CODING/crcext.h|openair1/PHY/CODING/types.h|openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c|openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_offload.h" || true` + IS_EXCEPTION=`echo $FILE | grep -E -c "common/utils/collection/tree.h|common/utils/collection/queue.h|openair2/UTIL/OPT/packet-rohc.h|openair3/NAS/COMMON/milenage.h|openair1/PHY/CODING/crc.h|openair1/PHY/CODING/crcext.h|openair1/PHY/CODING/types.h" || true` if [ $IS_OAI_LICENCE_PRESENT -eq 0 ] && [ $IS_BSD_LICENCE_PRESENT -eq 0 ] && [ $IS_MIT_LICENCE_PRESENT -eq 0 ] then if [ $IS_NFAPI -eq 0 ] && [ $IS_EXCEPTION -eq 0 ] @@ -184,9 +184,9 @@ do then IS_NFAPI=`echo $FULLFILE | grep -E -c "nfapi/open-nFAPI|nfapi/oai_integration/vendor_ext" || true` IS_OAI_LICENCE_PRESENT=`grep -E -c "OAI Public License" $FULLFILE || true` - IS_BSD_LICENCE_PRESENT=`grep -E -c "the terms of the BSD Licence|License-Identifier: BSD-2-Clause" $FULLFILE || true` + IS_BSD_LICENCE_PRESENT=`grep -E -c "the terms of the BSD Licence|License-Identifier: BSD-2-Clause|License-Identifier: BSD-3-Clause" $FULLFILE || true` IS_MIT_LICENCE_PRESENT=`grep -E -c "MIT License" $FULLFILE || true` - IS_EXCEPTION=`echo $FULLFILE | grep -E -c "common/utils/collection/tree.h|common/utils/collection/queue.h|openair2/UTIL/OPT/packet-rohc.h|openair3/NAS/COMMON/milenage.h|openair1/PHY/CODING/crc.h|openair1/PHY/CODING/crcext.h|openair1/PHY/CODING/types.h|openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c|openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_offload.h" || true` + IS_EXCEPTION=`echo $FULLFILE | grep -E -c "common/utils/collection/tree.h|common/utils/collection/queue.h|openair2/UTIL/OPT/packet-rohc.h|openair3/NAS/COMMON/milenage.h|openair1/PHY/CODING/crc.h|openair1/PHY/CODING/crcext.h|openair1/PHY/CODING/types.h" || true` if [ $IS_OAI_LICENCE_PRESENT -eq 0 ] && [ $IS_BSD_LICENCE_PRESENT -eq 0 ] && [ $IS_MIT_LICENCE_PRESENT -eq 0 ] then if [ $IS_NFAPI -eq 0 ] && [ $IS_EXCEPTION -eq 0 ] From 37bb58feb259e5243cf002778749049103edd53f Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Wed, 6 Nov 2024 15:43:46 +0100 Subject: [PATCH 46/83] fix(nrLDPC_coding_interface): lidldpc_slot_segment becomes default libldpc --- CMakeLists.txt | 21 ++++++++++--------- openair1/PHY/CODING/TESTBENCH/ldpctest.c | 2 +- .../nrLDPC_coding_segment_decoder.c | 2 +- .../nrLDPC_coding_xdma/nrLDPC_coding_xdma.c | 2 +- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e1528d1a62..8d569239e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -841,8 +841,8 @@ set(PHY_LDPC_OPTIM8SEGMULTI_SRC ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c ) -add_library(ldpc MODULE ${PHY_LDPC_OPTIM8SEGMULTI_SRC} ) -target_link_libraries(ldpc PRIVATE ldpc_gen_HEADERS) +add_library(ldpc_optim8segmulti MODULE ${PHY_LDPC_OPTIM8SEGMULTI_SRC} ) +target_link_libraries(ldpc_optim8segmulti PRIVATE ldpc_gen_HEADERS) set(PHY_LDPC_CUDA_SRC ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu @@ -895,7 +895,7 @@ add_library(coding MODULE ${PHY_TURBOSRC} ) add_library(dfts MODULE ${OPENAIR1_DIR}/PHY/TOOLS/oai_dfts.c ${OPENAIR1_DIR}/PHY/TOOLS/oai_dfts_neon.c) -add_library(ldpc_slot_segment MODULE ${PHY_NRLDPC_CODING_SEGMENT_SRC}) +add_library(ldpc MODULE ${PHY_NRLDPC_CODING_SEGMENT_SRC}) set(PHY_SRC_COMMON ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_tools_common.c @@ -1084,7 +1084,6 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/TOOLS/simde_operations.c ${PHY_POLARSRC} ${PHY_SMALLBLOCKSRC} - ${PHY_NR_CODINGIF} ${PHY_NRLDPC_CODINGIF} ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/pucch_rx.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/srs_rx.c @@ -1140,7 +1139,6 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/INIT/nr_init_ue.c ${PHY_POLARSRC} ${PHY_SMALLBLOCKSRC} - ${PHY_NR_CODINGIF} ${PHY_NRLDPC_CODINGIF} ) @@ -2072,7 +2070,7 @@ if(E2_AGENT) endif() -add_dependencies(nr-softmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc ldpc_slot_segment) +add_dependencies(nr-softmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti ldpc) if (ENABLE_LDPC_T2) add_dependencies(nr-softmodem ldpc_t2) @@ -2133,7 +2131,7 @@ target_link_libraries(nr-uesoftmodem PRIVATE pthread m CONFIG_LIB rt nr_ue_phy_m target_link_libraries(nr-uesoftmodem PRIVATE ${T_LIB}) target_link_libraries(nr-uesoftmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) -add_dependencies( nr-uesoftmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc ldpc_slot_segment) +add_dependencies( nr-uesoftmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti ldpc) if (ENABLE_LDPC_CUDA) add_dependencies(nr-uesoftmodem ldpc_cuda) add_dependencies(nr-softmodem ldpc_cuda) @@ -2201,7 +2199,7 @@ add_executable(ldpctest ${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/ldpctest.c ) -add_dependencies(ldpctest ldpc_orig ldpc_optim ldpc_optim8seg ldpc) +add_dependencies(ldpctest ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti) if (ENABLE_LDPC_CUDA) add_dependencies(ldpctest ldpc_cuda) endif() @@ -2307,7 +2305,10 @@ endif() if (ENABLE_LDPC_XDMA) add_dependencies(nr_ulsim ldpc_xdma) endif() -add_dependencies(nr_ulsim ldpc_slot_segment) +if (ENABLE_LDPC_CUDA) + add_dependencies(nr_ulsim ldpc_cuda) +endif() +add_dependencies(nr_ulsim ldpc ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti) target_link_libraries(nr_ulsim PRIVATE -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON nr_rrc CONFIG_LIB L2_NR HASHTABLE x2ap SECURITY ngap -lz -Wl,--end-group @@ -2374,7 +2375,7 @@ if (${T_TRACER}) PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU PHY_MEX L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE L2_UE_LTE_NR MAC_NR_COMMON MAC_UE_NR ngap CN_UTILS GTPV1U SCTP_CLIENT MME_APP LIB_NAS_UE NB_IoT SIMU OPENAIR0_LIB - ldpc_orig ldpc_optim ldpc_optim8seg ldpc_cl ldpc_cuda ldpc ldpc_slot_segment ldpc_t2 ldpc_xdma + ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti ldpc_cl ldpc_cuda ldpc ldpc_t2 ldpc_xdma dfts config_internals nr_common) if (TARGET ${i}) add_dependencies(${i} generate_T) diff --git a/openair1/PHY/CODING/TESTBENCH/ldpctest.c b/openair1/PHY/CODING/TESTBENCH/ldpctest.c index 1d4a31e655..1dad28c95e 100644 --- a/openair1/PHY/CODING/TESTBENCH/ldpctest.c +++ b/openair1/PHY/CODING/TESTBENCH/ldpctest.c @@ -403,7 +403,7 @@ int main(int argc, char *argv[]) { short block_length=8448; // decoder supports length: 1201 -> 1280, 2401 -> 2560 // default to check output inside ldpc, the NR version checks the outer CRC defined by 3GPP - char *ldpc_version = NULL; + char *ldpc_version = "_optim8segmulti"; /* version of the ldpc decoder library to use (XXX suffix to use when loading libldpc_XXX.so */ short max_iterations=5; int n_segments=1; diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c index 9264c7a5b6..e1fec76e23 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c @@ -291,7 +291,7 @@ int32_t nrLDPC_coding_init(void){ char *segment_shlibversion = NULL; paramdef_t LoaderParams[] = { - {"segment_shlibversion", NULL, 0, .strptr = &segment_shlibversion, .defstrval = "", TYPE_STRING, 0, NULL} + {"segment_shlibversion", NULL, 0, .strptr = &segment_shlibversion, .defstrval = "_optim8segmulti", TYPE_STRING, 0, NULL} }; config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "nrLDPC_coding_segment"); load_LDPClib(segment_shlibversion, &ldpc_interface_segment); diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c index 613c999042..057fb58f6a 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c @@ -103,7 +103,7 @@ int32_t nrLDPC_coding_init(void) char *encoder_shlibversion = NULL; paramdef_t LoaderParams[] = { {"num_threads_prepare", NULL, 0, .iptr = &num_threads_prepare_max, .defintval = 0, TYPE_INT, 0, NULL}, - {"encoder_shlibversion", NULL, 0, .strptr = &encoder_shlibversion, .defstrval = "", TYPE_STRING, 0, NULL}, + {"encoder_shlibversion", NULL, 0, .strptr = &encoder_shlibversion, .defstrval = "_optim8segmulti", TYPE_STRING, 0, NULL}, {"user_device", NULL, 0, .strptr = &user_device, .defstrval = DEVICE_NAME_DEFAULT_USER, TYPE_STRING, 0, NULL}, {"enc_read_device", NULL, 0, .strptr = &enc_read_device, .defstrval = DEVICE_NAME_DEFAULT_ENC_READ, TYPE_STRING, 0, NULL}, {"enc_write_device", NULL, 0, .strptr = &enc_write_device, .defstrval = DEVICE_NAME_DEFAULT_ENC_WRITE, TYPE_STRING, 0, NULL}, From 240aafeb14149ea1d27aaa64b0a067964093d24a Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Wed, 6 Nov 2024 15:44:36 +0100 Subject: [PATCH 47/83] fix(nrLDPC_coding_interface): use lidldpc_slot_t2 for CI --- .../xml_files/t2_offload_dec_nr_ulsim.xml | 18 +++++++------- .../xml_files/t2_offload_enc_nr_dlsim.xml | 24 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/ci-scripts/xml_files/t2_offload_dec_nr_ulsim.xml b/ci-scripts/xml_files/t2_offload_dec_nr_ulsim.xml index 7cbbbcaf14..808f7155b5 100644 --- a/ci-scripts/xml_files/t2_offload_dec_nr_ulsim.xml +++ b/ci-scripts/xml_files/t2_offload_dec_nr_ulsim.xml @@ -45,7 +45,7 @@ true nr_ulsim 100 - -n100 -s30 -S30.2 -m5 -r106 -R106 -C10 -o -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m5 -r106 -R106 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -63,7 +63,7 @@ true nr_ulsim 150 - -n100 -s30 -S30.2 -m15 -r106 -R106 -C10 -o -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m15 -r106 -R106 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -81,7 +81,7 @@ true nr_ulsim 250 - -n100 -s30 -S30.2 -m25 -r106 -R106 -C10 -o -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m25 -r106 -R106 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -99,7 +99,7 @@ true nr_ulsim 150 - -n100 -s30 -S30.2 -m5 -r273 -R273 -C10 -o -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m5 -r273 -R273 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -117,7 +117,7 @@ true nr_ulsim 350 - -n100 -s30 -S30.2 -m15 -r273 -R273 -C10 -o -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m15 -r273 -R273 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -135,7 +135,7 @@ true nr_ulsim 550 - -n100 -s30 -S30.2 -m25 -r273 -R273 -C10 -o -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m25 -r273 -R273 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -153,7 +153,7 @@ true nr_ulsim 250 - -n100 -s30 -S30.2 -m5 -r273 -R273 -C10 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m5 -r273 -R273 -C10 -W2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -171,7 +171,7 @@ true nr_ulsim 650 - -n100 -s30 -S30.2 -m15 -r273 -R273 -C10 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m15 -r273 -R273 -C10 -W2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -189,7 +189,7 @@ true nr_ulsim 1100 - -n100 -s30 -S30.2 -m25 -r273 -R273 -C10 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m25 -r273 -R273 -C10 -W2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 diff --git a/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml b/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml index c4dba5db6c..f1217ae737 100644 --- a/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml +++ b/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml @@ -46,7 +46,7 @@ true nr_dlsim 100 - -n100 -s30 -S30.2 -e5 -b106 -R106 -c -X4,5,6,7,8,9 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e5 -b106 -R106 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -64,7 +64,7 @@ true nr_dlsim 100 - -n100 -s30 -S30.2 -e15 -b106 -R106 -c -X4,5,6,7,8,9 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e15 -b106 -R106 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -82,7 +82,7 @@ true nr_dlsim 200 - -n100 -s30 -S30.2 -e25 -b106 -R106 -c -X4,5,6,7,8,9 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e25 -b106 -R106 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -100,7 +100,7 @@ true nr_dlsim 150 - -n100 -s30 -S30.2 -e5 -b273 -R273 -c -X4,5,6,7,8,9 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e5 -b273 -R273 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -118,7 +118,7 @@ true nr_dlsim 250 - -n100 -s30 -S30.2 -e15 -b273 -R273 -c -X4,5,6,7,8,9 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e15 -b273 -R273 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -136,7 +136,7 @@ true nr_dlsim 400 - -n100 -s30 -S30.2 -e25 -b273 -R273 -c -X4,5,6,7,8,9 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e25 -b273 -R273 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -154,7 +154,7 @@ true nr_dlsim 200 - -n100 -s30 -S30.2 -e5 -b273 -R273 -c -X4,5,6,7,8,9 -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e5 -b273 -R273 -X4,5,6,7,8,9 -x2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -172,7 +172,7 @@ true nr_dlsim 500 - -n100 -s30 -S30.2 -e15 -b273 -R273 -c -X4,5,6,7,8,9 -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e15 -b273 -R273 -X4,5,6,7,8,9 -x2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -190,7 +190,7 @@ true nr_dlsim 500 - -n100 -s30 -S30.2 -e25 -b273 -R273 -c -X4,5,6,7,8,9 -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e25 -b273 -R273 -X4,5,6,7,8,9 -x2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -208,7 +208,7 @@ true nr_dlsim 200 - -n100 -s30 -S30.2 -e5 -b273 -R273 -c -X4,5,6,7,8,9 -x2 -z4 -y4 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e5 -b273 -R273 -X4,5,6,7,8,9 -x2 -z4 -y4 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -226,7 +226,7 @@ true nr_dlsim 300 - -n100 -s30 -S30.2 -e15 -b273 -R273 -c -X4,5,6,7,8,9 -x2 -z4 -y4 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e15 -b273 -R273 -X4,5,6,7,8,9 -x2 -z4 -y4 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 @@ -244,6 +244,6 @@ true nr_dlsim 450 - -n100 -s30 -S30.2 -e25 -b273 -R273 -c -X4,5,6,7,8,9 -x2 -z4 -y4 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e25 -b273 -R273 -X4,5,6,7,8,9 -x2 -z4 -y4 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 From 97614d182f2f945f4a1434696dde2340fd2091a4 Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Wed, 9 Oct 2024 14:46:13 +0200 Subject: [PATCH 48/83] feat(nrLDPC_coding_interface): Documentation --- doc/LDPC_T2_OFFLOAD_SETUP.md | 36 ++-- doc/LDPC_XDMA_offload_setup.md | 161 ++++++++++++++++++ openair1/PHY/CODING/DOC/LDPCImplementation.md | 141 +++++++++++++-- 3 files changed, 314 insertions(+), 24 deletions(-) create mode 100644 doc/LDPC_XDMA_offload_setup.md diff --git a/doc/LDPC_T2_OFFLOAD_SETUP.md b/doc/LDPC_T2_OFFLOAD_SETUP.md index 93d72284f9..24d36e39cf 100644 --- a/doc/LDPC_T2_OFFLOAD_SETUP.md +++ b/doc/LDPC_T2_OFFLOAD_SETUP.md @@ -74,11 +74,6 @@ If DPDK library was installed into custom path, you have to point to the right d ``` export PKG_CONFIG_PATH=/opt/dpdk-t2/lib64/pkgconfig/:$PKG_CONFIG_PATH ``` -## Setup of T2-related DPDK EAL parameters -To configure T2-related DPDK Environment Abstraction Layer (EAL) parameters, you can set the following parameters via the command line: -- `ldpc_offload.dpdk_dev` - **mandatory** parameter, specifies PCI address of the T2 card. PCI address of the T2 card can be detected by `lspci | grep "Xilinx"` command. -- `ldpc_offload.dpdk_cores_list` - CPU cores assigned to DPDK for T2 processing, by default set to *11-12*. Ensure that the CPU cores specified in *ldpc_offload.dpdk_cores_list* are available and not used by other processes to avoid conflicts. -- `ldpc_offload.dpdk_prefix` - DPDK shared data file prefix, by default set to *b6* # OAI Build OTA deployment is precisely described in the following tutorial: @@ -106,14 +101,35 @@ Shared object file *libldpc_t2.so* is created during the compilation. This objec *Required poll mode driver has to be present on the host machine and required DPDK version has to be installed on the host, prior to the build of OAI* +# Setup of T2-related DPDK EAL parameters +To configure T2-related DPDK Environment Abstraction Layer (EAL) parameters, you can set the following parameters via the command line of PHY simulators or softmodem: +- `nrLDPC_coding_t2.dpdk_dev` - **mandatory** parameter, specifies PCI address of the T2 card. PCI address of the T2 card can be detected by `lspci | grep "Xilinx"` command. +- `nrLDPC_coding_t2.dpdk_core_list` - **mandatory** parameter, specifies CPU cores assigned to DPDK for T2 processing. Ensure that the CPU cores specified in *nrLDPC_coding_t2.dpdk_core_list* are available and not used by other processes to avoid conflicts. +- `nrLDPC_coding_t2.dpdk_prefix` - DPDK shared data file prefix, by default set to *b6*. + +**Note:** These parameters can also be provided in a configuration file: +``` +nrLDPC_coding_t2 : { + dpdk_dev : "41:00.0"; + dpdk_core_list : "14-15"; +}; + +loader : { + ldpc : { + shlibversion : "_t2"; + }; +}; +``` + # 5G PHY simulators + ## nr_ulsim test -Offload of the channel decoding to the T2 card is in nr_ulsim specified by *-o* option. Example command for running nr_ulsim with LDPC decoding offload to the T2 card: +Offload of the channel decoding to the T2 card is in nr_ulsim specified by *--loader.ldpc.shlibversion _t2* option. Example command for running nr_ulsim with LDPC decoding offload to the T2 card: ``` cd ~/openairinterface5g source oaienv cd cmake_targets/ran_build/build -sudo ./nr_ulsim -n100 -s20 -m20 -r273 -R273 -o --ldpc_offload.dpdk_dev 01:00.0 +sudo ./nr_ulsim -n100 -s20 -m20 -r273 -R273 --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev 01:00.0 --nrLDPC_coding_t2.dpdk_core_list 0-1 ``` ## nr_dlsim test Offload of the channel encoding to the AMD Xilinx T2 card is in nr_dlsim specified by *-c* option. Example command for running nr_dlsim with LDPC encoding offload to the T2 card: @@ -121,18 +137,18 @@ Offload of the channel encoding to the AMD Xilinx T2 card is in nr_dlsim specifi cd ~/openairinterface5g source oaienv cd cmake_targets/ran_build/build -sudo ./nr_dlsim -n300 -s30 -R 106 -e 27 -c --ldpc_offload.dpdk_dev 01:00.0 +sudo ./nr_dlsim -n300 -s30 -R 106 -e 27 --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev 01:00.0 --nrLDPC_coding_t2.dpdk_core_list 0-1 ``` # OTA test -Offload of the channel encoding and decoding to the AMD Xilinx T2 card is enabled by *--ldpc-offload-enable* option. +Offload of the channel encoding and decoding to the AMD Xilinx T2 card is enabled by *--loader.ldpc.shlibversion _t2* option. ## Run OAI gNB with USRP B210 ``` cd ~/openairinterface5g source oaienv cd cmake_targets/ran_build/build -sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --ldpc-offload-enable --ldpc_offload.dpdk_dev 01:00.0 +sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev 01:00.0 --nrLDPC_coding_t2.dpdk_core_list 0-1 ``` # Limitations diff --git a/doc/LDPC_XDMA_offload_setup.md b/doc/LDPC_XDMA_offload_setup.md new file mode 100644 index 0000000000..e32a414f88 --- /dev/null +++ b/doc/LDPC_XDMA_offload_setup.md @@ -0,0 +1,161 @@ +# LDPC offload with the XDMA driver + +[TOC] + +This documentation aims to provide a tutorial for using Xilinx PCIe-XDMA based FPGA LDPC decoding within OAI. LDPC decoding is offloaded to FPGA. + +## XDMA Driver Build & Install + +- Get XDMA driver source +```bash +git clone https://github.com/Xilinx/dma_ip_drivers.git +cd dma_ip_drivers/XDMA/linux-kernel +``` +The *xdma_driver* directory contains the following: + +```bash +dma_ip_drivers/XDMA/linux-kernel/ +├── COPYING +├── include +├── LICENSE +├── readme.txt +├── RELEASE +├── tests +├── tools +└── xdma +``` + +Before building the driver, ensure that your system recognizes the Xilinx device. You can check this using the `lspci` command: + +```bash +$ lspci | grep Xilinx +01:00.0 Serial controller: Xilinx Corporation Device 8038 +``` + +Building and Installing the Driver + +```bash +cd ~/dma_ip_drivers/XDMA/linux-kernel/xdma +make clean +make +# install to make the driver loading automatically at system startup +sudo make install +``` + +Load the Driver + +```bash +cd ~/dma_ip_drivers/XDMA/linux-kernel/tests +sudo ./load_driver.sh +``` + +## OAI Build + +```bash +# Get openairinterface5g source code +git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git ~/openairinterface5g +cd ~/openairinterface5g + +# Install OAI dependencies +cd ~/openairinterface5g/cmake_targets +./build_oai -I + +# Build OAI gNB & UE +cd ~/openairinterface5g +source oaienv +cd cmake_targets +./build_oai --ninja -w SIMU --gNB --nrUE -P --build-lib "ldpc_xdma" -C -c +``` + +Shared object file *libldpc_xdma.so* is created during the compilation. This object is conditionally compiled. Selection of the library to compile is done using `--build-lib ldpc_xdma`. + +## 5G PHY simulators + +The simulated test uses the option `--loader.ldpc.shlibversion _xdma` to select the XDMA version for loading into the LDPC interface. Additionally, the option `--nrLDPC_coding_xdma.num_threads_prepare` is used to specify the number of threads for preparing data before the LDPC processing, specifically for the deinterleaving and rate matching parts. + +Another way to activate the feature is to add the `xdma.conf` file with the following content: + +``` +nrLDPC_coding_xdma : { + num_threads_prepare : 2; +}; + +loader : { + ldpc : { + shlibversion : "_xdma"; + }; +}; + +``` + +and use option `-O xdma.conf`. + +### nr_ulsim test + +Example command for running nr_ulsim with LDPC decoding offload to the FPGA: + +```bash +cd ~/openairinterface5g/cmake_targets/ran_build/build +sudo ./nr_ulsim -n100 -m28 -r273 -R273 -s22 -I10 -C8 -P --loader.ldpc.shlibversion _xdma --nrLDPC_coding_xdma.num_threads_prepare 2 +``` + +or + +``` +sudo ./nr_ulsim -n100 -m28 -r273 -R273 -s22 -I10 -C8 -P -O xdma.conf +``` + +## Run + +Both gNB and nrUE use the option `--loader.ldpc.shlibversion _xdma` to select the XDMA version for loading into the LDPC interface and `--nrLDPC_coding_xdma.num_threads_prepare` to specify the number of threads for preparing data before the LDPC processing, specifically for the deinterleaving and rate matching parts. + +Another way to activate the feature is to add the following content to the `.conf` file you want to use: + +``` +nrLDPC_coding_xdma : { + num_threads_prepare : 2; +}; + +loader : { + ldpc : { + shlibversion : "_xdma"; + }; +}; + +``` + +and use option `-O *.conf`. + +### gNB + +Example command using rfsim: + +```bash +cd ~/openairinterface5g/cmake_targets/ran_build/build +sudo ./nr-softmodem --rfsim --log_config.global_log_options level,nocolor,time -O ../../../ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.conf --loader.ldpc.shlibversion _xdma --nrLDPC_coding_xdma.num_threads_prepare 2 +``` + +or + +```bash +sudo ./nr-softmodem --rfsim --log_config.global_log_options level,nocolor,time -O ../../../ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.conf +``` + +if you have added the configuration to the `.conf` file. + +### UE + +Example command using rfsim: + +```bash +cd ~/openairinterface5g/cmake_targets/ran_build/build +sudo ./nr-uesoftmodem --rfsim -r 106 --numerology 1 --band 78 -C 3319680000 --ue-nb-ant-tx 1 --ue-nb-ant-rx 1 -O ../../../ci-scripts/conf_files/nrue1.uicc.cluCN.conf --rfsimulator.serveraddr 10.201.1.100 --loader.ldpc.shlibversion _xdma --nrLDPC_coding_xdma.num_threads_prepare 2 +``` + +or + +```bash +sudo ./nr-uesoftmodem --rfsim -r 106 --numerology 1 --band 78 -C 3319680000 --ue-nb-ant-tx 1 --ue-nb-ant-rx 1 -O ../../../ci-scripts/conf_files/nrue1.uicc.cluCN.conf --rfsimulator.serveraddr 10.201.1.100 +``` + +if you have added the configuration to the `.conf` file. diff --git a/openair1/PHY/CODING/DOC/LDPCImplementation.md b/openair1/PHY/CODING/DOC/LDPCImplementation.md index 758f918963..f5260e4d0a 100644 --- a/openair1/PHY/CODING/DOC/LDPCImplementation.md +++ b/openair1/PHY/CODING/DOC/LDPCImplementation.md @@ -1,21 +1,134 @@ -# LDPC coder/decoder implementation -The LDPC coder and decoder are implemented in a shared library, dynamically loaded at run-time using the [oai shared library loader](file://../../../../common/utils/DOC/loader.md). The code loading the LDPC library is in [nrLDPC_load.c](file://../nrLDPC_load.c), in function `load_nrLDPClib`, which must be called at init time. +# LDPC coding implementation +The LDPC encoder and decoder are implemented in a shared library, dynamically loaded at run-time using the [oai shared library loader](file://../../../../common/utils/DOC/loader.md). +Two types of library are available with two different interfaces. There are libraries implementing the encoder and decoder of code segments and libraries implementing the encoder and decoder of slots. -## Selecting the LDPC library at run time +## LDPC slot coding +The interface of the library is defined in [nrLDPC_coding_interface.h](file://../nrLDPC_coding/nrLDPC_coding_interface.h). +The code loading the LDPC library is in [nrLDPC_coding_interface_load.c](file://../nrLDPC_coding/nrLDPC_coding_interface_load.c), in function `load_nrLDPC_coding_interface`, which must be called at init time. + +### Selecting the LDPC library at run time + +By default the function `int load_nrLDPC_coding_interface(void)` looks for `libldpc.so`.\ +This default behavior can be changed using the oai loader configuration options in the configuration file or from the command line as shown below: + +#### Examples of ldpc shared lib selection when running nr softmodem's: + +loading default `libldpc.so`: + +``` +./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5 +....................... +[CONFIG] loader.ldpc.shlibversion set to default value "" +[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (2 to default value) +shlib_path libldpc.so +[LOADER] library libldpc.so successfully loaded +........................ +``` + +`libldpc.so` has its decoder implemented in [nrLDPC_coding_segment_decoder.c](file://../nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c).\ +Its encoder is implemented in [nrLDPC_coding_segment_encoder.c](file://../nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c). + +*Note: The segment coding library `libldpc.so` is an adaptation layer between the slot coding interface and a segment coding library.* +*The segment coding library is `libldpc_optim8segmulti.so` by default but it can be chosen with option `--nrLDPC_coding_segment.segment_shlibversion` followed by the library version - like with `--loader.ldpc.shlibversion` in the slot coding case -* + +loading `libldpc_t2.so` instead of `libldpc.so`: + +`make ldpc_t2` + +This command creates the `libldpc_t2.so` shared library. + +``` +Building C object CMakeFiles/ldpc_t2.dir/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c.o +Linking C shared module libldpc_t2.so +``` + +At runtime, to successfully use the T2 board, you need to install vendor specific drivers and tools.\ +Please refer to the dedicated documentation at [LDPC_T2_OFFLOAD_SETUP.md](file://../../../../doc/LDPC_T2_OFFLOAD_SETUP.md). + +`./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev 01:00.0 --nrLDPC_coding_t2.dpdk_core_list 0-1` + +``` + +....................... +[CONFIG] loader.ldpc.shlibversion set to default value "" +[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (1 to default value) +[CONFIG] shlibversion set to _t2 from command line +[CONFIG] loader.ldpc 1 options set from command line +shlib_path libldpc_t2.so +[LOADER] library libldpc_t2.so successfully loaded +........................ +``` + +`libldpc_t2.so` has its decoder and its encoder implemented in [nrLDPC_coding_t2.c](file://../nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c). + +loading `libldpc_xdma.so` instead of `libldpc.so`: + +`make ldpc_xdma` or `ninja ldpc_xdma` + +This command creates the `libldpc_xdma.so` shared library. + +``` +ninja ldpc_xdma +[2/2] Linking C shared module libldpc_xdma.so +``` + +At runtime, to successfully use the xdma, you need to install vendor specific drivers and tools.\ +Please refer to the dedicated documentation at [LDPC_XDMA_OFFLOAD_SETUP.md](file://../../../../doc/LDPC_XDMA_OFFLOAD_SETUP.md). + +`./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _xdma --nrLDPC_coding_xdma.num_threads_prepare 2` + +``` +....................... +[CONFIG] loader.ldpc.shlibversion set to default value "" +[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (1 to default value) +[CONFIG] shlibversion set to _xdma from command line +[CONFIG] loader.ldpc 1 options set from command line +shlib_path libldpc_xdma.so +[LOADER] library libldpc_xdma.so successfully loaded +........................ +``` + +`libldpc_xdma.so` has its decoder implemented in [nrLDPC_coding_xdma.c](file://../nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c).\ +Its encoder is implemented in [nrLDPC_coding_segment_encoder.c](file://../nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c). + +*Note: `libldpc_xdma.so` relies on a segment coding library for encoding.* +*The segment coding library is `libldpc.so` by default but it can be chosen with option `--nrLDPC_coding_xdma.encoder_shlibversion` followed by the library version - like with `--loder.ldpc.shlibversion` in the segment coding case above -* + +#### Examples of ldpc shared lib selection when running ldpctest: + +Slot coding libraries cannot be used yet within ldpctest. + +But they can be used within nr_ulsim, nr_dlsim, nr_ulschsim and nr_dlschsim.\ +In these PHY simulators, using the slot coding libraries is enabled in the exact same way as in nr-softmodem. + +### LDPC libraries +Libraries implementing the slotwise LDPC coding must be named `libldpc<_version>.so`. They must implement four functions: `nrLDPC_coding_init`, `nrLDPC_coding_shutdown`, `nrLDPC_coding_decoder` and `nrLDPC_coding_encoder`. The prototypes for these functions is defined in [nrLDPC_coding_interface.h](file://../nrLDPC_coding/nrLDPC_coding_interface.h). + +`libldpc.so` is completed. + +`libldpc_t2.so` is completed. + +`libldpc_xdma.so` is completed. + +## LDPC segment coding +The interface of the library is defined in [nrLDPC_defs.h](file://../nrLDPC_defs.h). +The code loading the LDPC library is in [nrLDPC_load.c](file://../nrLDPC_load.c), in function `load_nrLDPClib`, which must be called at init time. + +### Selecting the LDPC library at run time By default the function `int load_nrLDPClib(void)` looks for `libldpc.so`, this default behavior can be changed using the oai loader configuration options in the configuration file or from the command line as shown below: #### Examples of ldpc shared lib selection when running nr softmodem's: -loading `libldpc_optim8seg.so` instead of `libldpc.so`: +loading `libldpc_optim8seg.so` instead of `libldpc_optim8segmulti.so`: ``` -./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5 --loader.ldpc.shlibversion _optim8seg +./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5 --nrLDPC_coding_segment.segment_shlibversion _optim8seg ....................... -[CONFIG] loader.ldpc.shlibversion set to default value "" -[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (1 to default value) -[CONFIG] shlibversion set to _optim8seg from command line -[CONFIG] loader.ldpc 1 options set from command line +[CONFIG] nrLDPC_coding_segment.segment_shlibversion set to default value "_optim8segmulti" +[LIBCONFIG] nrLDPC_coding_segment: 1/1 parameters successfully set, (0 to default value) +[CONFIG] segment_shlibversion set to _optim8seg from command line +[CONFIG] nrLDPC_coding_segment 1 options set from command line [LOADER] library libldpc_optim8seg.so successfully loaded ........................ ``` @@ -46,7 +159,7 @@ Built target ldpc_cl At runtime, to successfully use hardware acceleration via OpenCL, you need to install vendor specific packages which deliver the required drivers and tools to make use of their GPU (Nvidia, Intel...) , fpga (Xilinx, Intel) or CPU (Intel, AMD, ARM...) through OpenCL. -`./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _cl` +`./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --nrLDPC_coding_segment.segment_shlibversion _cl` ``` ------------------------------------------------ @@ -81,12 +194,12 @@ At runtime, to successfully use hardware acceleration via OpenCL, you need to in ----------------------------------------------------------------- ``` -`./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim -O libconfig:/usr/local/oai/conf/nrue_sim.conf:dbgl5 --loader.ldpc.shlibversion _cl --log_config.hw_log_level info` +`./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim -O libconfig:/usr/local/oai/conf/nrue_sim.conf:dbgl5 --nrLDPC_coding_segment.segment_shlibversion _cl --log_config.hw_log_level info` ``` ............................................................ -[CONFIG] shlibversion set to _cl from command line -[CONFIG] loader.ldpc 1 options set from command line +[CONFIG] segment_shlibversion set to _cl from command line +[CONFIG] nrLDPC_coding_segment 1 options set from command line [LOADER] library libldpc_cl.so successfully loaded [HW] Platform 0, OpenCL profile FULL_PROFILE [HW] Platform 0, OpenCL version OpenCL 2.1 LINUX @@ -118,7 +231,7 @@ At runtime, to successfully use hardware acceleration via OpenCL, you need to in ------------------------------------------------------------ ``` -A mechanism to select ldpc implementation is also available in the `ldpctest` phy simulator via the `-v`option, which can be used to specify the version of the ldpc shared library to be used. +A mechanism to select ldpc implementation is also available in the `ldpctest` phy simulator via the `-v` option, which can be used to specify the version of the ldpc shared library to be used. #### Examples of ldpc shared lib selection when running ldpctest: From 23bfce8d91c6bab3443dd3285680b609d6f16a6e Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Wed, 13 Nov 2024 10:15:21 +0100 Subject: [PATCH 49/83] feat(nrLDPC_coding_interface): Move LDPC and Turdo coding libraries cmake lists in sub directories --- CMakeLists.txt | 158 +----------------- openair1/PHY/CMakeLists.txt | 1 + openair1/PHY/CODING/CMakeLists.txt | 94 +++++++++++ .../PHY/CODING/nrLDPC_coding/CMakeLists.txt | 3 + .../nrLDPC_coding_segment/CMakeLists.txt | 24 +++ .../nrLDPC_coding_t2/CMakeLists.txt | 38 +++++ .../nrLDPC_coding_xdma/CMakeLists.txt | 36 ++++ 7 files changed, 197 insertions(+), 157 deletions(-) create mode 100644 openair1/PHY/CODING/CMakeLists.txt create mode 100644 openair1/PHY/CODING/nrLDPC_coding/CMakeLists.txt create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/CMakeLists.txt create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/CMakeLists.txt create mode 100644 openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d569239e0..7093b17218 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -485,42 +485,6 @@ target_link_libraries(params_libconfig PRIVATE config_internals ${libconfig_LIBR add_library(shlib_loader OBJECT common/utils/load_module_shlib.c) target_link_libraries(shlib_loader PRIVATE CONFIG_LIB) -########################################################## - -# LDPC offload library - AMD T2 Accelerator Card -########################################################## - -add_boolean_option(ENABLE_LDPC_T2 OFF "Build support for LDPC Offload to T2 library" OFF) -if (ENABLE_LDPC_T2) - pkg_check_modules(LIBDPDK_T2 REQUIRED libdpdk=20.11.9) - find_library(PMD_T2 NAMES rte_baseband_accl_ldpc HINTS ${LIBDPDK_T2_LIBRARY_DIRS}) - if (NOT PMD_T2) - message(FATAL_ERROR "could not find poll-mode driver for AccelerComm T2 LDPC Offload (rte_baseband_accl_ldpc.so)") - endif() - message(STATUS "T2 build: use ${PMD_T2}") - set(PHY_NRLDPC_CODING_T2_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c - ) - add_library(ldpc_t2 MODULE ${PHY_NRLDPC_CODING_T2_SRC}) - set_target_properties(ldpc_t2 PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API") - target_link_libraries(ldpc_t2 PRIVATE ldpc_gen_HEADERS ${LIBDPDK_T2_LDFLAGS} ${PMD_T2}) -endif() - -########################################################## - -# LDPC offload library - XDMA -########################################################## -add_boolean_option(ENABLE_LDPC_XDMA OFF "Build support for LDPC Offload to XDMA library" OFF) -if (ENABLE_LDPC_XDMA) - set(PHY_NRLDPC_CODING_XDMA_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c - ) - add_library(ldpc_xdma MODULE ${PHY_NRLDPC_CODING_XDMA_SRC}) -endif() - include_directories ("${OPENAIR_DIR}/radio/COMMON") ############################################################## @@ -786,14 +750,6 @@ include_directories(${NFAPI_USER_DIR}) # Layer 1 ############################# -set(PHY_TURBOSRC - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_sse.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder.c -) set(PHY_POLARSRC ${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_polar_init.c ${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_bitwise_operations.c @@ -816,87 +772,16 @@ set(PHY_TURBOIF ${OPENAIR1_DIR}/PHY/CODING/coding_load.c ) -set(PHY_LDPC_ORIG_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c -) -add_library(ldpc_orig MODULE ${PHY_LDPC_ORIG_SRC} ) -target_link_libraries(ldpc_orig PRIVATE ldpc_gen_HEADERS) - -set(PHY_LDPC_OPTIM_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim.c - ) -add_library(ldpc_optim MODULE ${PHY_LDPC_OPTIM_SRC} ) -target_link_libraries(ldpc_optim PRIVATE ldpc_gen_HEADERS) - -set(PHY_LDPC_OPTIM8SEG_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8seg.c -) -add_library(ldpc_optim8seg MODULE ${PHY_LDPC_OPTIM8SEG_SRC} ) -target_link_libraries(ldpc_optim8seg PRIVATE ldpc_gen_HEADERS) - -set(PHY_LDPC_OPTIM8SEGMULTI_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c - ) -add_library(ldpc_optim8segmulti MODULE ${PHY_LDPC_OPTIM8SEGMULTI_SRC} ) -target_link_libraries(ldpc_optim8segmulti PRIVATE ldpc_gen_HEADERS) - -set(PHY_LDPC_CUDA_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c -) - -set(PHY_LDPC_CL_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c -) -add_custom_target( nrLDPC_decoder_kernels_CL - COMMAND gcc ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c -dD -DNRLDPC_KERNEL_SOURCE -E -o ${CMAKE_CURRENT_BINARY_DIR}/nrLDPC_decoder_kernels_CL.clc - SOURCES ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c -) -add_library(ldpc_cl MODULE ${PHY_LDPC_CL_SRC} ) -target_link_libraries(ldpc_cl OpenCL) -add_dependencies(ldpc_cl nrLDPC_decoder_kernels_CL) - set(PHY_NR_CODINGIF ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c ) -set(PHY_NRLDPC_CODING_SEGMENT_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c - ${PHY_NR_CODINGIF} -) - set(PHY_NRLDPC_CODINGIF ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface_load.c ) -############################################## -# Base CUDA setting -############################################## - -add_boolean_option(ENABLE_LDPC_CUDA OFF "Build support for CUDA" OFF) -if (ENABLE_LDPC_CUDA) - find_package(CUDA REQUIRED) - SET(CUDA_NVCC_FLAG "${CUDA_NVCC_FLAGS};-arch=sm_60;") - SET(CUDA_VERBOSE_BUILD ON) - cuda_add_library(ldpc_cuda MODULE ${PHY_LDPC_CUDA_SRC}) - set_target_properties(ldpc_cuda PROPERTIES CUDA_SEPARABLE_COMPILATION ON) - if (NOT CUDA_FOUND) - message(FATAL_ERROR "no CUDA found") - endif() -endif() - -add_library(coding MODULE ${PHY_TURBOSRC} ) - add_library(dfts MODULE ${OPENAIR1_DIR}/PHY/TOOLS/oai_dfts.c ${OPENAIR1_DIR}/PHY/TOOLS/oai_dfts_neon.c) -add_library(ldpc MODULE ${PHY_NRLDPC_CODING_SEGMENT_SRC}) - set(PHY_SRC_COMMON ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_tools_common.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/lte_mcs.c @@ -2070,16 +1955,6 @@ if(E2_AGENT) endif() -add_dependencies(nr-softmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti ldpc) - -if (ENABLE_LDPC_T2) - add_dependencies(nr-softmodem ldpc_t2) -endif() - -if (ENABLE_LDPC_XDMA) - add_dependencies(nr-softmodem ldpc_xdma) -endif() - # force the generation of ASN.1 so that we don't need to wait during the build target_link_libraries(nr-softmodem PRIVATE asn1_lte_rrc asn1_nr_rrc asn1_s1ap asn1_ngap asn1_m2ap asn1_m3ap asn1_x2ap asn1_f1ap asn1_lpp) @@ -2131,20 +2006,6 @@ target_link_libraries(nr-uesoftmodem PRIVATE pthread m CONFIG_LIB rt nr_ue_phy_m target_link_libraries(nr-uesoftmodem PRIVATE ${T_LIB}) target_link_libraries(nr-uesoftmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) -add_dependencies( nr-uesoftmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti ldpc) -if (ENABLE_LDPC_CUDA) - add_dependencies(nr-uesoftmodem ldpc_cuda) - add_dependencies(nr-softmodem ldpc_cuda) -endif() - -if (ENABLE_LDPC_T2) - add_dependencies(nr-uesoftmodem ldpc_t2) -endif() - -if (ENABLE_LDPC_XDMA) - add_dependencies(nr-uesoftmodem ldpc_xdma) -endif() - # force the generation of ASN.1 so that we don't need to wait during the build target_link_libraries(nr-uesoftmodem PRIVATE asn1_lte_rrc asn1_nr_rrc asn1_s1ap asn1_ngap asn1_m2ap asn1_m3ap asn1_x2ap asn1_f1ap asn1_lpp) @@ -2198,11 +2059,6 @@ add_executable(ldpctest ${PHY_NR_CODINGIF} ${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/ldpctest.c ) - -add_dependencies(ldpctest ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti) -if (ENABLE_LDPC_CUDA) - add_dependencies(ldpctest ldpc_cuda) -endif() target_link_libraries(ldpctest PRIVATE -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON -Wl,--end-group m pthread dl shlib_loader ${T_LIB} @@ -2299,17 +2155,6 @@ add_executable(nr_ulsim ${PHY_INTERFACE_DIR}/queue_t.c ) -if (ENABLE_LDPC_T2) - add_dependencies(nr_ulsim ldpc_t2) -endif() -if (ENABLE_LDPC_XDMA) - add_dependencies(nr_ulsim ldpc_xdma) -endif() -if (ENABLE_LDPC_CUDA) - add_dependencies(nr_ulsim ldpc_cuda) -endif() -add_dependencies(nr_ulsim ldpc ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti) - target_link_libraries(nr_ulsim PRIVATE -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON nr_rrc CONFIG_LIB L2_NR HASHTABLE x2ap SECURITY ngap -lz -Wl,--end-group m pthread ${T_LIB} ITTI dl shlib_loader nr_ue_phy_meas @@ -2368,14 +2213,13 @@ if (${T_TRACER}) #all "add_library" definitions ITTI lte_rrc nr_rrc s1ap x2ap m2ap m3ap f1ap params_libconfig oai_usrpdevif oai_bladerfdevif oai_lmssdrdevif oai_iqplayer - oai_eth_transpro oai_mobipass coding HASHTABLE UTIL OMG_SUMO + oai_eth_transpro oai_mobipass HASHTABLE UTIL OMG_SUMO SECURITY SCHED_LIB SCHED_NR_LIB SCHED_RU_LIB SCHED_UE_LIB SCHED_NR_UE_LIB default_sched remote_sched RAL NFAPI_LIB NFAPI_PNF_LIB NFAPI_VNF_LIB NFAPI_USER_LIB MISC_NFAPI_LTE_LIB MISC_NFAPI_NR_LIB PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU PHY_MEX L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE L2_UE_LTE_NR MAC_NR_COMMON MAC_UE_NR ngap CN_UTILS GTPV1U SCTP_CLIENT MME_APP LIB_NAS_UE NB_IoT SIMU OPENAIR0_LIB - ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti ldpc_cl ldpc_cuda ldpc ldpc_t2 ldpc_xdma dfts config_internals nr_common) if (TARGET ${i}) add_dependencies(${i} generate_T) diff --git a/openair1/PHY/CMakeLists.txt b/openair1/PHY/CMakeLists.txt index 8c055bf878..2d74e9aedc 100644 --- a/openair1/PHY/CMakeLists.txt +++ b/openair1/PHY/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(nr_phy_common) add_subdirectory(TOOLS) add_subdirectory(NR_TRANSPORT) +add_subdirectory(CODING) diff --git a/openair1/PHY/CODING/CMakeLists.txt b/openair1/PHY/CODING/CMakeLists.txt new file mode 100644 index 0000000000..5a319932e1 --- /dev/null +++ b/openair1/PHY/CODING/CMakeLists.txt @@ -0,0 +1,94 @@ +set(PHY_TURBOSRC + ${OPENAIR1_DIR}/PHY/CODING/3gpplte_sse.c + ${OPENAIR1_DIR}/PHY/CODING/3gpplte.c + ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c + ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c + ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c + ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder.c +) + +add_library(coding MODULE ${PHY_TURBOSRC} ) +set_target_properties(coding PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + +set(PHY_LDPC_ORIG_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c +) +add_library(ldpc_orig MODULE ${PHY_LDPC_ORIG_SRC} ) +set_target_properties(ldpc_orig PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +target_link_libraries(ldpc_orig PRIVATE ldpc_gen_HEADERS) + +set(PHY_LDPC_OPTIM_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim.c + ) +add_library(ldpc_optim MODULE ${PHY_LDPC_OPTIM_SRC} ) +set_target_properties(ldpc_optim PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +target_link_libraries(ldpc_optim PRIVATE ldpc_gen_HEADERS) + +set(PHY_LDPC_OPTIM8SEG_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8seg.c +) +add_library(ldpc_optim8seg MODULE ${PHY_LDPC_OPTIM8SEG_SRC} ) +set_target_properties(ldpc_optim8seg PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +target_link_libraries(ldpc_optim8seg PRIVATE ldpc_gen_HEADERS) + +set(PHY_LDPC_OPTIM8SEGMULTI_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c + ) +add_library(ldpc_optim8segmulti MODULE ${PHY_LDPC_OPTIM8SEGMULTI_SRC} ) +set_target_properties(ldpc_optim8segmulti PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +target_link_libraries(ldpc_optim8segmulti PRIVATE ldpc_gen_HEADERS) + +set(PHY_LDPC_CUDA_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c +) + +set(PHY_LDPC_CL_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c +) +add_custom_target( nrLDPC_decoder_kernels_CL + COMMAND gcc ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c -dD -DNRLDPC_KERNEL_SOURCE -E -o ${CMAKE_CURRENT_BINARY_DIR}/nrLDPC_decoder_kernels_CL.clc + SOURCES ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c +) +add_library(ldpc_cl MODULE ${PHY_LDPC_CL_SRC} ) +set_target_properties(ldpc_cl PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +target_link_libraries(ldpc_cl OpenCL) +add_dependencies(ldpc_cl nrLDPC_decoder_kernels_CL) + +############################################## +# Base CUDA setting +############################################## + +add_boolean_option(ENABLE_LDPC_CUDA OFF "Build support for CUDA" OFF) +if (ENABLE_LDPC_CUDA) + find_package(CUDA REQUIRED) + SET(CUDA_NVCC_FLAG "${CUDA_NVCC_FLAGS};-arch=sm_60;") + SET(CUDA_VERBOSE_BUILD ON) + cuda_add_library(ldpc_cuda MODULE ${PHY_LDPC_CUDA_SRC}) + set_target_properties(ldpc_cuda PROPERTIES CUDA_SEPARABLE_COMPILATION ON) + set_target_properties(ldpc_cuda PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + if (NOT CUDA_FOUND) + message(FATAL_ERROR "no CUDA found") + endif() +endif() + +add_dependencies(ldpctest ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti) +if (ENABLE_LDPC_CUDA) + add_dependencies(ldpctest ldpc_cuda) +endif() + +#ensure that the T header files are generated before targets depending on them +if (${T_TRACER}) + foreach(i coding ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti ldpc_cl ldpc_cuda) + if (TARGET ${i}) + add_dependencies(${i} generate_T) + endif() + endforeach(i) +endif (${T_TRACER}) + +add_subdirectory(nrLDPC_coding) diff --git a/openair1/PHY/CODING/nrLDPC_coding/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_coding/CMakeLists.txt new file mode 100644 index 0000000000..e60ca479bb --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(nrLDPC_coding_segment) +add_subdirectory(nrLDPC_coding_xdma) +add_subdirectory(nrLDPC_coding_t2) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/CMakeLists.txt new file mode 100644 index 0000000000..42dcf74607 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/CMakeLists.txt @@ -0,0 +1,24 @@ +set(PHY_NRLDPC_CODING_SEGMENT_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c + ${PHY_NR_CODINGIF} +) + +add_library(ldpc MODULE ${PHY_NRLDPC_CODING_SEGMENT_SRC}) +set_target_properties(ldpc PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + +add_dependencies(nr-softmodem ldpc) +add_dependencies(nr-uesoftmodem ldpc) +add_dependencies(nr_ulsim ldpc) +add_dependencies(nr_ulschsim ldpc) +add_dependencies(nr_dlsim ldpc) +add_dependencies(nr_dlschsim ldpc) + +if (${T_TRACER}) + add_dependencies(ldpc generate_T) +endif(${T_TRACER}) + +add_dependencies(ldpc ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti) +if (ENABLE_LDPC_CUDA) + add_dependencies(ldpc ldpc_cuda) +endif() diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/CMakeLists.txt new file mode 100644 index 0000000000..36504ff506 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/CMakeLists.txt @@ -0,0 +1,38 @@ +########################################################## + +# LDPC offload library - AMD T2 Accelerator Card +########################################################## + +add_boolean_option(ENABLE_LDPC_T2 OFF "Build support for LDPC Offload to T2 library" OFF) + +if (ENABLE_LDPC_T2) + + pkg_check_modules(LIBDPDK_T2 REQUIRED libdpdk=20.11.9) + + find_library(PMD_T2 NAMES rte_baseband_accl_ldpc HINTS ${LIBDPDK_T2_LIBRARY_DIRS}) + if (NOT PMD_T2) + message(FATAL_ERROR "could not find poll-mode driver for AccelerComm T2 LDPC Offload (rte_baseband_accl_ldpc.so)") + endif() + + message(STATUS "T2 build: use ${PMD_T2}") + set(PHY_NRLDPC_CODING_T2_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c + ) + + add_library(ldpc_t2 MODULE ${PHY_NRLDPC_CODING_T2_SRC}) + set_target_properties(ldpc_t2 PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API") + set_target_properties(ldpc_t2 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + target_link_libraries(ldpc_t2 PRIVATE ldpc_gen_HEADERS ${LIBDPDK_T2_LDFLAGS} ${PMD_T2}) + + add_dependencies(nr-softmodem ldpc_t2) + add_dependencies(nr-uesoftmodem ldpc_t2) + add_dependencies(nr_ulsim ldpc_t2) + add_dependencies(nr_ulschsim ldpc_t2) + add_dependencies(nr_dlsim ldpc_t2) + add_dependencies(nr_dlschsim ldpc_t2) + + if (${T_TRACER}) + add_dependencies(ldpc_t2 generate_T) + endif(${T_TRACER}) + +endif() diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/CMakeLists.txt new file mode 100644 index 0000000000..4b76a5dd94 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/CMakeLists.txt @@ -0,0 +1,36 @@ +########################################################## + +# LDPC offload library - XDMA +########################################################## + +add_boolean_option(ENABLE_LDPC_XDMA OFF "Build support for LDPC Offload to XDMA library" OFF) + +if (ENABLE_LDPC_XDMA) + + set(PHY_NRLDPC_CODING_XDMA_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c + ) + + add_library(ldpc_xdma MODULE ${PHY_NRLDPC_CODING_XDMA_SRC}) + set_target_properties(ldpc_xdma PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + + add_dependencies(nr-softmodem ldpc_xdma) + add_dependencies(nr-uesoftmodem ldpc_xdma) + add_dependencies(nr_ulsim ldpc_xdma) + add_dependencies(nr_ulschsim ldpc_xdma) + add_dependencies(nr_dlsim ldpc_xdma) + add_dependencies(nr_dlschsim ldpc_xdma) + + if (${T_TRACER}) + add_dependencies(ldpc_xdma generate_T) + endif(${T_TRACER}) + + add_dependencies(ldpc_xdma ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti) + if (ENABLE_LDPC_CUDA) + add_dependencies(ldpc_xdma ldpc_cuda) + endif() + +endif() From 0aeba914a0d86cbc8d7053af5cfcea8859cac0ec Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 27 Nov 2024 14:57:36 +0100 Subject: [PATCH 50/83] Cleanup in CMakeLists.txt - Remove all variables (like OPENAIR1), they serve no purpose and make unnecessarily long lines - Remove linking to T, it does not seem to be necessary - Avoid intermediate variables to keep sources, and declare libraries directly, making for shorter code --- openair1/PHY/CODING/CMakeLists.txt | 91 ++++++++----------- .../nrLDPC_coding_segment/CMakeLists.txt | 12 +-- .../nrLDPC_coding_t2/CMakeLists.txt | 9 +- .../nrLDPC_coding_xdma/CMakeLists.txt | 16 +--- 4 files changed, 46 insertions(+), 82 deletions(-) diff --git a/openair1/PHY/CODING/CMakeLists.txt b/openair1/PHY/CODING/CMakeLists.txt index 5a319932e1..c469a2b236 100644 --- a/openair1/PHY/CODING/CMakeLists.txt +++ b/openair1/PHY/CODING/CMakeLists.txt @@ -1,63 +1,52 @@ -set(PHY_TURBOSRC - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_sse.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder.c +add_library(coding MODULE + 3gpplte_sse.c + 3gpplte.c + 3gpplte_turbo_decoder_sse_8bit.c + 3gpplte_turbo_decoder_sse_16bit.c + 3gpplte_turbo_decoder_avx2_16bit.c + 3gpplte_turbo_decoder.c ) - -add_library(coding MODULE ${PHY_TURBOSRC} ) set_target_properties(coding PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -set(PHY_LDPC_ORIG_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c +add_library(ldpc_orig MODULE + nrLDPC_decoder/nrLDPC_decoder.c + nrLDPC_encoder/ldpc_encoder.c ) -add_library(ldpc_orig MODULE ${PHY_LDPC_ORIG_SRC} ) set_target_properties(ldpc_orig PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) target_link_libraries(ldpc_orig PRIVATE ldpc_gen_HEADERS) -set(PHY_LDPC_OPTIM_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim.c - ) -add_library(ldpc_optim MODULE ${PHY_LDPC_OPTIM_SRC} ) +add_library(ldpc_optim MODULE + nrLDPC_decoder/nrLDPC_decoder.c + nrLDPC_encoder/ldpc_encoder_optim.c +) set_target_properties(ldpc_optim PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) target_link_libraries(ldpc_optim PRIVATE ldpc_gen_HEADERS) -set(PHY_LDPC_OPTIM8SEG_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8seg.c +add_library(ldpc_optim8seg MODULE + nrLDPC_decoder/nrLDPC_decoder.c + nrLDPC_encoder/ldpc_encoder_optim8seg.c ) -add_library(ldpc_optim8seg MODULE ${PHY_LDPC_OPTIM8SEG_SRC} ) set_target_properties(ldpc_optim8seg PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) target_link_libraries(ldpc_optim8seg PRIVATE ldpc_gen_HEADERS) -set(PHY_LDPC_OPTIM8SEGMULTI_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c - ) -add_library(ldpc_optim8segmulti MODULE ${PHY_LDPC_OPTIM8SEGMULTI_SRC} ) +add_library(ldpc_optim8segmulti MODULE + nrLDPC_decoder/nrLDPC_decoder.c + nrLDPC_encoder/ldpc_encoder_optim8segmulti.c +) set_target_properties(ldpc_optim8segmulti PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) target_link_libraries(ldpc_optim8segmulti PRIVATE ldpc_gen_HEADERS) -set(PHY_LDPC_CUDA_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c +add_custom_target(nrLDPC_decoder_kernels_CL + COMMAND gcc nrLDPC_decoder/nrLDPC_decoder_CL.c -dD -DNRLDPC_KERNEL_SOURCE -E -o ${CMAKE_CURRENT_BINARY_DIR}/nrLDPC_decoder_kernels_CL.clc + SOURCES nrLDPC_decoder/nrLDPC_decoder_CL.c + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) - -set(PHY_LDPC_CL_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c +add_library(ldpc_cl MODULE + nrLDPC_decoder/nrLDPC_decoder_CL.c + nrLDPC_encoder/ldpc_encoder_optim8segmulti.c ) -add_custom_target( nrLDPC_decoder_kernels_CL - COMMAND gcc ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c -dD -DNRLDPC_KERNEL_SOURCE -E -o ${CMAKE_CURRENT_BINARY_DIR}/nrLDPC_decoder_kernels_CL.clc - SOURCES ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c -) -add_library(ldpc_cl MODULE ${PHY_LDPC_CL_SRC} ) set_target_properties(ldpc_cl PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -target_link_libraries(ldpc_cl OpenCL) +target_link_libraries(ldpc_cl PRIVATE OpenCL) add_dependencies(ldpc_cl nrLDPC_decoder_kernels_CL) ############################################## @@ -67,14 +56,17 @@ add_dependencies(ldpc_cl nrLDPC_decoder_kernels_CL) add_boolean_option(ENABLE_LDPC_CUDA OFF "Build support for CUDA" OFF) if (ENABLE_LDPC_CUDA) find_package(CUDA REQUIRED) - SET(CUDA_NVCC_FLAG "${CUDA_NVCC_FLAGS};-arch=sm_60;") - SET(CUDA_VERBOSE_BUILD ON) - cuda_add_library(ldpc_cuda MODULE ${PHY_LDPC_CUDA_SRC}) - set_target_properties(ldpc_cuda PROPERTIES CUDA_SEPARABLE_COMPILATION ON) - set_target_properties(ldpc_cuda PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) if (NOT CUDA_FOUND) message(FATAL_ERROR "no CUDA found") endif() + SET(CUDA_NVCC_FLAG "${CUDA_NVCC_FLAGS};-arch=sm_60;") + SET(CUDA_VERBOSE_BUILD ON) + cuda_add_library(ldpc_cuda MODULE + nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu + nrLDPC_encoder/ldpc_encoder_optim8segmulti.c + ) + set_target_properties(ldpc_cuda PROPERTIES CUDA_SEPARABLE_COMPILATION ON) + set_target_properties(ldpc_cuda PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) endif() add_dependencies(ldpctest ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti) @@ -82,13 +74,4 @@ if (ENABLE_LDPC_CUDA) add_dependencies(ldpctest ldpc_cuda) endif() -#ensure that the T header files are generated before targets depending on them -if (${T_TRACER}) - foreach(i coding ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti ldpc_cl ldpc_cuda) - if (TARGET ${i}) - add_dependencies(${i} generate_T) - endif() - endforeach(i) -endif (${T_TRACER}) - add_subdirectory(nrLDPC_coding) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/CMakeLists.txt index 42dcf74607..ca8ff03700 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/CMakeLists.txt +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/CMakeLists.txt @@ -1,10 +1,8 @@ -set(PHY_NRLDPC_CODING_SEGMENT_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c +add_library(ldpc MODULE + nrLDPC_coding_segment_decoder.c + nrLDPC_coding_segment_encoder.c ${PHY_NR_CODINGIF} ) - -add_library(ldpc MODULE ${PHY_NRLDPC_CODING_SEGMENT_SRC}) set_target_properties(ldpc PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) add_dependencies(nr-softmodem ldpc) @@ -14,10 +12,6 @@ add_dependencies(nr_ulschsim ldpc) add_dependencies(nr_dlsim ldpc) add_dependencies(nr_dlschsim ldpc) -if (${T_TRACER}) - add_dependencies(ldpc generate_T) -endif(${T_TRACER}) - add_dependencies(ldpc ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti) if (ENABLE_LDPC_CUDA) add_dependencies(ldpc ldpc_cuda) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/CMakeLists.txt index 36504ff506..5b89d36f38 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/CMakeLists.txt +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/CMakeLists.txt @@ -15,11 +15,8 @@ if (ENABLE_LDPC_T2) endif() message(STATUS "T2 build: use ${PMD_T2}") - set(PHY_NRLDPC_CODING_T2_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c - ) + add_library(ldpc_t2 MODULE nrLDPC_coding_t2.c) - add_library(ldpc_t2 MODULE ${PHY_NRLDPC_CODING_T2_SRC}) set_target_properties(ldpc_t2 PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API") set_target_properties(ldpc_t2 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) target_link_libraries(ldpc_t2 PRIVATE ldpc_gen_HEADERS ${LIBDPDK_T2_LDFLAGS} ${PMD_T2}) @@ -31,8 +28,4 @@ if (ENABLE_LDPC_T2) add_dependencies(nr_dlsim ldpc_t2) add_dependencies(nr_dlschsim ldpc_t2) - if (${T_TRACER}) - add_dependencies(ldpc_t2 generate_T) - endif(${T_TRACER}) - endif() diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/CMakeLists.txt index 4b76a5dd94..4e7d79f6d7 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/CMakeLists.txt +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/CMakeLists.txt @@ -7,14 +7,12 @@ add_boolean_option(ENABLE_LDPC_XDMA OFF "Build support for LDPC Offload to XDMA if (ENABLE_LDPC_XDMA) - set(PHY_NRLDPC_CODING_XDMA_SRC - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma_offload.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c + add_library(ldpc_xdma MODULE + nrLDPC_coding_xdma_offload.c + nrLDPC_coding_xdma.c + ../nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c + ../../nrLDPC_load.c ) - - add_library(ldpc_xdma MODULE ${PHY_NRLDPC_CODING_XDMA_SRC}) set_target_properties(ldpc_xdma PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) add_dependencies(nr-softmodem ldpc_xdma) @@ -24,10 +22,6 @@ if (ENABLE_LDPC_XDMA) add_dependencies(nr_dlsim ldpc_xdma) add_dependencies(nr_dlschsim ldpc_xdma) - if (${T_TRACER}) - add_dependencies(ldpc_xdma generate_T) - endif(${T_TRACER}) - add_dependencies(ldpc_xdma ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti) if (ENABLE_LDPC_CUDA) add_dependencies(ldpc_xdma ldpc_cuda) From 7bf6f3f276fa7f649748782c8915bfa518c75547 Mon Sep 17 00:00:00 2001 From: Romain Beurdouche Date: Thu, 12 Dec 2024 10:43:28 +0100 Subject: [PATCH 51/83] Simplify segment decoder and encoder interfaces More complex implementations will be achieved using the new reworked interface - t_nrLDPC_dec_params: remove F, Qm, rv and perCB - encoder_implemparams_t: remove Qm, Tbslbrm, G, rv and perCB --- .../nrLDPC_coding_segment_encoder.c | 7 ------- openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h | 13 ------------- openair1/PHY/CODING/nrLDPC_defs.h | 7 ------- 3 files changed, 27 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c index 2a9682d585..6c66edeb82 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c @@ -190,13 +190,6 @@ static int nrLDPC_prepare_TB_encoding(nrLDPC_slot_encoding_parameters_t *nrLDPC_ impp.output = nrLDPC_TB_encoding_parameters->segments->output; impp.K = nrLDPC_TB_encoding_parameters->K; impp.F = nrLDPC_TB_encoding_parameters->F; - impp.Qm = nrLDPC_TB_encoding_parameters->Qm; - impp.Tbslbrm = nrLDPC_TB_encoding_parameters->tbslbrm; - impp.G = nrLDPC_TB_encoding_parameters->G; - for (int r = 0; r < nrLDPC_TB_encoding_parameters->C; r++) { - impp.perCB[r].E_cb = nrLDPC_TB_encoding_parameters->segments[r].E; - } - impp.rv = nrLDPC_TB_encoding_parameters->rv_index; size_t const n_seg = (impp.n_segments / 8 + ((impp.n_segments & 7) == 0 ? 0 : 1)); diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h index 053f7ebf16..25e78a542a 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h @@ -78,15 +78,6 @@ typedef enum nrLDPC_outMode { nrLDPC_outMode_LLRINT8 /**< Single LLR value per int8_t output */ } e_nrLDPC_outMode; -/** - Structure containing LDPC parameters per CB -*/ -typedef struct nrLDPC_params_per_cb { - uint32_t E_cb; - uint8_t status_cb; - uint8_t* p_status_cb; -} nrLDPC_params_per_cb_t; - /** Structure containing LDPC decoder parameters. */ @@ -94,16 +85,12 @@ typedef struct nrLDPC_dec_params { uint8_t BG; /**< Base graph */ uint16_t Z; /**< Lifting size */ uint8_t R; /**< Decoding rate: Format 15,13,... for code rates 1/5, 1/3,... */ - uint16_t F; /**< Filler bits */ - uint8_t Qm; /**< Modulation */ - uint8_t rv; uint8_t numMaxIter; /**< Maximum number of iterations */ int E; e_nrLDPC_outMode outMode; /**< Output format */ int crc_type; int (*check_crc)(uint8_t* decoded_bytes, uint32_t n, uint8_t crc_type); uint8_t setCombIn; - nrLDPC_params_per_cb_t perCB[NR_LDPC_MAX_NUM_CB]; } t_nrLDPC_dec_params; /** diff --git a/openair1/PHY/CODING/nrLDPC_defs.h b/openair1/PHY/CODING/nrLDPC_defs.h index 628862c687..471498be74 100644 --- a/openair1/PHY/CODING/nrLDPC_defs.h +++ b/openair1/PHY/CODING/nrLDPC_defs.h @@ -57,13 +57,6 @@ typedef struct { uint32_t K; /// Number of "Filler" bits uint32_t F; - /// Modulation order - uint8_t Qm; - uint32_t Tbslbrm; - unsigned int G; - nrLDPC_params_per_cb_t perCB[NR_LDPC_MAX_NUM_CB]; - // Redundancy version index - uint8_t rv; task_ans_t *ans; } encoder_implemparams_t; From 5785bc18949cd1677a4b7f7d00c529bec3a61e5d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 25 Nov 2024 18:55:47 +0100 Subject: [PATCH 52/83] Msg4 RNTI not found: abort RA --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 29e4ea1122..c7faf78179 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1941,7 +1941,8 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, NR_UE_info_t *UE = find_nr_UE(&nr_mac->UE_info, ra->rnti); if (!UE) { - LOG_E(NR_MAC, "want to generate %s, but rnti %04x not in the table\n", ra_type_str, ra->rnti); + LOG_E(NR_MAC, "want to generate %s, but rnti %04x not in the table. Abort RA\n", ra_type_str, ra->rnti); + nr_clear_ra_proc(ra); return; } From c80821e5784e444ae45a2af2cce94aa49dc49669 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 5 Oct 2023 08:52:48 +0200 Subject: [PATCH 53/83] NR MAC: save total/used PRBs aggregate --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 5 +++++ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 55c86594cd..730e954f4b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -938,6 +938,9 @@ void nr_schedule_ue_spec(module_id_t module_id, NR_UEs_t *UE_info = &gNB_mac->UE_info; nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body; + const NR_BWP_t *initialDL = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; + gNB_mac->mac_stats.total_prb_aggregate += NRRIV2BW(initialDL->locationAndBandwidth, MAX_BWP_SIZE); + UE_iterator(UE_info->list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP; @@ -1252,6 +1255,7 @@ void nr_schedule_ue_spec(module_id_t module_id, T(T_GNB_MAC_RETRANSMISSION_DL_PDU_WITH_DATA, T_INT(module_id), T_INT(CC_id), T_INT(rnti), T_INT(frame), T_INT(slot), T_INT(current_harq_pid), T_INT(harq->round), T_BUFFER(harq->transportBlock, TBS)); UE->mac_stats.dl.total_rbs_retx += sched_pdsch->rbSize; + gNB_mac->mac_stats.used_prb_aggregate += sched_pdsch->rbSize; } else { /* initial transmission */ LOG_D(NR_MAC, "Initial HARQ transmission in %d.%d\n", frame, slot); uint8_t *buf = (uint8_t *) harq->transportBlock; @@ -1369,6 +1373,7 @@ void nr_schedule_ue_spec(module_id_t module_id, UE->mac_stats.dl.num_mac_sdu += sdus; UE->mac_stats.dl.current_rbs = sched_pdsch->rbSize; UE->mac_stats.dl.total_sdu_bytes += dlsch_total_bytes; + gNB_mac->mac_stats.used_prb_aggregate += sched_pdsch->rbSize; /* save retransmission information */ harq->sched_pdsch = *sched_pdsch; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 420445076f..641f6d93d1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -807,6 +807,11 @@ typedef struct { int8_t nvipc_poll_core; } nvipc_params_t; +typedef struct { + uint64_t total_prb_aggregate; + uint64_t used_prb_aggregate; +} mac_stats_t; + /*! \brief top level eNB MAC structure */ typedef struct gNB_MAC_INST_s { /// Ethernet parameters for northbound midhaul interface @@ -930,6 +935,8 @@ typedef struct gNB_MAC_INST_s { pthread_mutex_t sched_lock; + mac_stats_t mac_stats; + } gNB_MAC_INST; #endif /*__LAYER2_NR_MAC_GNB_H__ */ From f804a355ad34a5131afe661dedd9cc6a8e89f08a Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 8 Feb 2024 10:46:19 +0100 Subject: [PATCH 54/83] Trigger F1 UE context release if no UE context in RRC --- executables/nr-cuup.c | 3 +++ openair2/RRC/NR/rrc_gNB.c | 43 ++++++++++++++++++++++++--------------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/executables/nr-cuup.c b/executables/nr-cuup.c index 381e56bd2f..978486f261 100644 --- a/executables/nr-cuup.c +++ b/executables/nr-cuup.c @@ -145,6 +145,9 @@ f1ap_cudu_inst_t *getCxt(instance_t instanceP) return &fake; } configmodule_interface_t *uniqCfg = NULL; + +void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, uint32_t gNB_ue_ngap_id) { }; + int main(int argc, char **argv) { /// static configuration for NR at the moment diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index e8c7fcdc2c..9bf178afe2 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -106,6 +106,21 @@ extern RAN_CONTEXT_t RC; mui_t rrc_gNB_mui = 0; +typedef struct deliver_ue_ctxt_release_data_t { + gNB_RRC_INST *rrc; + f1ap_ue_context_release_cmd_t *release_cmd; + sctp_assoc_t assoc_id; +} deliver_ue_ctxt_release_data_t; + +static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id) +{ + DevAssert(deliver_pdu_data != NULL); + deliver_ue_ctxt_release_data_t *data = deliver_pdu_data; + data->release_cmd->rrc_container = (uint8_t*) buf; + data->release_cmd->rrc_container_length = size; + data->rrc->mac_rrc.ue_context_release_command(data->assoc_id, data->release_cmd); +} + ///---------------------------------------------------------------------------------------------------------------/// ///---------------------------------------------------------------------------------------------------------------/// @@ -1974,8 +1989,18 @@ static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p, sctp_as rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, req->gNB_CU_ue_id); // TODO what happens if no AMF connected? should also handle, set an_release true if (!ue_context_p) { - LOG_E(RRC, "could not find UE context for CU UE ID %u, aborting transaction\n", req->gNB_CU_ue_id); - // TODO just request the DU to release to make it happy + LOG_W(RRC, "could not find UE context for CU UE ID %u: auto-generate release command\n", req->gNB_CU_ue_id); + uint8_t buffer[RRC_BUF_SIZE] = {0}; + int size = do_NR_RRCRelease(buffer, RRC_BUF_SIZE, rrc_gNB_get_next_transaction_identifier(0)); + f1ap_ue_context_release_cmd_t ue_context_release_cmd = { + .gNB_CU_ue_id = req->gNB_CU_ue_id, + .gNB_DU_ue_id = req->gNB_DU_ue_id, + .cause = F1AP_CAUSE_RADIO_NETWORK, + .cause_value = 10, // 10 = F1AP_CauseRadioNetwork_normal_release + .srb_id = DCCH, + }; + deliver_ue_ctxt_release_data_t data = {.rrc = rrc, .release_cmd = &ue_context_release_cmd}; + nr_pdcp_data_req_srb(req->gNB_CU_ue_id, DCCH, rrc_gNB_mui++, size, buffer, rrc_deliver_ue_ctxt_release_cmd, &data); return; } @@ -2645,20 +2670,6 @@ void rrc_gNB_generate_SecurityModeCommand(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, buffer, size); } -typedef struct deliver_ue_ctxt_release_data_t { - gNB_RRC_INST *rrc; - f1ap_ue_context_release_cmd_t *release_cmd; - sctp_assoc_t assoc_id; -} deliver_ue_ctxt_release_data_t; -static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id) -{ - DevAssert(deliver_pdu_data != NULL); - deliver_ue_ctxt_release_data_t *data = deliver_pdu_data; - data->release_cmd->rrc_container = (uint8_t*) buf; - data->release_cmd->rrc_container_length = size; - data->rrc->mac_rrc.ue_context_release_command(data->assoc_id, data->release_cmd); -} - //----------------------------------------------------------------------------- /* * Generate the RRC Connection Release to UE. From 6330bfe0e8c591f097747b6205a670ad5ab7f7e5 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 26 Nov 2024 07:57:55 +0100 Subject: [PATCH 55/83] fixup: there is no init_gNB_afterRU() --- executables/nr-softmodem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/executables/nr-softmodem.h b/executables/nr-softmodem.h index 4311777f6c..ecbf5d8759 100644 --- a/executables/nr-softmodem.h +++ b/executables/nr-softmodem.h @@ -52,7 +52,7 @@ extern void stop_RU(int nb_ru); extern void kill_NR_RU_proc(int inst); extern void set_function_spec_param(RU_t *ru); -void init_gNB_afterRU(void); +void init_eNB_afterRU(void); void init_pdcp(void); From a7d0e609ed954c58b3bd3b2708bb28fb2a7cf80f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 27 Nov 2024 16:58:00 +0100 Subject: [PATCH 56/83] config module: check that memory is enough, allow more restarts A later commit implements the "restart" of the L1. The L1 reads configuration options. First, allow to re-read configurations by increasing the amount of memory the config module might allocate. Then, avoid an out-of-bound write by checking that we still have memory available (and assert if not possible). --- common/config/config_common.c | 1 + common/config/config_load_configmodule.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/common/config/config_common.c b/common/config/config_common.c index d6e499b6a8..2bca71d912 100644 --- a/common/config/config_common.c +++ b/common/config/config_common.c @@ -108,6 +108,7 @@ void *config_allocate_new(configmodule_interface_t *cfg, int sz, bool autoFree) // add the memory piece in the managed memory pieces list pthread_mutex_lock(&cfg->memBlocks_mutex); int newBlockIdx=cfg->numptrs++; + AssertFatal(newBlockIdx < sizeofArray(cfg->oneBlock), "reached maximum number of dynamically allocatable blocks\n"); oneBlock_t* tmp=&cfg->oneBlock[newBlockIdx]; tmp->ptrs = (char *)ptr; tmp->ptrsAllocated = true; diff --git a/common/config/config_load_configmodule.h b/common/config/config_load_configmodule.h index bc38322805..3ec27d456f 100644 --- a/common/config/config_load_configmodule.h +++ b/common/config/config_load_configmodule.h @@ -41,7 +41,7 @@ #include "common/config/config_paramdesc.h" #include "common/utils/T/T.h" #define CONFIG_MAX_OOPT_PARAMS 10 // maximum number of parameters in the -O option (-O :P1:P2... -#define CONFIG_MAX_ALLOCATEDPTRS 2048 // maximum number of parameters that can be dynamicaly allocated in the config module +#define CONFIG_MAX_ALLOCATEDPTRS 32768 // maximum number of parameters that can be dynamicaly allocated in the config module /* default values for configuration module parameters */ #define CONFIG_LIBCONFIGFILE "libconfig" // use libconfig file From 3361db1a344515c88aa4e28494c0fbd4e1dea307 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 28 Nov 2024 15:16:53 +0100 Subject: [PATCH 57/83] Stop RU thread pool on exit, if applicable --- executables/nr-ru.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index dd31088ff8..37e520431c 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1443,6 +1443,12 @@ void kill_NR_RU_proc(int inst) { RU_t *ru = RC.ru[inst]; RU_proc_t *proc = &ru->proc; + if (ru->if_south != REMOTE_IF4p5) { + abortTpool(ru->threadPool); + abortNotifiedFIFO(ru->respfeprx); + abortNotifiedFIFO(ru->respfeptx); + } + /* Note: it seems pthread_FH and and FEP thread below both use * mutex_fep/cond_fep. Thus, we unlocked above for pthread_FH above and do * the same for FEP thread below again (using broadcast() to ensure both From 70b461100179ef14396cdcb2ae8f84ed0037b9c4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 28 Nov 2024 14:42:00 +0100 Subject: [PATCH 58/83] Stop L1_rx_thread/L1_tx_thread first These are the "main" worker threads (apart the ru_thread). If the thread-pool stops, they might get stuck. E.g., in PUSCH channel estimation, it uses a local response queue, and if the thread pool is terminated, it seems that the L1_rx_thread can get stuck in there. To limit these problems, attempt to stop these threads first; stop the queue from which they read and make them terminate; then, stop the thread pool. Also, fix the termination of respPuschSymb queue. --- executables/nr-gnb.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 4206cfd585..48c5aca630 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -383,12 +383,16 @@ void init_gNB_Tpool(int inst) { void term_gNB_Tpool(int inst) { PHY_VARS_gNB *gNB = RC.gNB[inst]; - abortTpool(&gNB->threadPool); - abortNotifiedFIFO(&gNB->respDecode); abortNotifiedFIFO(&gNB->resp_L1); + pthread_join(gNB->L1_rx_thread, NULL); + abortNotifiedFIFO(&gNB->L1_tx_out); + pthread_join(gNB->L1_tx_thread, NULL); + + abortTpool(&gNB->threadPool); + abortNotifiedFIFO(&gNB->respPuschSymb); + abortNotifiedFIFO(&gNB->respDecode); abortNotifiedFIFO(&gNB->L1_tx_free); abortNotifiedFIFO(&gNB->L1_tx_filled); - abortNotifiedFIFO(&gNB->L1_tx_out); abortNotifiedFIFO(&gNB->L1_rx_out); gNB_L1_proc_t *proc = &gNB->proc; From 5600316d343da3f2bafa8dee24ca72c6e94d2030 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 3 Dec 2024 12:18:47 +0100 Subject: [PATCH 59/83] UL ref sequences: prevent double-initialization The existing code prevents double initialization if e.g., both gNB&UE call these functions (like in a simulator). However, in the case of a double-initialization such as stopping and re-starting the L1, the memory will be freed, but not freed again. Basically, this works: generate() generate() # not initialized again but this leads to problems: generate() free() generate() # not initialized again, but should be! Reimplement the check based on the data to be initialized, such that an intermediate free() will be handled properly. --- openair1/PHY/NR_REFSIG/ul_ref_seq_nr.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openair1/PHY/NR_REFSIG/ul_ref_seq_nr.c b/openair1/PHY/NR_REFSIG/ul_ref_seq_nr.c index 22fe1b0d13..baa2734f87 100644 --- a/openair1/PHY/NR_REFSIG/ul_ref_seq_nr.c +++ b/openair1/PHY/NR_REFSIG/ul_ref_seq_nr.c @@ -177,10 +177,9 @@ c16_t *gNB_dmrs_lowpaprtype1_sequence[U_GROUP_NUMBER][V_BASE_SEQUENCE_NUMBER][MA void generate_lowpapr_typ1_refsig_sequences(unsigned int scaling) { /* prevent multiple calls, relevant when both UE & gNB initialize this */ - static bool already_called = false; + bool already_called = gNB_dmrs_lowpaprtype1_sequence[0][0][0] != NULL; if (already_called) return; - already_called = true; unsigned int v = 0; // sequence hopping and group hopping are not supported yet for (unsigned int Msc_RS = 0; Msc_RS <= INDEX_SB_LESS_32; Msc_RS++) { @@ -200,9 +199,8 @@ c16_t *dmrs_lowpaprtype1_ul_ref_sig[U_GROUP_NUMBER][V_BASE_SEQUENCE_NUMBER][MAX_ void generate_ul_reference_signal_sequences(unsigned int scaling) { /* prevent multiple calls, relevant when both UE & gNB initialize this */ - static bool already_called = false; + bool already_called = rv_ul_ref_sig[0][0][0] != NULL; if (already_called) return; - already_called = true; unsigned int u,v,Msc_RS; From 462d1a6a8b17af5ebe69b430f0341ceffa263b9d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 14 Feb 2024 10:24:06 +0100 Subject: [PATCH 60/83] RLF: avoid encoder problem --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index e0cc7a8fe0..1f9cb9c0c1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3319,7 +3319,7 @@ bool nr_mac_request_release_ue(const gNB_MAC_INST *nrmac, int rnti) .gNB_CU_ue_id = ue_data.secondary_ue, .gNB_DU_ue_id = rnti, .cause = F1AP_CAUSE_RADIO_NETWORK, - .cause_value = F1AP_CauseRadioNetwork_rl_failure_others, + .cause_value = F1AP_CauseRadioNetwork_rl_failure_rlc, }; nrmac->mac_rrc.ue_context_release_request(&request); return true; From bc8556eafb819ac0ff6efb1f5d59d15f424babcd Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 27 Nov 2024 16:51:13 +0100 Subject: [PATCH 61/83] Implement RFsim stopServer: close listen socket, free memory --- radio/rfsimulator/simulator.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/radio/rfsimulator/simulator.c b/radio/rfsimulator/simulator.c index d362d5ef7b..faa185a0cb 100644 --- a/radio/rfsimulator/simulator.c +++ b/radio/rfsimulator/simulator.c @@ -1085,7 +1085,16 @@ static void rfsimulator_end(openair0_device *device) { } close(s->epollfd); hashtable_destroy(&s->fd_to_buf_map); + free(s); } +static void stopServer(openair0_device *device) +{ + rfsimulator_state_t *t = (rfsimulator_state_t *) device->priv; + DevAssert(t != NULL); + close(t->listen_sock); + rfsimulator_end(device); +} + static int rfsimulator_stop(openair0_device *device) { return 0; } @@ -1136,7 +1145,7 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { device->trx_start_func = rfsimulator->role == SIMU_ROLE_SERVER ? startServer : startClient; device->trx_get_stats_func = rfsimulator_get_stats; device->trx_reset_stats_func = rfsimulator_reset_stats; - device->trx_end_func = rfsimulator_end; + device->trx_end_func = rfsimulator->role == SIMU_ROLE_SERVER ? stopServer : rfsimulator_end; device->trx_stop_func = rfsimulator_stop; device->trx_set_freq_func = rfsimulator_set_freq; device->trx_set_gains_func = rfsimulator_set_gains; From 3c94b9a18f298ead25ae8b8b99ed104d57ffbda3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 26 Nov 2024 11:57:00 +0100 Subject: [PATCH 62/83] rrc_gNB_du.c: avoid potential double-free Set pointer to NULL when freeing to avoid potential double frees. --- openair2/RRC/NR/rrc_gNB_du.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index bc3c564516..4f563d8c43 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -505,8 +505,10 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update // MIB is mandatory, so will be overwritten. SIB1 is optional, so will // only be overwritten if present in sys_info ASN_STRUCT_FREE(asn_DEF_NR_MIB, du->mib); - if (sys_info->sib1 != NULL) + if (sys_info->sib1 != NULL) { ASN_STRUCT_FREE(asn_DEF_NR_SIB1, du->sib1); + du->sib1 = NULL; + } NR_MIB_t *mib = NULL; if (!extract_sys_info(sys_info, &mib, &du->sib1)) { From c852d9337cb67ff150de99c305feb41b0963c670 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 27 Nov 2024 16:59:09 +0100 Subject: [PATCH 63/83] nr_rrc_config_ul_tda(): ensure not double initialization For the "restart" feature, earlier versions where creating multiple UL TDA. This is not a problem (anymore), but to avoid that we call this multiple times, add this assert. --- openair2/RRC/NR/nr_rrc_config.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index e70d7b66eb..f6e7c15e8b 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -920,10 +920,14 @@ void nr_rrc_config_dl_tda(struct NR_PDSCH_TimeDomainResourceAllocationList *pdsc } -void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay){ - +void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay) +{ //TODO change to accomodate for SRS + const NR_PUSCH_TimeDomainResourceAllocationList_t *tda = + scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; + AssertFatal(tda->list.count == 0, "already have pusch_TimeDomainAllocationList members\n"); + frame_type_t frame_type = get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); const int k2 = min_fb_delay; From ed876a53b291d0fe4130c5d46154eddbe7e48289 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 27 Nov 2024 18:27:14 +0100 Subject: [PATCH 64/83] F1: refactor out served_cell_info/du system info Split out these functions, to be reused in a follow-up commit to correctly have gNB-DU configuration update message working. Change the return type copy_f1ap_served_cell_info(), to return the copy, which IMO is more intuitive then passing target and source in parentheses. --- openair2/F1AP/lib/f1ap_interface_management.c | 76 ++++++++++++------- openair2/F1AP/lib/f1ap_interface_management.h | 2 +- openair2/RRC/NR/rrc_gNB_du.c | 2 +- 3 files changed, 50 insertions(+), 30 deletions(-) diff --git a/openair2/F1AP/lib/f1ap_interface_management.c b/openair2/F1AP/lib/f1ap_interface_management.c index f067985a2d..a8d46787b4 100644 --- a/openair2/F1AP/lib/f1ap_interface_management.c +++ b/openair2/F1AP/lib/f1ap_interface_management.c @@ -534,20 +534,56 @@ bool decode_f1ap_setup_request(const F1AP_F1AP_PDU_t *pdu, f1ap_setup_req_t *out return true; } -void copy_f1ap_served_cell_info(f1ap_served_cell_info_t *dest, const f1ap_served_cell_info_t *src) +f1ap_served_cell_info_t copy_f1ap_served_cell_info(const f1ap_served_cell_info_t *src) { - // shallow copy - *dest = *src; - // tac + f1ap_served_cell_info_t dst = { + .plmn = src->plmn, + .nr_cellid = src->nr_cellid, + .nr_pci = src->nr_pci, + .num_ssi = src->num_ssi, + .mode = src->mode, + }; + + for (int i = 0; i < src->num_ssi; ++i) + dst.nssai[i] = src->nssai[i]; + + if (src->mode == F1AP_MODE_TDD) + dst.tdd = src->tdd; + else + dst.fdd = src->fdd; + if (src->tac) { - dest->tac = malloc_or_fail(sizeof(*dest->tac)); - *dest->tac = *src->tac; + dst.tac = malloc_or_fail(sizeof(*dst.tac)); + *dst.tac = *src->tac; } - // measurement timing config - if (src->measurement_timing_config_len) { - dest->measurement_timing_config = calloc_or_fail(src->measurement_timing_config_len, sizeof(*dest->measurement_timing_config)); - memcpy(dest->measurement_timing_config, src->measurement_timing_config, src->measurement_timing_config_len); + + if (src->measurement_timing_config_len > 0) { + dst.measurement_timing_config_len = src->measurement_timing_config_len; + dst.measurement_timing_config = calloc_or_fail(src->measurement_timing_config_len, sizeof(*dst.measurement_timing_config)); + memcpy(dst.measurement_timing_config, src->measurement_timing_config, src->measurement_timing_config_len); } + return dst; +} + +static f1ap_gnb_du_system_info_t *copy_f1ap_gnb_du_system_info(const f1ap_gnb_du_system_info_t *src) +{ + if (!src) + return NULL; + + f1ap_gnb_du_system_info_t *dst = calloc_or_fail(1, sizeof(*dst)); + if (src->mib_length > 0) { + dst->mib_length = src->mib_length; + dst->mib = calloc_or_fail(src->mib_length, sizeof(*src->mib)); + memcpy(dst->mib, src->mib, dst->mib_length); + } + + if (src->sib1_length > 0) { + dst->sib1_length = src->sib1_length; + dst->sib1 = calloc_or_fail(src->sib1_length, sizeof(*dst->sib1)); + memcpy(dst->sib1, src->sib1, dst->sib1_length); + } + + return dst; } /** @@ -567,25 +603,9 @@ f1ap_setup_req_t cp_f1ap_setup_request(const f1ap_setup_req_t *msg) cp.num_cells_available = msg->num_cells_available; for (int n = 0; n < msg->num_cells_available; n++) { /* cell.info */ - f1ap_served_cell_info_t *sci = &cp.cell[n].info; - const f1ap_served_cell_info_t *msg_sci = &msg->cell[n].info; - copy_f1ap_served_cell_info(sci, msg_sci); + cp.cell[n].info = copy_f1ap_served_cell_info(&msg->cell[n].info); /* cell.sys_info */ - if (msg->cell[n].sys_info) { - f1ap_gnb_du_system_info_t *orig_sys_info = msg->cell[n].sys_info; - f1ap_gnb_du_system_info_t *copy_sys_info = calloc_or_fail(1, sizeof(*copy_sys_info)); - cp.cell[n].sys_info = copy_sys_info; - if (orig_sys_info->mib_length > 0) { - copy_sys_info->mib = calloc_or_fail(orig_sys_info->mib_length, sizeof(*copy_sys_info->mib)); - copy_sys_info->mib_length = orig_sys_info->mib_length; - memcpy(copy_sys_info->mib, orig_sys_info->mib, copy_sys_info->mib_length); - } - if (orig_sys_info->sib1_length > 0) { - copy_sys_info->sib1 = calloc_or_fail(orig_sys_info->sib1_length, sizeof(*copy_sys_info->sib1)); - copy_sys_info->sib1_length = orig_sys_info->sib1_length; - memcpy(copy_sys_info->sib1, orig_sys_info->sib1, copy_sys_info->sib1_length); - } - } + cp.cell[n].sys_info = copy_f1ap_gnb_du_system_info(msg->cell[n].sys_info); } for (int i = 0; i < sizeofArray(msg->rrc_ver); i++) cp.rrc_ver[i] = msg->rrc_ver[i]; diff --git a/openair2/F1AP/lib/f1ap_interface_management.h b/openair2/F1AP/lib/f1ap_interface_management.h index e483a74301..6fd79b4007 100644 --- a/openair2/F1AP/lib/f1ap_interface_management.h +++ b/openair2/F1AP/lib/f1ap_interface_management.h @@ -32,7 +32,7 @@ bool decode_f1ap_setup_request(const struct F1AP_F1AP_PDU *pdu, f1ap_setup_req_t f1ap_setup_req_t cp_f1ap_setup_request(const f1ap_setup_req_t *msg); bool eq_f1ap_setup_request(const f1ap_setup_req_t *a, const f1ap_setup_req_t *b); void free_f1ap_setup_request(const f1ap_setup_req_t *msg); -void copy_f1ap_served_cell_info(f1ap_served_cell_info_t *a, const f1ap_served_cell_info_t *b); +f1ap_served_cell_info_t copy_f1ap_served_cell_info(const f1ap_served_cell_info_t *src); void free_f1ap_cell(const f1ap_served_cell_info_t *info, const f1ap_gnb_du_system_info_t *sys_info); /* F1 Setup Response */ diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 4f563d8c43..fc2aec64b4 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -448,7 +448,7 @@ static void update_cell_info(nr_rrc_du_container_t *du, const f1ap_served_cell_i f1ap_served_cell_info_t *ci = &du->setup_req->cell[0].info; // make sure no memory is allocated free_f1ap_cell(ci, NULL); - copy_f1ap_served_cell_info(ci, new_ci); + *ci = copy_f1ap_served_cell_info(new_ci); NR_MeasurementTimingConfiguration_t *new_mtc = extract_mtc(new_ci->measurement_timing_config, new_ci->measurement_timing_config_len); From 6b7055bb3750331616aaeb986b380dc8d050f525 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 27 Nov 2024 18:34:57 +0100 Subject: [PATCH 65/83] eq_f1ap_sys_info(): correct check a and b can only be equal if both NULL or both set (and all fields the same). Check for this. --- openair2/F1AP/lib/f1ap_lib_common.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openair2/F1AP/lib/f1ap_lib_common.c b/openair2/F1AP/lib/f1ap_lib_common.c index 2938898aff..2dc149a8be 100644 --- a/openair2/F1AP/lib/f1ap_lib_common.c +++ b/openair2/F1AP/lib/f1ap_lib_common.c @@ -81,6 +81,13 @@ bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_ bool eq_f1ap_sys_info(const f1ap_gnb_du_system_info_t *a, const f1ap_gnb_du_system_info_t *b) { + if (!a && !b) + return true; + + /* will fail if not both a/b NULL or set */ + if ((!a) ^ (!b)) + return false; + /* MIB */ _F1_EQ_CHECK_INT(a->mib_length, b->mib_length); for (int i = 0; i < a->mib_length; i++) From 3de8a746fe91989f66f040a0f349f9926ab8cb51 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 28 Nov 2024 08:53:35 +0100 Subject: [PATCH 66/83] Fix eq_f1ap_cell_info(): correct TAC comparison Check that both a->tac/b->tac are present, or both not present. Then, check they are equal if present. --- openair2/F1AP/lib/f1ap_lib_common.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openair2/F1AP/lib/f1ap_lib_common.c b/openair2/F1AP/lib/f1ap_lib_common.c index 2dc149a8be..a569146815 100644 --- a/openair2/F1AP/lib/f1ap_lib_common.c +++ b/openair2/F1AP/lib/f1ap_lib_common.c @@ -53,7 +53,10 @@ bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_ { _F1_EQ_CHECK_LONG(a->nr_cellid, b->nr_cellid); _F1_EQ_CHECK_INT(a->nr_pci, b->nr_pci); - _F1_EQ_CHECK_INT(*a->tac, *b->tac); + if ((!a->tac) ^ (!b->tac)) + return false; + if (a->tac) + _F1_EQ_CHECK_INT(*a->tac, *b->tac); _F1_EQ_CHECK_INT(a->mode, b->mode); if (a->mode == F1AP_MODE_TDD) { /* TDD */ From 509cc8cc584f137b6c3416b807e6ec3e00abdfbe Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 28 Nov 2024 08:32:52 +0100 Subject: [PATCH 67/83] Use PLMNID_TO_MCC_MNC() to decode PLMN ID --- openair2/F1AP/lib/f1ap_interface_management.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openair2/F1AP/lib/f1ap_interface_management.c b/openair2/F1AP/lib/f1ap_interface_management.c index a8d46787b4..d44b230df6 100644 --- a/openair2/F1AP/lib/f1ap_interface_management.c +++ b/openair2/F1AP/lib/f1ap_interface_management.c @@ -173,7 +173,7 @@ static bool decode_served_cell_info(const F1AP_Served_Cell_Information_t *in, f1 OCTET_STRING_TO_INT24(in->fiveGS_TAC, *info->tac); } // NR CGI (M) - TBCD_TO_MCC_MNC(&(in->nRCGI.pLMN_Identity), info->plmn.mcc, info->plmn.mnc, info->plmn.mnc_digit_length); + PLMNID_TO_MCC_MNC(&(in->nRCGI.pLMN_Identity), info->plmn.mcc, info->plmn.mnc, info->plmn.mnc_digit_length); // NR Cell Identity (M) BIT_STRING_TO_NR_CELL_IDENTITY(&in->nRCGI.nRCellIdentity, info->nr_cellid); // NR PCI (M) @@ -310,7 +310,7 @@ static bool decode_cells_to_activate(served_cells_to_activate_t *out, const F1AP "in->value.present != F1AP_Cells_to_be_Activated_List_ItemIEs__value_PR_Cells_to_be_Activated_List_Item\n"); const F1AP_Cells_to_be_Activated_List_Item_t *cell = &in->value.choice.Cells_to_be_Activated_List_Item; // NR CGI (M) - TBCD_TO_MCC_MNC(&cell->nRCGI.pLMN_Identity, out->plmn.mcc, out->plmn.mnc, out->plmn.mnc_digit_length); + PLMNID_TO_MCC_MNC(&cell->nRCGI.pLMN_Identity, out->plmn.mcc, out->plmn.mnc, out->plmn.mnc_digit_length); BIT_STRING_TO_NR_CELL_IDENTITY(&cell->nRCGI.nRCellIdentity, out->nr_cellid); // NR PCI (O) if (cell->nRPCI != NULL) @@ -1162,7 +1162,7 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du /* Old NR CGI (M) */ F1AP_NRCGI_t *oldNRCGI = &served_cells_item->oldNRCGI; f1ap_plmn_t *old_plmn = &out->cell_to_modify[i].old_plmn; - TBCD_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length); + PLMNID_TO_MCC_MNC(&oldNRCGI->pLMN_Identity, old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length); /* Old NR CGI Cell ID */ BIT_STRING_TO_NR_CELL_IDENTITY(&oldNRCGI->nRCellIdentity, out->cell_to_modify[i].old_nr_cellid); /* Served Cell Information (M) */ @@ -1186,7 +1186,7 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du F1AP_NRCGI_t *oldNRCGI = &served_cells_item->oldNRCGI; f1ap_plmn_t *plmn = &out->cell_to_delete[i].plmn; /* Old NR CGI (M) */ - TBCD_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length); + PLMNID_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length); // NR cellID BIT_STRING_TO_NR_CELL_IDENTITY(&oldNRCGI->nRCellIdentity, out->cell_to_delete[i].nr_cellid); } @@ -1541,7 +1541,7 @@ bool decode_f1ap_cu_configuration_update_acknowledge(const F1AP_F1AP_PDU_t *pdu, const F1AP_Cells_Failed_to_be_Activated_List_Item_t *item = &itemIE->value.choice.Cells_Failed_to_be_Activated_List_Item; // NR CGI (M) f1ap_plmn_t *plmn = &out->cells_failed_to_be_activated[j].plmn; - TBCD_TO_MCC_MNC(&(item->nRCGI.pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length); + PLMNID_TO_MCC_MNC(&(item->nRCGI.pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length); BIT_STRING_TO_NR_CELL_IDENTITY(&item->nRCGI.nRCellIdentity, out->cells_failed_to_be_activated[j].nr_cellid); // Cause (M) switch (item->cause.present) { From adbbbaeaba512edb2cab93a9baf363232dfb15b0 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 27 Nov 2024 19:50:11 +0100 Subject: [PATCH 68/83] Properly implement eq/cp() functions of gNB-DU config update, fix test Implement those functions following more closely 38.473, i.e., check all mandatory fields. Add mandatory fields in the test. --- openair2/F1AP/lib/f1ap_interface_management.c | 48 ++++++------------- openair2/F1AP/tests/f1ap_lib_test.c | 4 ++ 2 files changed, 19 insertions(+), 33 deletions(-) diff --git a/openair2/F1AP/lib/f1ap_interface_management.c b/openair2/F1AP/lib/f1ap_interface_management.c index d44b230df6..777a4e33a9 100644 --- a/openair2/F1AP/lib/f1ap_interface_management.c +++ b/openair2/F1AP/lib/f1ap_interface_management.c @@ -1236,10 +1236,8 @@ bool eq_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *a for (int i = 0; i < a->num_cells_to_add; i++) { if (!eq_f1ap_cell_info(&a->cell_to_add[i].info, &b->cell_to_add[i].info)) return false; - if (a->cell_to_add[i].sys_info && b->cell_to_add[i].sys_info) { - if (!eq_f1ap_sys_info(a->cell_to_add[i].sys_info, b->cell_to_add[i].sys_info)) - return false; - } + if (!eq_f1ap_sys_info(a->cell_to_add[i].sys_info, b->cell_to_add[i].sys_info)) + return false; } /* to delete */ _F1_EQ_CHECK_INT(a->num_cells_to_delete, b->num_cells_to_delete); @@ -1251,12 +1249,13 @@ bool eq_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *a /* to modify */ _F1_EQ_CHECK_INT(a->num_cells_to_modify, b->num_cells_to_modify); for (int i = 0; i < a->num_cells_to_modify; i++) { + if (!eq_f1ap_plmn(&a->cell_to_modify[i].old_plmn, &b->cell_to_modify[i].old_plmn)) + return false; + _F1_EQ_CHECK_LONG(a->cell_to_modify[i].old_nr_cellid, b->cell_to_modify[i].old_nr_cellid); if (!eq_f1ap_cell_info(&a->cell_to_modify[i].info, &b->cell_to_modify[i].info)) return false; - if (a->cell_to_modify[i].sys_info && b->cell_to_modify[i].sys_info) { - if (!eq_f1ap_sys_info(a->cell_to_modify[i].sys_info, b->cell_to_modify[i].sys_info)) - return false; - } + if (!eq_f1ap_sys_info(a->cell_to_modify[i].sys_info, b->cell_to_modify[i].sys_info)) + return false; } return true; } @@ -1276,6 +1275,10 @@ f1ap_gnb_du_configuration_update_t cp_f1ap_du_configuration_update(const f1ap_gn cp.transaction_id = msg->transaction_id; /* to add */ cp.num_cells_to_add = msg->num_cells_to_add; + for (int i = 0; i < cp.num_cells_to_add; ++i) { + cp.cell_to_add[i].info = copy_f1ap_served_cell_info(&msg->cell_to_add[i].info); + cp.cell_to_add[i].sys_info = copy_f1ap_gnb_du_system_info(msg->cell_to_add[i].sys_info); + } /* to delete */ cp.num_cells_to_delete = msg->num_cells_to_delete; for (int i = 0; i < cp.num_cells_to_delete; i++) { @@ -1285,31 +1288,10 @@ f1ap_gnb_du_configuration_update_t cp_f1ap_du_configuration_update(const f1ap_gn /* to modify */ cp.num_cells_to_modify = msg->num_cells_to_modify; for (int i = 0; i < cp.num_cells_to_modify; i++) { - cp.cell_to_modify[i].info = msg->cell_to_modify[i].info; - f1ap_served_cell_info_t *info = &cp.cell_to_modify[i].info; - if (info->measurement_timing_config_len > 0) { - info->measurement_timing_config = malloc_or_fail(info->measurement_timing_config_len * sizeof(*info->measurement_timing_config)); - for (int j = 0; j < info->measurement_timing_config_len; j++) - info->measurement_timing_config[j] = msg->cell_to_modify[i].info.measurement_timing_config[j]; - } - /* TAC */ - info->tac = calloc_or_fail(1, sizeof(*info->tac)); - *info->tac = *msg->cell_to_modify[i].info.tac; - /* System information */ - cp.cell_to_modify[i].sys_info = malloc_or_fail(sizeof(*cp.cell_to_modify[i].sys_info)); - f1ap_gnb_du_system_info_t *sys_info = cp.cell_to_modify[i].sys_info; - if (msg->cell_to_modify[i].sys_info->mib_length > 0) { - sys_info->mib_length = msg->cell_to_modify[i].sys_info->mib_length; - sys_info->mib = calloc_or_fail(msg->cell_to_modify[i].sys_info->mib_length, sizeof(*sys_info->mib)); - for (int j = 0; j < sys_info->mib_length; j++) - sys_info->mib[j] = msg->cell_to_modify[i].sys_info->mib[j]; - } - if (msg->cell_to_modify[i].sys_info->sib1_length > 0) { - sys_info->sib1_length = msg->cell_to_modify[i].sys_info->sib1_length; - sys_info->sib1 = calloc_or_fail(msg->cell_to_modify[i].sys_info->sib1_length, sizeof(*sys_info->sib1)); - for (int j = 0; j < sys_info->sib1_length; j++) - sys_info->sib1[j] = msg->cell_to_modify[i].sys_info->sib1[j]; - } + cp.cell_to_modify[i].old_plmn = msg->cell_to_modify[i].old_plmn; + cp.cell_to_modify[i].old_nr_cellid = msg->cell_to_modify[i].old_nr_cellid; + cp.cell_to_modify[i].info = copy_f1ap_served_cell_info(&msg->cell_to_modify[i].info); + cp.cell_to_modify[i].sys_info = copy_f1ap_gnb_du_system_info(msg->cell_to_modify[i].sys_info); } return cp; } diff --git a/openair2/F1AP/tests/f1ap_lib_test.c b/openair2/F1AP/tests/f1ap_lib_test.c index 4c75aa944e..80726d000d 100644 --- a/openair2/F1AP/tests/f1ap_lib_test.c +++ b/openair2/F1AP/tests/f1ap_lib_test.c @@ -425,6 +425,10 @@ static void test_f1ap_du_configuration_update(void) .transaction_id = 2, .num_cells_to_modify = 1, .cell_to_modify[0].info = info, + .cell_to_modify[0].old_nr_cellid = 1235UL, + .cell_to_modify[0].old_plmn.mcc = 208, + .cell_to_modify[0].old_plmn.mnc = 88, + .cell_to_modify[0].old_plmn.mnc_digit_length = 2, .num_cells_to_delete = 0, .cell_to_delete[0].nr_cellid = 1234UL, .cell_to_delete[0].plmn.mcc = 1, From 3e8636ce98abf1215ce2ad279634e4b6a55d0bf1 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 29 Nov 2024 11:20:18 +0100 Subject: [PATCH 69/83] Test gNB-DU config update: cell to add/delete --- openair2/F1AP/lib/f1ap_interface_management.c | 4 +--- openair2/F1AP/tests/f1ap_lib_test.c | 24 ++++++++++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/openair2/F1AP/lib/f1ap_interface_management.c b/openair2/F1AP/lib/f1ap_interface_management.c index 777a4e33a9..182f40952d 100644 --- a/openair2/F1AP/lib/f1ap_interface_management.c +++ b/openair2/F1AP/lib/f1ap_interface_management.c @@ -1022,7 +1022,6 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura /* mandatory */ /* c2. Served_Cells_To_Add */ if (msg->num_cells_to_add > 0) { - AssertFatal(false, "code for adding cells not tested\n"); asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie2); ie2->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Add_List; ie2->criticality = F1AP_Criticality_reject; @@ -1080,7 +1079,6 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura ie4->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Delete_List; ie4->criticality = F1AP_Criticality_reject; ie4->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_Served_Cells_To_Delete_List; - AssertFatal(msg->num_cells_to_delete == 0, "code for deleting cells not tested\n"); for (int i = 0; i < msg->num_cells_to_delete; i++) { asn1cSequenceAdd(ie4->value.choice.Served_Cells_To_Delete_List.list, F1AP_Served_Cells_To_Delete_ItemIEs_t, @@ -1134,8 +1132,8 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du } break; case F1AP_ProtocolIE_ID_id_Served_Cells_To_Add_List: { /* Served Cells To Add List */ - AssertError(out->num_cells_to_add > 0, return false, "at least 1 cell to add shall to be present"); out->num_cells_to_add = ie->value.choice.Served_Cells_To_Add_List.list.count; + AssertError(out->num_cells_to_add > 0, return false, "at least 1 cell to add shall to be present"); for (int i = 0; i < out->num_cells_to_add; i++) { F1AP_Served_Cells_To_Add_Item_t *served_cells_item = &((F1AP_Served_Cells_To_Add_ItemIEs_t *)ie->value.choice.Served_Cells_To_Add_List.list.array[i]) diff --git a/openair2/F1AP/tests/f1ap_lib_test.c b/openair2/F1AP/tests/f1ap_lib_test.c index 80726d000d..5d153f1aea 100644 --- a/openair2/F1AP/tests/f1ap_lib_test.c +++ b/openair2/F1AP/tests/f1ap_lib_test.c @@ -420,16 +420,38 @@ static void test_f1ap_du_configuration_update(void) .plmn.mnc_digit_length = 3, .tac = tac, }; + char *mtc2_data = "mtc2"; + uint8_t *mtc2 = (void*)strdup(mtc2_data); + int mtc2_len = strlen(mtc2_data); + f1ap_served_cell_info_t info2 = { + .mode = F1AP_MODE_FDD, + .fdd.ul_freqinfo.arfcn = 640000, + .fdd.ul_freqinfo.band = 78, + .fdd.dl_freqinfo.arfcn = 600000, + .fdd.dl_freqinfo.band = 78, + .fdd.ul_tbw.nrb = 66, + .fdd.ul_tbw.scs = 1, + .fdd.dl_tbw.nrb = 66, + .fdd.dl_tbw.scs = 1, + .measurement_timing_config_len = mtc2_len, + .measurement_timing_config = mtc2, + .nr_cellid = 123456, + .plmn.mcc = 2, + .plmn.mnc = 2, + .plmn.mnc_digit_length = 2, + }; /* create message */ f1ap_gnb_du_configuration_update_t orig = { .transaction_id = 2, + .num_cells_to_add = 1, + .cell_to_add[0].info = info2, .num_cells_to_modify = 1, .cell_to_modify[0].info = info, .cell_to_modify[0].old_nr_cellid = 1235UL, .cell_to_modify[0].old_plmn.mcc = 208, .cell_to_modify[0].old_plmn.mnc = 88, .cell_to_modify[0].old_plmn.mnc_digit_length = 2, - .num_cells_to_delete = 0, + .num_cells_to_delete = 1, .cell_to_delete[0].nr_cellid = 1234UL, .cell_to_delete[0].plmn.mcc = 1, .cell_to_delete[0].plmn.mnc = 1, From 9858a733c19983583a1221b327bc002d7261ba4d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 28 Nov 2024 17:43:44 +0100 Subject: [PATCH 70/83] gnb_du_configuration_update_f1ap(): send to correct task --- openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c index 6d8f7a7115..99e6f02a57 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c @@ -85,7 +85,7 @@ static void gnb_du_configuration_update_f1ap(const f1ap_gnb_du_configuration_upd /* free after copy */ free_f1ap_du_configuration_update(upd); /* send to RRC task */ - itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); + itti_send_msg_to_task(TASK_DU_F1, 0, msg); } static void ue_context_setup_response_f1ap(const f1ap_ue_context_setup_t *req, const f1ap_ue_context_setup_t *resp) From 3e63f1dab2275dcc8073570a6a4e8767ffe995ac Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 28 Nov 2024 17:50:45 +0100 Subject: [PATCH 71/83] Correctly handle received gNB-DU config update ack --- openair2/F1AP/f1ap_du_interface_management.c | 9 +++------ openair2/GNB_APP/gnb_app.c | 4 ---- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/openair2/F1AP/f1ap_du_interface_management.c b/openair2/F1AP/f1ap_du_interface_management.c index 8f6114a9e5..f12b104263 100644 --- a/openair2/F1AP/f1ap_du_interface_management.c +++ b/openair2/F1AP/f1ap_du_interface_management.c @@ -262,12 +262,9 @@ int DU_handle_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance, free_f1ap_du_configuration_update_acknowledge(&in); return -1; } - // Allocate and send an ITTI message - MessageDef *msg_p = itti_alloc_new_message(TASK_DU_F1, 0, F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE); - f1ap_gnb_du_configuration_update_acknowledge_t *msg = &F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_p); - // Copy the decoded message to the ITTI message (RRC thread will free it) - *msg = in; // Copy the decoded message to the ITTI message (RRC thread will free it) - itti_send_msg_to_task(TASK_GNB_APP, GNB_MODULE_ID_TO_INSTANCE(assoc_id), msg_p); + + gnb_du_configuration_update_acknowledge(&in); + free_f1ap_du_configuration_update_acknowledge(&in); return 0; } diff --git a/openair2/GNB_APP/gnb_app.c b/openair2/GNB_APP/gnb_app.c index 354ed2e415..2162d9998e 100644 --- a/openair2/GNB_APP/gnb_app.c +++ b/openair2/GNB_APP/gnb_app.c @@ -238,10 +238,6 @@ void *gNB_app_task(void *args_p) break; - case F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE: - LOG_E(GNB_APP, "[gNB %ld] Handling of %s message not implemented yet\n", instance, msg_name); - break; - case NGAP_DEREGISTERED_GNB_IND: LOG_W(GNB_APP, "[gNB %ld] Received %s: associated AMF %d\n", instance, msg_name, NGAP_DEREGISTERED_GNB_IND(msg_p).nb_amf); From 8e44b2d22ed460665a6cc8348d059ee02bb2face Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 27 Nov 2024 19:49:14 +0100 Subject: [PATCH 72/83] RRC: fix double free, already freed in scope of caller of this function --- openair2/RRC/NR/rrc_gNB_du.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index fc2aec64b4..654ef04be1 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -533,8 +533,6 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update /* Send DU Configuration Acknowledgement */ f1ap_gnb_du_configuration_update_acknowledge_t ack = {.transaction_id = conf_up->transaction_id}; rrc->mac_rrc.gnb_du_configuration_update_acknowledge(assoc_id, &ack); - /* free F1AP message after use */ - free_f1ap_du_configuration_update(conf_up); } void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t *lc, sctp_assoc_t assoc_id) From 6b852a6fff4cedd7c83a61f2c9141d57e3039bf3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 28 Nov 2024 17:42:46 +0100 Subject: [PATCH 73/83] CU_handle_gNB_DU_CONFIGURATION_UPDATE(): don't free the message of RRC The message is already freed at reception at RRC. --- openair2/F1AP/f1ap_cu_interface_management.c | 1 - 1 file changed, 1 deletion(-) diff --git a/openair2/F1AP/f1ap_cu_interface_management.c b/openair2/F1AP/f1ap_cu_interface_management.c index aed1ae6d23..bc5480a11b 100644 --- a/openair2/F1AP/f1ap_cu_interface_management.c +++ b/openair2/F1AP/f1ap_cu_interface_management.c @@ -143,7 +143,6 @@ int CU_handle_gNB_DU_CONFIGURATION_UPDATE(instance_t instance, sctp_assoc_t asso message_p->ittiMsgHeader.originInstance = assoc_id; f1ap_gnb_du_configuration_update_t *req = &F1AP_GNB_DU_CONFIGURATION_UPDATE(message_p); // RRC thread will free it *req = msg; // copy F1 message to ITTI - free_f1ap_du_configuration_update(&msg); LOG_D(F1AP, "Sending F1AP_GNB_DU_CONFIGURATION_UPDATE ITTI message \n"); itti_send_msg_to_task(TASK_RRC_GNB, GNB_MODULE_ID_TO_INSTANCE(instance), message_p); return 0; From 5f01cf6f93baec3b376a1477b09df33cced30d41 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 27 Nov 2024 16:49:04 +0100 Subject: [PATCH 74/83] Keep track of number of RUs in L1 Need to keep track of number of RUs, as the RU initialization increments the number of RUs. Therefore, subsequent initializations would fail if we don't decrement first. There is no better place (or I did not find it) to decrement the number of RUs than in nr_phy_free_RU(). For this reason, we also have to manually set the number of RUs in nr_prachsim to 1, otherwise the assert will trigger. --- openair1/PHY/INIT/nr_init_ru.c | 4 ++++ openair1/SIMULATION/NR_PHY/prachsim.c | 1 + 2 files changed, 5 insertions(+) diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index bf447645d6..674c70cdc3 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -180,4 +180,8 @@ void nr_phy_free_RU(RU_t *ru) free_and_zero(ru->common.beam_id[i]); free_and_zero(ru->common.beam_id); } + + PHY_VARS_gNB *gNB0 = ru->gNB_list[0]; + gNB0->num_RU--; + DevAssert(gNB0->num_RU >= 0); } diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index 08bf2e8fe6..de69fb6c16 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -467,6 +467,7 @@ int main(int argc, char **argv){ ru->nb_rx = n_rx; ru->num_gNB = 1; ru->gNB_list[0] = gNB; + gNB->num_RU = 1; gNB->gNB_config.carrier_config.num_tx_ant.value = 1; gNB->gNB_config.carrier_config.num_rx_ant.value = 1; if (mu == 0) From 0c24f1ff13e91e08b551f493263b4a0305f9177d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 27 Nov 2024 16:50:57 +0100 Subject: [PATCH 75/83] Upon RRC exit: stop ongoing timer --- openair2/RRC/NR/rrc_gNB.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 9bf178afe2..9e552eaa2f 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2498,6 +2498,7 @@ void *rrc_gnb_task(void *args_p) { switch (ITTI_MSG_ID(msg_p)) { case TERMINATE_MESSAGE: LOG_W(NR_RRC, " *** Exiting NR_RRC thread\n"); + timer_remove(stats_timer_id); itti_exit_task(); break; From 511b5f8ebdafc6d75f39d824d7379d5edda7f727 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 26 Nov 2024 07:45:37 +0100 Subject: [PATCH 76/83] Expose F1 primitives for next commits Need to proper forward declaration, as we otherwise need to make telnet_o1 module dependent on F1. Make functions publicly accessible, as the F1 functions are used in an upcoming commit to start the L1. --- openair2/F1AP/f1ap_du_rrc_message_transfer.h | 5 ++- openair2/GNB_APP/gnb_config.c | 43 +++++++++++--------- openair2/GNB_APP/gnb_config.h | 8 ++++ 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/openair2/F1AP/f1ap_du_rrc_message_transfer.h b/openair2/F1AP/f1ap_du_rrc_message_transfer.h index 4064a7cd2a..3c3bc228ad 100644 --- a/openair2/F1AP/f1ap_du_rrc_message_transfer.h +++ b/openair2/F1AP/f1ap_du_rrc_message_transfer.h @@ -34,9 +34,10 @@ #ifndef F1AP_DU_RRC_MESSAGE_TRANSFER_H_ #define F1AP_DU_RRC_MESSAGE_TRANSFER_H_ -#include "f1ap_common.h" +#include -int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); +struct F1AP_F1AP_PDU; +int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, struct F1AP_F1AP_PDU *pdu); int DU_send_UL_NR_RRC_MESSAGE_TRANSFER(sctp_assoc_t assoc_id, const f1ap_ul_rrc_message_t *msg); diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 0612fa9677..7555d1f5d0 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1166,7 +1166,7 @@ static int read_du_cell_info(configmodule_interface_t *cfg, return 1; } -static f1ap_tdd_info_t read_tdd_config(const NR_ServingCellConfigCommon_t *scc) +f1ap_tdd_info_t read_tdd_config(const NR_ServingCellConfigCommon_t *scc) { const NR_FrequencyInfoDL_t *dl = scc->downlinkConfigCommon->frequencyInfoDL; f1ap_tdd_info_t tdd = { @@ -1195,7 +1195,27 @@ static f1ap_fdd_info_t read_fdd_config(const NR_ServingCellConfigCommon_t *scc) return fdd; } -static f1ap_setup_req_t *RC_read_F1Setup(uint64_t id, +f1ap_gnb_du_system_info_t *get_sys_info(NR_BCCH_BCH_Message_t *mib, const NR_BCCH_DL_SCH_Message_t *sib1) +{ + int buf_len = 3; + f1ap_gnb_du_system_info_t *sys_info = calloc_or_fail(1, sizeof(*sys_info)); + + sys_info->mib = calloc_or_fail(buf_len, sizeof(*sys_info->mib)); + DevAssert(mib != NULL); + sys_info->mib_length = encode_MIB_NR(mib, 0, sys_info->mib, buf_len); + DevAssert(sys_info->mib_length == buf_len); + + DevAssert(sib1 != NULL); + NR_SIB1_t *bcch_SIB1 = sib1->message.choice.c1->choice.systemInformationBlockType1; + sys_info->sib1 = calloc_or_fail(NR_MAX_SIB_LENGTH / 8, sizeof(*sys_info->sib1)); + asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_SIB1, NULL, (void *)bcch_SIB1, sys_info->sib1, NR_MAX_SIB_LENGTH / 8); + AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded); + sys_info->sib1_length = (enc_rval.encoded + 7) / 8; + + return sys_info; +} + +f1ap_setup_req_t *RC_read_F1Setup(uint64_t id, const char *name, const f1ap_served_cell_info_t *info, const NR_ServingCellConfigCommon_t *scc, @@ -1244,24 +1264,7 @@ static f1ap_setup_req_t *RC_read_F1Setup(uint64_t id, if (IS_SA_MODE(get_softmodem_params())) { // in NSA we don't transmit SIB1, so cannot fill DU system information // so cannot send MIB either - - int buf_len = 3; // this is what we assume in monolithic - req->cell[0].sys_info = calloc(1, sizeof(*req->cell[0].sys_info)); - AssertFatal(req->cell[0].sys_info != NULL, "out of memory\n"); - f1ap_gnb_du_system_info_t *sys_info = req->cell[0].sys_info; - sys_info->mib = calloc(buf_len, sizeof(*sys_info->mib)); - DevAssert(sys_info->mib != NULL); - DevAssert(mib != NULL); - // encode only the mib message itself - sys_info->mib_length = encode_MIB_NR_setup(mib->message.choice.mib, 0, sys_info->mib, buf_len); - DevAssert(sys_info->mib_length == buf_len); - - DevAssert(sib1 != NULL); - NR_SIB1_t *bcch_SIB1 = sib1->message.choice.c1->choice.systemInformationBlockType1; - sys_info->sib1 = calloc(NR_MAX_SIB_LENGTH / 8, sizeof(*sys_info->sib1)); - asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_SIB1, NULL, (void *)bcch_SIB1, sys_info->sib1, NR_MAX_SIB_LENGTH / 8); - AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded); - sys_info->sib1_length = (enc_rval.encoded + 7) / 8; + req->cell[0].sys_info = get_sys_info(mib, sib1); } int num = read_version(TO_STRING(NR_RRC_VERSION), &req->rrc_ver[0], &req->rrc_ver[1], &req->rrc_ver[2]); diff --git a/openair2/GNB_APP/gnb_config.h b/openair2/GNB_APP/gnb_config.h index aaa945509c..baf4ad5d94 100644 --- a/openair2/GNB_APP/gnb_config.h +++ b/openair2/GNB_APP/gnb_config.h @@ -95,6 +95,14 @@ gNB_RRC_INST *RCconfig_NRRRC(); int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i); int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i); void wait_f1_setup_response(void); +f1ap_setup_req_t *RC_read_F1Setup(uint64_t id, + const char *name, + const f1ap_served_cell_info_t *info, + const NR_ServingCellConfigCommon_t *scc, + NR_BCCH_BCH_Message_t *mib, + const NR_BCCH_DL_SCH_Message_t *sib1); +f1ap_tdd_info_t read_tdd_config(const NR_ServingCellConfigCommon_t *scc); +f1ap_gnb_du_system_info_t *get_sys_info(NR_BCCH_BCH_Message_t *mib, const NR_BCCH_DL_SCH_Message_t *sib1); int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_update_t *gnb_cu_cfg_update); MessageDef *RCconfig_NR_CU_E1(const E1_t *entity); ngran_node_t get_node_type(void); From 8e32f566fca66413d94df2febdb7ceb9cd80e4bb Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 29 Nov 2024 11:22:42 +0100 Subject: [PATCH 77/83] Refactor code to stop L1 Refactor L1 stopping code into a function. The function is basically the same as what we were doing at the end of main() of nr-softmodem.c. This will be reused to support the "soft-restart" functionality in the next commits. --- executables/nr-softmodem.c | 74 +++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 8de047ea06..de06a34d8f 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -401,6 +401,54 @@ void terminate_task(task_id_t task_id, module_id_t mod_id) { //extern void free_transport(PHY_VARS_gNB *); extern void nr_phy_free_RU(RU_t *); +int stop_L1(module_id_t gnb_id) +{ + RU_t *ru = RC.ru[gnb_id]; + if (!ru) { + LOG_W(GNB_APP, "no RU configured\n"); + return -1; + } + + if (!RC.gNB[gnb_id]->configured) { + LOG_W(GNB_APP, "L1 already stopped\n"); + return -1; + } + + LOG_I(GNB_APP, "stopping nr-softmodem\n"); + oai_exit = 1; + + /* these tasks/layers need to pick up new configuration */ + 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_stop_func) { + ru->rfdevice.trx_stop_func(&ru->rfdevice); + LOG_I(GNB_APP, "turned off RU rfdevice\n"); + } + + if (ru->ifdevice.trx_stop_func) { + ru->ifdevice.trx_stop_func(&ru->ifdevice); + LOG_I(GNB_APP, "turned off RU ifdevice\n"); + } + + /* 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++) { + nr_phy_free_RU(RC.ru[inst]); + } + + for (int inst = 0; inst < RC.nb_nr_L1_inst; inst++) { + phy_free_nr_gNB(RC.gNB[inst]); + } + + RC.gNB[gnb_id]->configured = 0; + return 0; +} + static void wait_nfapi_init(char *thread_name) { pthread_mutex_lock( &nfapi_sync_mutex ); @@ -629,37 +677,15 @@ int main( int argc, char **argv ) { printf("TYPE TO TERMINATE\n"); itti_wait_tasks_end(NULL); printf("Returned from ITTI signal handler\n"); - oai_exit=1; - // cleanup - if (RC.nb_nr_L1_inst > 0) - stop_gNB(RC.nb_nr_L1_inst); - - 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++) { - nr_phy_free_RU(RC.ru[inst]); - } - - for (int inst = 0; inst < RC.nb_nr_L1_inst; inst++) { - phy_free_nr_gNB(RC.gNB[inst]); - } + if (RC.nb_nr_L1_inst > 0 || RC.nb_RU > 0) + stop_L1(0); pthread_cond_destroy(&sync_cond); pthread_mutex_destroy(&sync_mutex); pthread_cond_destroy(&nfapi_sync_cond); pthread_mutex_destroy(&nfapi_sync_mutex); - // *** Handle per CC_id openair0 - - for(ru_id = 0; ru_id < RC.nb_RU; ru_id++) { - if (RC.ru[ru_id]->ifdevice.trx_end_func) - RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); - } - free(pckg); logClean(); printf("Bye.\n"); From 68ae3ea11c4d6ce2ed0732f37bd5ffbcdd0cb933 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 29 Nov 2024 11:25:55 +0100 Subject: [PATCH 78/83] Implement start_L1L2() Implements the re-start of the L1 after it has been stopped through stop_L1(). It takes into account some changes, such as bandwidth, or frequency, when restarting the L1. To this end, it also triggers a gNB-DU configuration update message on each restart to inform the CU about any changes in the DU. FDD has not been tested. --- executables/nr-softmodem.c | 51 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index de06a34d8f..96527fb303 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -449,6 +449,57 @@ int stop_L1(module_id_t gnb_id) return 0; } +/* + * Restart the nr-softmodem after it has been soft-stopped with stop_L1L2() + */ +#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" +int start_L1L2(module_id_t gnb_id) +{ + LOG_I(GNB_APP, "starting nr-softmodem\n"); + /* block threads */ + oai_exit = 0; + sync_var = -1; + extern void init_sched_response(void); + init_sched_response(); + + /* update config */ + gNB_MAC_INST *mac = RC.nrmac[0]; + NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; + nr_mac_config_scc(mac, scc, &mac->radio_config); + + NR_BCCH_BCH_Message_t *mib = mac->common_channels[0].mib; + const NR_BCCH_DL_SCH_Message_t *sib1 = mac->common_channels[0].sib1; + + /* update existing config in F1 Setup request structures */ + f1ap_setup_req_t *sr = mac->f1_config.setup_req; + DevAssert(sr->num_cells_available == 1); + f1ap_served_cell_info_t *info = &sr->cell[0].info; + DevAssert(info->mode == F1AP_MODE_TDD); + DevAssert(scc->tdd_UL_DL_ConfigurationCommon != NULL); + info->tdd = read_tdd_config(scc); /* updates radio config */ + /* send gNB-DU configuration update to RRC */ + f1ap_gnb_du_configuration_update_t update = { + .transaction_id = 1, + .num_cells_to_modify = 1, + }; + update.cell_to_modify[0].old_nr_cellid = info->nr_cellid; + update.cell_to_modify[0].info = *info; + update.cell_to_modify[0].sys_info = get_sys_info(mib, sib1); + mac->mac_rrc.gnb_du_configuration_update(&update); + + init_NR_RU(config_get_if(), NULL); + + start_NR_RU(); + wait_RUs(); + init_eNB_afterRU(); + LOG_I(GNB_APP, "Sending sync to all threads\n"); + pthread_mutex_lock(&sync_mutex); + sync_var=0; + pthread_cond_broadcast(&sync_cond); + pthread_mutex_unlock(&sync_mutex); + return 0; +} + static void wait_nfapi_init(char *thread_name) { pthread_mutex_lock( &nfapi_sync_mutex ); From aba506e5e3669a10e3e4e99a6fdf133ead1b5360 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 5 Oct 2023 08:53:12 +0200 Subject: [PATCH 79/83] Add basic O1 telnet module This adds a basic telnet module to support the O1 interface at the DU, to be used together with the oai/o1-adapter>. Concretely, this first version supports to - read/modify cell parameters - stop/start the L1 --- common/utils/telnetsrv/CMakeLists.txt | 8 +- common/utils/telnetsrv/DOC/telneto1.md | 176 +++++++++++ common/utils/telnetsrv/DOC/telnetsrv.md | 1 + common/utils/telnetsrv/telnetsrv_o1.c | 391 ++++++++++++++++++++++++ 4 files changed, 575 insertions(+), 1 deletion(-) create mode 100644 common/utils/telnetsrv/DOC/telneto1.md create mode 100644 common/utils/telnetsrv/telnetsrv_o1.c diff --git a/common/utils/telnetsrv/CMakeLists.txt b/common/utils/telnetsrv/CMakeLists.txt index a7da081f09..5f190edc02 100644 --- a/common/utils/telnetsrv/CMakeLists.txt +++ b/common/utils/telnetsrv/CMakeLists.txt @@ -75,7 +75,13 @@ add_library(telnetsrv_rrc MODULE telnetsrv_rrc.c) target_link_libraries(telnetsrv_rrc PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) add_dependencies(telnetsrv telnetsrv_rrc) +message(STATUS "Add CI specific telnet functions in libtelnetsrv_o1.so") +add_library(telnetsrv_o1 MODULE telnetsrv_o1.c) +target_link_libraries(telnetsrv_o1 PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) +add_dependencies(telnetsrv telnetsrv_o1) + # all libraries should be written to root build dir -set_target_properties(telnetsrv telnetsrv_enb telnetsrv_5Gue telnetsrv_ci telnetsrv_ciUE telnetsrv_bearer telnetsrv_rrc +set_target_properties(telnetsrv telnetsrv_enb telnetsrv_5Gue telnetsrv_ci telnetsrv_ciUE + telnetsrv_bearer telnetsrv_rrc telnetsrv_o1 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ../../.. ) diff --git a/common/utils/telnetsrv/DOC/telneto1.md b/common/utils/telnetsrv/DOC/telneto1.md new file mode 100644 index 0000000000..4c6b9a3b4d --- /dev/null +++ b/common/utils/telnetsrv/DOC/telneto1.md @@ -0,0 +1,176 @@ +[[_TOC_]] + +The telnet O1 module (`telnetsrv_o1.c`) can be used to perform some O1-related +actions (reading data, starting and stopping the nr-softmodem, reconfigurating +frequency and bandwidth). + +# General usage + +The usage is similar to the general telnet usage, but in short: +``` +./build_oai --ninja -c --gNB --nrUE --build-lib telnetsrv +``` +to build everything including the telnet library. Then, run the nr-softmodem +by activating telnet and loading the `o1` module: +``` +./nr-softmodem -O --telnetsrv --telnetsrv.shrmod o1 +``` + +Afterwards, it should be possible to connect via telnet on localhost, port +9090. Use `help` to get help on the different command sections, and type e.g. +`o1 stats` to get statistics (more information further below): + +``` +$ telnet 127.0.0.1 9090 +Trying 127.0.0.1... +Connected to 127.0.0.1. +Escape character is '^]'. + +softmodem_gnb> help +[...] + module 4 = o1: + o1 stats + o1 config ? + o1 stop_modem + o1 start_modem +[...] +softmodem_gnb> o1 stats +[...] +softmodem_gnb> exit +Connection closed by foreign host. +``` + +It also possible to send a command "directly from the command line", by piping +the command into netcat: +``` +echo o1 stats | nc -N 127.0.0.1 9090 +``` + +Note that only one telnet client can be connected at a time. + +# Get statistics + +Use the `o1 stats` command. The output is in JSON format: +```json +{ + "o1-config": { + "BWP": { + "dl": [ + { + "bwp3gpp:isInitialBwp": true, + "bwp3gpp:numberOfRBs": 106, + "bwp3gpp:startRB": 0, + "bwp3gpp:subCarrierSpacing": 30 + } + ], + "ul": [ + { + "bwp3gpp:isInitialBwp": true, + "bwp3gpp:numberOfRBs": 106, + "bwp3gpp:startRB": 0, + "bwp3gpp:subCarrierSpacing": 30 + } + ] + }, + "NRCELLDU": { + "nrcelldu3gpp:ssbFrequency": 641280, + "nrcelldu3gpp:arfcnDL": 640008, + "nrcelldu3gpp:bSChannelBwDL": 40, + "nrcelldu3gpp:arfcnUL": 640008, + "nrcelldu3gpp:bSChannelBwUL": 40, + "nrcelldu3gpp:nRPCI": 0, + "nrcelldu3gpp:nRTAC": 1, + "nrcelldu3gpp:mcc": "208", + "nrcelldu3gpp:mnc": "95", + "nrcelldu3gpp:sd": 16777215, + "nrcelldu3gpp:sst": 1 + }, + "device": { + "gnbId": 1, + "gnbName": "gNB-Eurecom-5GNRBox", + "vendor": "OpenAirInterface" + } + }, + "O1-Operational": { + "frame-type": "tdd", + "band-number": 78, + "num-ues": 1, + "ues": [ + 6876 + ], + "load": 9, + "ues-thp": [ + { + "rnti": 6876, + "dl": 3279, + "ul": 2725 + } + ] + } +} +``` + +Note that no actual JSON engine is used, so no actual verification is done; it +is for convenience of the consumer. To verify, you can employ `jq`: +``` +echo o1 stats | nc -N 127.0.0.1 9090 | awk '/^{$/, /^}$/' | jq . +``` +(`awk`'s pattern matching makes that only everything between the first `{` and +its corresponding `}` is printed). + +There are two sections: +1. `.o1-config` show some stats that map directly to the O1 Netconf model. Note + that only one MCC/MNC/SD/SST (each) are supported right now. Also, note that + as per 3GPP specifications, SD of value `0xffffff` (16777215 in decimal) + means "no SD". `bSChannelBwDL/UL` is reported in MHz. +2. `.O1-operational` output some statistics that do not map yet to any netconf + parameters, but that might be useful nevertheless for a consumer. + +# Write a new configuration + +Use `o1 config` to write a configuration: +``` +echo o1 config nrcelldu3gpp:ssbFrequency 620736 nrcelldu3gpp:arfcnDL 620020 nrcelldu3gpp:bSChannelBwDL 51 bwp3gpp:numberOfRBs 51 bwp3gpp:startRB 0 | nc -N 127.0.0.1 9090 +``` +You have to pass the above parameters in exactly this order. The softmodem +needs to be stopped; it will pick up the new configuration when starting the +softmodem again. + +Note that you cannot switch three-quarter sampling for this as of now. + +For values of the configuration, refer to the next section. + +# Use hardcoded configuration + +Use `o1 bwconfig` to write a hard-coded configuration for 20 or 40 MHz cells: +``` +echo o1 bwconfig 20 | nc -N 127.0.0.1 9090 +echo o1 bwconfig 40 | nc -N 127.0.0.1 9090 +``` + +The softmodem needs to be stopped; it will pick up the new configuration when +starting the softmodem again. + +Use `o1 stats` to see which configurations are set by these commands for the +parameters `nrcelldu3gpp:ssbFrequency`, `nrcelldu3gpp:arfcnDL`, +`nrcelldu3gpp:arfcnUL`, `nrcelldu3gpp:bSChannelBwDL`, +`nrcelldu3gpp:bSChannelBwUL`, and `bwp3gpp:numberOfRBsbwp3gpp:startRB`. +Furthermore, for 20MHz, it *disables* three-quarter sampling, whereas it +*enables* three-quarter sampling for 40MHz. + +# Restart the softmodem + +Use `o1 stop_modem` to stop the `nr-softmodem`. To restart the softmodem, use +`o1 start_modem`: +``` +echo o1 stop_modem | nc -N 127.0.0.1 9090 +echo o1 start_modem | nc -N 127.0.0.1 9090 +``` + +In fact, stopping terminates all L1 threads. It will be as if the softmodem +"freezes", and no periodical output of statistics will occur (the O1 telnet +interface will still work, though). Starting again will "defreeze" the +softmodem. + +Upon restart, the DU sends a gNB-DU configuration update to the CU to inform it +about the updated configuration. Therefore, this also works in F1. diff --git a/common/utils/telnetsrv/DOC/telnetsrv.md b/common/utils/telnetsrv/DOC/telnetsrv.md index 11c6cf071f..68051e7df8 100644 --- a/common/utils/telnetsrv/DOC/telnetsrv.md +++ b/common/utils/telnetsrv/DOC/telnetsrv.md @@ -3,5 +3,6 @@ The oai embedded telnet server is an optional monitoring and debugging tool. It * [Using the telnet server](telnetusage.md) * [Adding commands to the oai telnet server](telnetaddcmd.md) * [telnet server architecture ](telnetarch.md) +* [on the telnet O1 module](telneto1.md) [oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home) diff --git a/common/utils/telnetsrv/telnetsrv_o1.c b/common/utils/telnetsrv/telnetsrv_o1.c new file mode 100644 index 0000000000..36cffdf18d --- /dev/null +++ b/common/utils/telnetsrv/telnetsrv_o1.c @@ -0,0 +1,391 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define TELNETSERVERCODE +#include "telnetsrv.h" + +#include "openair2/RRC/NR/nr_rrc_defs.h" +#include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h" +#include "openair2/RRC/NR/nr_rrc_config.h" +#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" +#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c" +#include "common/utils/nr/nr_common.h" + +#define ERROR_MSG_RET(mSG, aRGS...) do { prnt("FAILURE: " mSG, ##aRGS); return 1; } while (0) + +#define ISINITBWP "bwp3gpp:isInitialBwp" +//#define CYCLPREF "bwp3gpp:cyclicPrefix" +#define NUMRBS "bwp3gpp:numberOfRBs" +#define STARTRB "bwp3gpp:startRB" +#define BWPSCS "bwp3gpp:subCarrierSpacing" + +#define SSBFREQ "nrcelldu3gpp:ssbFrequency" +#define ARFCNDL "nrcelldu3gpp:arfcnDL" +#define BWDL "nrcelldu3gpp:bSChannelBwDL" +#define ARFCNUL "nrcelldu3gpp:arfcnUL" +#define BWUL "nrcelldu3gpp:bSChannelBwUL" +#define PCI "nrcelldu3gpp:nRPCI" +#define TAC "nrcelldu3gpp:nRTAC" +#define MCC "nrcelldu3gpp:mcc" +#define MNC "nrcelldu3gpp:mnc" +#define SD "nrcelldu3gpp:sd" +#define SST "nrcelldu3gpp:sst" + +typedef struct b { + long int dl; + long int ul; +} b_t; + +typedef struct ue_stat { + rnti_t rnti; + b_t thr; +} ue_stat_t; + +#define PRINTLIST_i(len, fmt, ...) \ + { \ + for (int i = 0; i < len; ++i) { \ + if (i != 0) prnt(", "); \ + prnt(fmt, __VA_ARGS__); \ + } \ + } \ + +static int get_stats(char *buf, int debug, telnet_printfunc_t prnt) +{ + if (buf) + ERROR_MSG_RET("no parameter allowed\n"); + + gNB_MAC_INST *mac = RC.nrmac[0]; + AssertFatal(mac != NULL, "need MAC\n"); + NR_SCHED_LOCK(&mac->sched_lock); + + const f1ap_setup_req_t *sr = mac->f1_config.setup_req; + const f1ap_served_cell_info_t *cell_info = &sr->cell[0].info; + + const NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; + const NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL; + const NR_FrequencyInfoUL_t *frequencyInfoUL = scc->uplinkConfigCommon->frequencyInfoUL; + frame_type_t frame_type = get_frame_type(*frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); + const NR_BWP_t *initialDL = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; + const NR_BWP_t *initialUL = &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + + int scs = initialDL->subcarrierSpacing; + AssertFatal(scs == initialUL->subcarrierSpacing, "different SCS for UL/DL not supported!\n"); + int band = *frequencyInfoDL->frequencyBandList.list.array[0]; + int nrb = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; + AssertFatal(nrb == frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth, "different BW for UL/DL not supported!\n"); + frequency_range_t fr = band > 256 ? FR2 : FR1; + int bw_index = get_supported_band_index(scs, fr, nrb); + int bw_mhz = get_supported_bw_mhz(fr, bw_index); + + const mac_stats_t *stat = &mac->mac_stats; + static mac_stats_t last = {0}; + int diff_used = stat->used_prb_aggregate - last.used_prb_aggregate; + int diff_total = stat->total_prb_aggregate - last.total_prb_aggregate; + int load = diff_total > 0 ? 100 * diff_used / diff_total : 0; + last = *stat; + + static struct timespec tp_last = {0}; + struct timespec tp_now; + clock_gettime(CLOCK_MONOTONIC, &tp_now); + size_t diff_msec = (tp_now.tv_sec - tp_last.tv_sec) * 1000 + (tp_now.tv_nsec - tp_last.tv_nsec) / 1000000; + tp_last = tp_now; + + const int srb_flag = 0; + const int rb_id = 1; + static b_t last_total[MAX_MOBILES_PER_GNB] = {0}; // TODO: hash table? + ue_stat_t ue_stat[MAX_MOBILES_PER_GNB] = {0}; + int num_ues = 0; + UE_iterator((NR_UE_info_t **)mac->UE_info.list, it) { + nr_rlc_statistics_t rlc = {0}; + nr_rlc_get_statistics(it->rnti, srb_flag, rb_id, &rlc); + b_t *lt = &last_total[num_ues]; + ue_stat_t *ue_s = &ue_stat[num_ues]; + ue_s->rnti = it->rnti; + // static var last_total: we might have old data, larger than what + // reports RLC, leading to a huge number -> cut off to zero + if (lt->dl > rlc.txpdu_bytes) + lt->dl = rlc.txpdu_bytes; + if (lt->ul > rlc.rxpdu_bytes) + lt->ul = rlc.rxpdu_bytes; + ue_s->thr.dl = (rlc.txpdu_bytes - lt->dl) * 8 / diff_msec; + ue_s->thr.ul = (rlc.rxpdu_bytes - lt->ul) * 8 / diff_msec; + lt->dl = rlc.txpdu_bytes; + lt->ul = rlc.rxpdu_bytes; + num_ues++; + } + + prnt("{\n"); + prnt(" \"o1-config\": {\n"); + + prnt(" \"BWP\": {\n"); + prnt(" \"dl\": [{\n"); + prnt(" \"" ISINITBWP "\": true,\n"); + //prnt(" \"" CYCLPREF "\": %ld,\n", *initialDL->cyclicPrefix); + prnt(" \"" NUMRBS "\": %ld,\n", NRRIV2BW(initialDL->locationAndBandwidth, MAX_BWP_SIZE)); + prnt(" \"" STARTRB "\": %ld,\n", NRRIV2PRBOFFSET(initialDL->locationAndBandwidth, MAX_BWP_SIZE)); + prnt(" \"" BWPSCS "\": %ld\n", 15 * (1U << scs)); + prnt(" }],\n"); + prnt(" \"ul\": [{\n"); + prnt(" \"" ISINITBWP "\": true,\n"); + //prnt(" \"" CYCLPREF "\": %ld,\n", *initialUL->cyclicPrefix); + prnt(" \"" NUMRBS "\": %ld,\n", NRRIV2BW(initialUL->locationAndBandwidth, MAX_BWP_SIZE)); + prnt(" \"" STARTRB "\": %ld,\n", NRRIV2PRBOFFSET(initialUL->locationAndBandwidth, MAX_BWP_SIZE)); + prnt(" \"" BWPSCS "\": %ld\n", 15 * (1U << scs)); + prnt(" }]\n"); + prnt(" },\n"); + + prnt(" \"NRCELLDU\": {\n"); + prnt(" \"" SSBFREQ "\": %ld,\n", *scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB); + prnt(" \"" ARFCNDL "\": %ld,\n", frequencyInfoDL->absoluteFrequencyPointA); + prnt(" \"" BWDL "\": %ld,\n", bw_mhz); + prnt(" \"" ARFCNUL "\": %ld,\n", frequencyInfoUL->absoluteFrequencyPointA ? *frequencyInfoUL->absoluteFrequencyPointA : frequencyInfoDL->absoluteFrequencyPointA); + prnt(" \"" BWUL "\": %ld,\n", bw_mhz); + prnt(" \"" PCI "\": %ld,\n", *scc->physCellId); + prnt(" \"" TAC "\": %ld,\n", *cell_info->tac); + prnt(" \"" MCC "\": \"%03d\",\n", cell_info->plmn.mcc); + prnt(" \"" MNC "\": \"%0*d\",\n", cell_info->plmn.mnc_digit_length, cell_info->plmn.mnc); + prnt(" \"" SD "\": %d,\n", cell_info->nssai[0].sd); + prnt(" \"" SST "\": %d\n", cell_info->nssai[0].sst); + prnt(" },\n"); + prnt(" \"device\": {\n"); + prnt(" \"gnbId\": %d,\n", sr->gNB_DU_id); + prnt(" \"gnbName\": \"%s\",\n", sr->gNB_DU_name); + prnt(" \"vendor\": \"OpenAirInterface\"\n"); + prnt(" }\n"); + prnt(" },\n"); + + prnt(" \"O1-Operational\": {\n"); + prnt(" \"frame-type\": \"%s\",\n", frame_type == TDD ? "tdd" : "fdd"); + prnt(" \"band-number\": %ld,\n", band); + prnt(" \"num-ues\": %d,\n", num_ues); + prnt(" \"ues\": ["); PRINTLIST_i(num_ues, "%d", ue_stat[i].rnti); prnt("],\n"); + prnt(" \"load\": %d,\n", load); + prnt(" \"ues-thp\": ["); + PRINTLIST_i(num_ues, "\n {\"rnti\": %d, \"dl\": %ld, \"ul\": %ld}", ue_stat[i].rnti, ue_stat[i].thr.dl, ue_stat[i].thr.ul); + prnt("\n ]\n"); + prnt(" }\n"); + prnt("}\n"); + prnt("OK\n"); + NR_SCHED_UNLOCK(&mac->sched_lock); + return 0; +} + +static int read_long(const char *buf, const char *end, const char *id, long *val) +{ + const char *curr = buf; + while (isspace(*curr) && curr < end) // skip leading spaces + curr++; + int len = strlen(id); + if (curr + len >= end) + return -1; + if (strncmp(curr, id, len) != 0) // check buf has id + return -1; + curr += len; + while (isspace(*curr) && curr < end) // skip middle spaces + curr++; + if (curr >= end) + return -1; + int nread = sscanf(curr, "%ld", val); + if (nread != 1) + return -1; + while (isdigit(*curr) && curr < end) // skip all digits read above + curr++; + if (curr > end) + return -1; + return curr - buf; +} + +bool running = true; // in the beginning, the softmodem is started automatically +static int set_config(char *buf, int debug, telnet_printfunc_t prnt) +{ + if (!buf) + ERROR_MSG_RET("need param: o1 config param1 val1 [param2 val2 ...]\n"); + if (running) + ERROR_MSG_RET("cannot set parameters while L1 is running\n"); + const char *end = buf + strlen(buf); + + /* we need to update the following fields to change frequency and/or + * bandwidth: + * --gNBs.[0].servingCellConfigCommon.[0].absoluteFrequencySSB 620736 -> SSBFREQ + * --gNBs.[0].servingCellConfigCommon.[0].dl_absoluteFrequencyPointA 620020 -> ARFCNDL + * --gNBs.[0].servingCellConfigCommon.[0].dl_carrierBandwidth 51 -> BWDL + * --gNBs.[0].servingCellConfigCommon.[0].initialDLBWPlocationAndBandwidth 13750 -> NUMRBS + STARTRB + * --gNBs.[0].servingCellConfigCommon.[0].ul_carrierBandwidth 51 -> BWUL? + * --gNBs.[0].servingCellConfigCommon.[0].initialULBWPlocationAndBandwidth 13750 -> ? + */ + + int processed = 0; + int pos = 0; + + long ssbfreq; + processed = read_long(buf + pos, end, SSBFREQ, &ssbfreq); + if (processed < 0) + ERROR_MSG_RET("could not read " SSBFREQ " at index %d\n", pos + processed); + pos += processed; + prnt("setting " SSBFREQ ": %ld [len %d]\n", ssbfreq, pos); + + long arfcn; + processed = read_long(buf + pos, end, ARFCNDL, &arfcn); + if (processed < 0) + ERROR_MSG_RET("could not read " ARFCNDL " at index %d\n", pos + processed); + pos += processed; + prnt("setting " ARFCNDL ": %ld [len %d]\n", arfcn, pos); + + long bwdl; + processed = read_long(buf + pos, end, BWDL, &bwdl); + if (processed < 0) + ERROR_MSG_RET("could not read " BWDL " at index %d\n", pos + processed); + pos += processed; + prnt("setting " BWDL ": %ld [len %d]\n", bwdl, pos); + + long numrbs; + processed = read_long(buf + pos, end, NUMRBS, &numrbs); + if (processed < 0) + ERROR_MSG_RET("could not read " NUMRBS " at index %d\n", pos + processed); + pos += processed; + prnt("setting " NUMRBS ": %ld [len %d]\n", numrbs, pos); + + long startrb; + processed = read_long(buf + pos, end, STARTRB, &startrb); + if (processed < 0) + ERROR_MSG_RET("could not read " STARTRB " at index %d\n", pos + processed); + pos += processed; + prnt("setting " STARTRB ": %ld [len %d]\n", startrb, pos); + + int locationAndBandwidth = PRBalloc_to_locationandbandwidth0(numrbs, startrb, MAX_BWP_SIZE); + prnt("inferred locationAndBandwidth: %d\n", locationAndBandwidth); + prnt("OK\n"); + return 0; +} + +static int set_bwconfig(char *buf, int debug, telnet_printfunc_t prnt) +{ + if (running) + ERROR_MSG_RET("cannot set parameters while L1 is running\n"); + if (!buf) + ERROR_MSG_RET("need param: o1 bwconfig \n"); + + char *end = NULL; + if (NULL != (end = strchr(buf, '\n'))) + *end = 0; + if (NULL != (end = strchr(buf, '\r'))) + *end = 0; + + gNB_MAC_INST *mac = RC.nrmac[0]; + NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; + NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL; + NR_BWP_t *initialDL = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; + NR_FrequencyInfoUL_t *frequencyInfoUL = scc->uplinkConfigCommon->frequencyInfoUL; + NR_BWP_t *initialUL = &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + if (strcmp(buf, "40") == 0) { + *scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB = 641280; + frequencyInfoDL->absoluteFrequencyPointA = 640008; + AssertFatal(frequencyInfoUL->absoluteFrequencyPointA == NULL, "only handle TDD\n"); + frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 106; + initialDL->locationAndBandwidth = 28875; + frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 106; + initialUL->locationAndBandwidth = 28875; + get_softmodem_params()->threequarter_fs = 1; + } else if (strcmp(buf, "20") == 0) { + *scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB = 641280; + frequencyInfoDL->absoluteFrequencyPointA = 640596; + AssertFatal(frequencyInfoUL->absoluteFrequencyPointA == NULL, "only handle TDD\n"); + frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 51; + initialDL->locationAndBandwidth = 13750; + frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 51; + initialUL->locationAndBandwidth = 13750; + get_softmodem_params()->threequarter_fs = 0; + } else { + ERROR_MSG_RET("unhandled option %s\n", buf); + } + + free(RC.nrmac[0]->sched_ctrlCommon); + RC.nrmac[0]->sched_ctrlCommon = NULL; + + free_MIB_NR(mac->common_channels[0].mib); + mac->common_channels[0].mib = get_new_MIB_NR(scc); + + const f1ap_served_cell_info_t *info = &mac->f1_config.setup_req->cell[0].info; + nr_mac_configure_sib1(mac, &info->plmn, info->nr_cellid, *info->tac); + + prnt("OK\n"); + return 0; +} + +extern int stop_L1(module_id_t gnb_id); +static int stop_modem(char *buf, int debug, telnet_printfunc_t prnt) +{ + if (!running) + ERROR_MSG_RET("cannot stop, nr-softmodem not running\n"); + + /* make UEs out of sync and wait 50ms to ensure no PUCCH is scheduled. After + * a restart, the frame/slot numbers will be different, which "confuses" the + * scheduler, which has many PUCCH structures filled with expected frame/slot + * combinations that won't happen. */ + const gNB_MAC_INST *mac = RC.nrmac[0]; + UE_iterator((NR_UE_info_t **)mac->UE_info.list, it) { + nr_mac_trigger_ul_failure(&it->UE_sched_ctrl, 1); + } + usleep(50000); + + stop_L1(0); + running = false; + prnt("OK\n"); + return 0; +} + +extern int start_L1L2(module_id_t gnb_id); +static int start_modem(char *buf, int debug, telnet_printfunc_t prnt) +{ + if (running) + ERROR_MSG_RET("cannot start, nr-softmodem already running\n"); + start_L1L2(0); + running = true; + prnt("OK\n"); + return 0; +} + +static telnetshell_cmddef_t o1cmds[] = { + {"stats", "", get_stats}, + {"config", "[]", set_config}, + {"bwconfig", "", set_bwconfig}, + {"stop_modem", "", stop_modem}, + {"start_modem", "", start_modem}, + {"", "", NULL}, +}; + +static telnetshell_vardef_t o1vars[] = { + {"", 0, 0, NULL} +}; + +void add_o1_cmds(void) { + add_telnetcmd("o1", o1vars, o1cmds); +} From c71c9de953ea0dd791abc28fe34b5eee26846dee Mon Sep 17 00:00:00 2001 From: Ronak Kanthaliya Date: Fri, 30 Aug 2024 14:26:20 +0530 Subject: [PATCH 80/83] Additional BW configurability on telnet server --- common/utils/telnetsrv/telnetsrv_o1.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/common/utils/telnetsrv/telnetsrv_o1.c b/common/utils/telnetsrv/telnetsrv_o1.c index 36cffdf18d..18cd58aa06 100644 --- a/common/utils/telnetsrv/telnetsrv_o1.c +++ b/common/utils/telnetsrv/telnetsrv_o1.c @@ -323,6 +323,24 @@ static int set_bwconfig(char *buf, int debug, telnet_printfunc_t prnt) frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 51; initialUL->locationAndBandwidth = 13750; get_softmodem_params()->threequarter_fs = 0; + } else if (strcmp(buf, "100") == 0) { + *scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB = 646668; + frequencyInfoDL->absoluteFrequencyPointA = 643392; + AssertFatal(frequencyInfoUL->absoluteFrequencyPointA == NULL, "only handle TDD\n"); + frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 273; + initialDL->locationAndBandwidth = 1099; + frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 273; + initialUL->locationAndBandwidth = 1099; + get_softmodem_params()->threequarter_fs = 0; + } else if (strcmp(buf, "60") == 0) { + *scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB = 621984; + frequencyInfoDL->absoluteFrequencyPointA = 620040; + AssertFatal(frequencyInfoUL->absoluteFrequencyPointA == NULL, "only handle TDD\n"); + frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 162; + initialDL->locationAndBandwidth = 31624; + frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 162; + initialUL->locationAndBandwidth = 31624; + get_softmodem_params()->threequarter_fs = 0; } else { ERROR_MSG_RET("unhandled option %s\n", buf); } From 70a746a4454d9e8a0d5e6a05d808e98dcf2917d9 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 5 Dec 2024 13:59:49 +0100 Subject: [PATCH 81/83] Provide O1 telnet interface to remove all UEs --- common/utils/telnetsrv/telnetsrv_o1.c | 9 +++++++++ openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/common/utils/telnetsrv/telnetsrv_o1.c b/common/utils/telnetsrv/telnetsrv_o1.c index 18cd58aa06..dc48a477d3 100644 --- a/common/utils/telnetsrv/telnetsrv_o1.c +++ b/common/utils/telnetsrv/telnetsrv_o1.c @@ -391,12 +391,21 @@ static int start_modem(char *buf, int debug, telnet_printfunc_t prnt) return 0; } +extern void du_clear_all_ue_states(); +static int remove_mac_ues(char *buf, int debug, telnet_printfunc_t prnt) +{ + du_clear_all_ue_states(); + prnt("OK\n"); + return 0; +} + static telnetshell_cmddef_t o1cmds[] = { {"stats", "", get_stats}, {"config", "[]", set_config}, {"bwconfig", "", set_bwconfig}, {"stop_modem", "", stop_modem}, {"start_modem", "", start_modem}, + {"remove_mac_ues", "", remove_mac_ues}, {"", "", NULL}, }; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 1faee06a39..9c6f5f4b27 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -99,7 +99,8 @@ static bool check_plmn_identity(const f1ap_plmn_t *check_plmn, const f1ap_plmn_t return plmn->mcc == check_plmn->mcc && plmn->mnc_digit_length == check_plmn->mnc_digit_length && plmn->mnc == check_plmn->mnc; } -static void du_clear_all_ue_states() +/* not static, so we can call it from the outside (in telnet) */ +void du_clear_all_ue_states() { gNB_MAC_INST *mac = RC.nrmac[0]; NR_SCHED_LOCK(&mac->sched_lock); From bcba876fcba1033e07d41248688d25b2d0ef6adc Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 6 Dec 2024 10:00:21 +0100 Subject: [PATCH 82/83] Do not free inside gnb_du_configuration_update_f1ap() The consumer of this function just passes a pointer to something to be sent. This function should not free this memory, it's simply not it's task. This is the same bug as above in "CU_handle_gNB_DU_CONFIGURATION_UPDATE(): don't free the message of RRC" --- openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c index 99e6f02a57..544ab3889c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c @@ -82,8 +82,6 @@ static void gnb_du_configuration_update_f1ap(const f1ap_gnb_du_configuration_upd f1ap_gnb_du_configuration_update_t cp = cp_f1ap_du_configuration_update(upd); /* transfer to ITTI message */ F1AP_GNB_DU_CONFIGURATION_UPDATE(msg) = cp; - /* free after copy */ - free_f1ap_du_configuration_update(upd); /* send to RRC task */ itti_send_msg_to_task(TASK_DU_F1, 0, msg); } From 59e6a33d2bec4becc899aadac17f67cacfe561e5 Mon Sep 17 00:00:00 2001 From: sagar arora Date: Fri, 6 Dec 2024 11:19:50 +0100 Subject: [PATCH 83/83] Add telnet (O1) support modules in gNB image --- docker/Dockerfile.gNB.ubuntu22 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker/Dockerfile.gNB.ubuntu22 b/docker/Dockerfile.gNB.ubuntu22 index 8d154eeb13..35e442f93d 100644 --- a/docker/Dockerfile.gNB.ubuntu22 +++ b/docker/Dockerfile.gNB.ubuntu22 @@ -95,6 +95,10 @@ COPY --from=gnb-build \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_ci.so \ /oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \ + /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_bearer.so \ + /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_5Gue.so \ + /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_rrc.so \ + /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_o1.so \ /usr/local/lib/ # Now we are copying from builder-image the UHD files.