diff --git a/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.yaml b/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.yaml index 6240b62104..918bdc9802 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.yaml +++ b/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.yaml @@ -146,6 +146,7 @@ MACRLCs: tr_n_preference: local_RRC pusch_TargetSNRx10: 200 pucch_TargetSNRx10: 200 + stats_max_ue: 17 L1s: - num_cc: 1 diff --git a/ci-scripts/conf_files/gnb.sa.band78.51prb.aw2s.ddsuu.conf b/ci-scripts/conf_files/gnb.sa.band78.51prb.aw2s.ddsuu.conf index 69cf8b7330..58571b839f 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.51prb.aw2s.ddsuu.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.51prb.aw2s.ddsuu.conf @@ -182,6 +182,7 @@ MACRLCs = ( tr_n_preference = "local_RRC"; pusch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200; + stats_max_ue = 17; } ); diff --git a/doc/MAC/mac-usage.md b/doc/MAC/mac-usage.md index 54a30cdd5f..a3b174f50c 100644 --- a/doc/MAC/mac-usage.md +++ b/doc/MAC/mac-usage.md @@ -236,6 +236,9 @@ In the `MACRLCs` section of the gNB/DU configuration file: case RSSI reaches the threshold and prevents ADC railing. Unit depends on RSSI reporting config. * `pucch_RSSI_Threshold`: Same as above but for PUCCH +* `stats_max_ue` (default 8): maximum number of UEs to show in periodical + stats; beyond this number, periodical statistics will be disabled (it can + still be seen in `nrMAC_stats.log`. Use `0` to disable periodical stats. In the `gNBs` section of the gNB/DU configuration file: some of the parameters affect RRC configuration (CellGroupConfig) of a UE, and are therefore listed diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index b0509f158d..b866a83222 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -150,7 +150,9 @@ void *L1_rx_thread(void *arg) if (res == NULL) break; processingData_L1_t *info = (processingData_L1_t *)NotifiedFifoData(res); + start_meas(&gNB->l1_rx_proc); rx_func(info); + stop_meas(&gNB->l1_rx_proc); delNotifiedFIFO_elt(res); } return NULL; @@ -164,7 +166,9 @@ void *L1_tx_thread(void *arg) { if (res == NULL) // stopping condition, happens only when queue is freed break; processingData_L1tx_t *info = (processingData_L1tx_t *)NotifiedFifoData(res); + start_meas(&gNB->l1_tx_proc); tx_func(info); + stop_meas(&gNB->l1_tx_proc); delNotifiedFIFO_elt(res); } return NULL; @@ -229,6 +233,8 @@ static void rx_func(processingData_L1_t *info) static size_t dump_L1_meas_stats(PHY_VARS_gNB *gNB, RU_t *ru, char *output, size_t outputlen) { const char *begin = output; const char *end = output + outputlen; + output += print_meas_log(&gNB->l1_tx_proc, "L1 Tx job", NULL, NULL, output, end - output); + output += print_meas_log(&gNB->l1_rx_proc, "L1 Rx job", NULL, NULL, output, end - output); output += print_meas_log(&gNB->phy_proc_tx, "L1 Tx processing", NULL, NULL, output, end - output); output += print_meas_log(&gNB->dlsch_encoding_stats, "DLSCH encoding", NULL, NULL, output, end - output); output += print_meas_log(&gNB->dlsch_scrambling_stats, "DLSCH scrambling", NULL, NULL, output, end-output); @@ -293,6 +299,8 @@ void *nrL1_stats_thread(void *param) { return NULL; } + reset_meas(&gNB->l1_tx_proc); + reset_meas(&gNB->l1_rx_proc); reset_meas(&gNB->phy_proc_tx); reset_meas(&gNB->dlsch_encoding_stats); reset_meas(&gNB->phy_proc_rx); @@ -309,13 +317,16 @@ void *nrL1_stats_thread(void *param) { reset_meas(&gNB->dlsch_precoding_stats); while (!oai_exit) { sleep(1); + if (ftruncate(fileno(fd), 0) != 0 || fseek(fd, 0, SEEK_SET) != 0) { + LOG_E(NR_MAC, "error while writing nrL1_stats.log: %d, %s\n", errno, strerror(errno)); + break; + } dump_nr_I0_stats(fd,gNB); dump_pdsch_stats(fd,gNB); dump_pusch_stats(fd,gNB); dump_L1_meas_stats(gNB, ru, output, L1STATSSTRLEN); fprintf(fd,"%s\n",output); fflush(fd); - fseek(fd,0,SEEK_SET); } fclose(fd); return(NULL); diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index ad08cc1df1..ef12f20ce5 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -464,6 +464,9 @@ typedef struct PHY_VARS_gNB_s { bool enable_analog_das; + time_stats_t l1_tx_proc; + time_stats_t l1_rx_proc; + time_stats_t phy_proc_tx; time_stats_t phy_proc_rx; time_stats_t rx_prach; diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 752211fa10..c03e3c0046 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -182,13 +182,13 @@ extern void fix_scd(NR_ServingCellConfig_t *scd);// forward declaration /* specific dlsim DL preprocessor: uses rbStart/rbSize/mcs/nrOfLayers from command line of dlsim */ int g_mcsIndex = -1, g_mcsTableIdx = 0, g_rbStart = -1, g_rbSize = -1, g_nrOfLayers = 1, g_pmi = 0; -void nr_dlsim_preprocessor(module_id_t module_id, frame_t frame, slot_t slot) +void nr_dlsim_preprocessor(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pp_pdsch) { - NR_UE_info_t *UE_info = RC.nrmac[module_id]->UE_info.connected_ue_list[0]; - AssertFatal(RC.nrmac[module_id]->UE_info.connected_ue_list[1] == NULL, "Only single UE allowed in dlsim\n"); + NR_UE_info_t *UE_info = nr_mac->UE_info.connected_ue_list[0]; + AssertFatal(nr_mac->UE_info.connected_ue_list[1] == NULL, "Only single UE allowed in dlsim\n"); NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl; NR_UE_DL_BWP_t *current_BWP = &UE_info->current_DL_BWP; - NR_ServingCellConfigCommon_t *scc = RC.nrmac[0]->common_channels[0].ServingCellConfigCommon; + NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels[0].ServingCellConfigCommon; uint8_t nr_of_candidates = 0; if (g_mcsIndex < 4) { @@ -201,8 +201,8 @@ void nr_dlsim_preprocessor(module_id_t module_id, frame_t frame, slot_t slot) &nr_of_candidates, sched_ctrl->search_space,4); } - uint32_t Y = get_Y(sched_ctrl->search_space, slot, UE_info->rnti); - int CCEIndex = find_pdcch_candidate(RC.nrmac[module_id], + uint32_t Y = get_Y(sched_ctrl->search_space, pp_pdsch->slot, UE_info->rnti); + int CCEIndex = find_pdcch_candidate(nr_mac, /* CC_id = */ 0, sched_ctrl->aggregation_level, nr_of_candidates, @@ -210,49 +210,55 @@ void nr_dlsim_preprocessor(module_id_t module_id, frame_t frame, slot_t slot) &sched_ctrl->sched_pdcch, sched_ctrl->coreset, Y); - AssertFatal(CCEIndex>=0, "%4d.%2d could not find CCE for DL DCI UE %d/RNTI %04x\n", frame, slot, 0, UE_info->rnti); + AssertFatal(CCEIndex >= 0, + "%4d.%2d could not find CCE for DL DCI UE %d/RNTI %04x\n", + pp_pdsch->frame, + pp_pdsch->slot, + 0, + UE_info->rnti); sched_ctrl->cce_index = CCEIndex; - NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; - sched_pdsch->rbStart = g_rbStart; - sched_pdsch->rbSize = g_rbSize; - sched_pdsch->bwp_info = get_pdsch_bwp_start_size(RC.nrmac[module_id], UE_info); - sched_pdsch->mcs = g_mcsIndex; - sched_pdsch->nrOfLayers = g_nrOfLayers; - sched_pdsch->pm_index = g_pmi; + NR_sched_pdsch_t sched_pdsch = { + .rbStart = g_rbStart, + .rbSize = g_rbSize, + .bwp_info = get_pdsch_bwp_start_size(nr_mac, UE_info), + .mcs = g_mcsIndex, + .nrOfLayers = g_nrOfLayers, + .pm_index = g_pmi, + }; /* the following might override the table that is mandated by RRC * configuration */ current_BWP->mcsTableIdx = g_mcsTableIdx; - sched_pdsch->time_domain_allocation = get_dl_tda(RC.nrmac[module_id], slot); - AssertFatal(sched_pdsch->time_domain_allocation >= 0,"Unable to find PDSCH time domain allocation in list\n"); + sched_pdsch.time_domain_allocation = get_dl_tda(nr_mac, pp_pdsch->slot); + AssertFatal(sched_pdsch.time_domain_allocation >= 0,"Unable to find PDSCH time domain allocation in list\n"); - sched_pdsch->tda_info = get_dl_tda_info(current_BWP, + sched_pdsch.tda_info = get_dl_tda_info(current_BWP, sched_ctrl->search_space->searchSpaceType->present, - sched_pdsch->time_domain_allocation, + sched_pdsch.time_domain_allocation, NR_MIB__dmrs_TypeA_Position_pos2, 1, TYPE_C_RNTI_, sched_ctrl->coreset->controlResourceSetId, false); - sched_pdsch->dmrs_parms = get_dl_dmrs_params(scc, + sched_pdsch.dmrs_parms = get_dl_dmrs_params(scc, current_BWP, - &sched_pdsch->tda_info, - sched_pdsch->nrOfLayers); + &sched_pdsch.tda_info, + sched_pdsch.nrOfLayers); - sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, current_BWP->mcsTableIdx); - sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, current_BWP->mcsTableIdx); - sched_pdsch->tb_size = nr_compute_tbs(sched_pdsch->Qm, - sched_pdsch->R, - sched_pdsch->rbSize, - sched_pdsch->tda_info.nrOfSymbols, - sched_pdsch->dmrs_parms.N_PRB_DMRS * sched_pdsch->dmrs_parms.N_DMRS_SLOT, + sched_pdsch.Qm = nr_get_Qm_dl(sched_pdsch.mcs, current_BWP->mcsTableIdx); + sched_pdsch.R = nr_get_code_rate_dl(sched_pdsch.mcs, current_BWP->mcsTableIdx); + sched_pdsch.tb_size = nr_compute_tbs(sched_pdsch.Qm, + sched_pdsch.R, + sched_pdsch.rbSize, + sched_pdsch.tda_info.nrOfSymbols, + sched_pdsch.dmrs_parms.N_PRB_DMRS * sched_pdsch.dmrs_parms.N_DMRS_SLOT, 0 /* N_PRB_oh, 0 for initialBWP */, 0 /* tb_scaling */, - sched_pdsch->nrOfLayers) >> 3; + sched_pdsch.nrOfLayers) >> 3; /* the simulator assumes the HARQ PID is equal to the slot number */ - sched_pdsch->dl_harq_pid = slot; + sched_pdsch.dl_harq_pid = pp_pdsch->slot; /* The scheduler uses lists to track whether a HARQ process is * free/busy/awaiting retransmission, and updates the HARQ process states. @@ -261,15 +267,17 @@ void nr_dlsim_preprocessor(module_id_t module_id, frame_t frame, slot_t slot) * Therefore, below lines just "repair" everything so that the scheduler * won't remark that there is no HARQ feedback */ sched_ctrl->feedback_dl_harq.head = -1; // always overwrite feedback HARQ process - if (sched_ctrl->harq_processes[slot].round == 0) // depending on round set in simulation ... - add_front_nr_list(&sched_ctrl->available_dl_harq, slot); // ... make PID available + if (sched_ctrl->harq_processes[pp_pdsch->slot].round == 0) // depending on round set in simulation ... + add_front_nr_list(&sched_ctrl->available_dl_harq, pp_pdsch->slot); // ... make PID available else - add_front_nr_list(&sched_ctrl->retrans_dl_harq, slot); // ... make PID retransmission - sched_ctrl->harq_processes[slot].is_waiting = false; - AssertFatal(sched_pdsch->rbStart >= 0, "invalid rbStart %d\n", sched_pdsch->rbStart); - AssertFatal(sched_pdsch->rbSize > 0, "invalid rbSize %d\n", sched_pdsch->rbSize); - AssertFatal(sched_pdsch->mcs >= 0, "invalid mcs %d\n", sched_pdsch->mcs); + add_front_nr_list(&sched_ctrl->retrans_dl_harq, pp_pdsch->slot); // ... make PID retransmission + sched_ctrl->harq_processes[pp_pdsch->slot].is_waiting = false; + AssertFatal(sched_pdsch.rbStart >= 0, "invalid rbStart %d\n", sched_pdsch.rbStart); + AssertFatal(sched_pdsch.rbSize > 0, "invalid rbSize %d\n", sched_pdsch.rbSize); + AssertFatal(sched_pdsch.mcs >= 0, "invalid mcs %d\n", sched_pdsch.mcs); AssertFatal(current_BWP->mcsTableIdx >= 0 && current_BWP->mcsTableIdx <= 2, "invalid mcsTableIdx %d\n", current_BWP->mcsTableIdx); + + post_process_dlsch(nr_mac, pp_pdsch, UE_info, &sched_pdsch); } nrUE_params_t nrUE_params; diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index a6299b10cc..6bd02cf74a 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -79,6 +79,7 @@ #define CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST "beam_weights" #define CONFIG_STRING_MACRLC_PUSCH_RSSI_THRESHOLD "pusch_RSSI_Threshold" #define CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD "pucch_RSSI_Threshold" +#define CONFIG_STRING_MACRLC_STATS_MAX_UE "stats_max_ue" #define HLP_MACRLC_UL_PRBBLACK "SNR threshold to decide whether a PRB will be blacklisted or not" #define HLP_MACRLC_DL_BLER_UP "Upper threshold of BLER to decrease DL MCS" @@ -98,6 +99,7 @@ #define HLP_MACRLC_BEAMS_PERIOD "set of beams that can be simultaneously allocated in a period" #define HLP_MACRLC_PUSCH_RSSI_THRESHOLD "Limits PUSCH TPC commands based on RSSI to prevent ADC railing. Value range [-1280, 0], unit 0.1 dBm/dBFS" #define HLP_MACRLC_PUCCH_RSSI_THRESHOLD "Limits PUCCH TPC commands based on RSSI to prevent ADC railing. Value range [-1280, 0], unit 0.1 dBm/dBFS" +#define HLP_MACRLC_STATS_MAX_UE "Maximum number of UEs before disabling periodical output (0 to disable)" /*-------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* MacRLC configuration parameters */ @@ -149,6 +151,7 @@ 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD, HLP_MACRLC_PUCCH_RSSI_THRESHOLD, \ 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ + {CONFIG_STRING_MACRLC_STATS_MAX_UE, HLP_MACRLC_STATS_MAX_UE, 0, .iptr=NULL, .defintval=8, TYPE_INT, 0}, \ } // clang-format off @@ -194,6 +197,7 @@ #define MACRLC_BEAMWEIGHTS_IDX 39 #define MACRLC_PUSCH_RSSI_THRES_IDX 40 #define MACRLC_PUCCH_RSSI_THRES_IDX 41 +#define MACRLC_STATS_MAX_UE_IDX 42 #define MACRLCPARAMS_CHECK { \ { .s5 = { NULL } }, \ @@ -238,6 +242,7 @@ { .s5 = { NULL } }, \ { .s2 = { config_check_intrange, {-1280, 0}} }, /* PUSCH RSSI threshold range */ \ { .s2 = { config_check_intrange, {-1280, 0}} }, /* PUCCH RSSI threshold range */ \ + { .s5 = { NULL } }, \ } /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 056387de92..5238df77fa 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1582,6 +1582,8 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) AssertFatal(1 == 0, "MACRLC %d: %s unknown southbound midhaul\n", j, *(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr)); } RC.nrmac[j]->ulsch_max_frame_inactivity = *(MacRLC_ParamList.paramarray[j][MACRLC_ULSCH_MAX_FRAME_INACTIVITY].uptr); + RC.nrmac[j]->stats_max_ue = *MacRLC_ParamList.paramarray[j][MACRLC_STATS_MAX_UE_IDX].iptr; + RC.nrmac[j]->print_ue_stats = RC.nrmac[j]->stats_max_ue > 0; NR_bler_options_t *dl_bler_options = &RC.nrmac[j]->dl_bler; dl_bler_options->upper = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_UPPER_IDX].dblptr); dl_bler_options->lower = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_LOWER_IDX].dblptr); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index 46ad8069da..a102411721 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -195,10 +195,23 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, slot_t slo } bool wait_prach_completed = gNB->num_scheduled_prach_rx >= NUM_PRACH_RX_FOR_NOISE_ESTIMATE; - if ((wait_prach_completed || get_softmodem_params()->phy_test) && (slot == 0) && (frame & 127) == 0) { + if (gNB->print_ue_stats && (wait_prach_completed || get_softmodem_params()->phy_test) && (slot == 0) && (frame & 127) == 0) { char stats_output[32656] = {0}; dump_mac_stats(gNB, stats_output, sizeof(stats_output), true); LOG_I(NR_MAC, "Frame.Slot %d.%d\n%s\n", frame, slot, stats_output); + + // TODO: this should be replaced with a size() operation on connected_ue_list + int num_ue = 0; + UE_iterator(gNB->UE_info.connected_ue_list, it) { + (void) it; // not used + num_ue++; + } + if (gNB->print_ue_stats && num_ue > gNB->stats_max_ue) { + gNB->print_ue_stats = false; + LOG_W(NR_MAC, + "periodical UE stats deactivated after reaching %d UEs, please check nrMAC_stats.log, or increase MACRLCs.[0].stats_max_ue\n", + gNB->stats_max_ue); + } } nr_measgap_scheduling(gNB, frame, slot); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 198975f1ae..8478df8916 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -2119,10 +2119,9 @@ static void nr_fill_rar(uint8_t Mod_idP, NR_UE_info_t *UE, uint8_t *dlsch_buffer * The corresponding function to add is add_new_UE_RA(). */ void nr_release_ra_UE(gNB_MAC_INST *mac, rnti_t rnti) { + NR_SCHED_ENSURE_LOCKED(&mac->sched_lock); NR_UEs_t *UE_info = &mac->UE_info; - NR_SCHED_LOCK(&UE_info->mutex); NR_UE_info_t *UE = remove_UE_from_list(NR_NB_RA_PROC_MAX, UE_info->access_ue_list, rnti); - NR_SCHED_UNLOCK(&UE_info->mutex); if (UE) { delete_nr_ue_data(UE, mac->common_channels, &UE_info->uid_allocator); } else { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 8a81d8ae4f..1f6fb64181 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -274,35 +274,32 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, slot_t slotP, nfapi } } -static uint32_t get_tbs_bch(NR_sched_pdsch_t *pdsch, - uint32_t num_total_bytes, - uint16_t *vrb_map) +static void update_rb_mcs_tbs(NR_sched_pdsch_t *pdsch, uint32_t num_total_bytes, uint16_t *vrb_map) { - NR_tda_info_t *tda_info = &pdsch->tda_info; + const NR_tda_info_t *tda_info = &pdsch->tda_info; // Calculate number of PRB_DMRS uint8_t N_PRB_DMRS = pdsch->dmrs_parms.N_PRB_DMRS; LOG_D(MAC, "dlDmrsSymbPos %x\n", pdsch->dmrs_parms.dl_dmrs_symb_pos); int mcsTableIdx = 0; - uint32_t TBS = 0; const uint16_t slbitmap = SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols); int bwpSize = pdsch->bwp_info.bwpSize; int bwpStart = pdsch->bwp_info.bwpStart; int rbStop = bwpSize - 1; - int rbStart = 0; - uint16_t rbSize = 0; - while (rbStart < rbStop) { - if (vrb_map[rbStart + bwpStart] & slbitmap) - rbStart++; + while (pdsch->rbStart < rbStop) { + if (vrb_map[pdsch->rbStart + bwpStart] & slbitmap) + pdsch->rbStart++; else { int max_rbSize = 0; - while (rbStart + max_rbSize <= rbStop && !(vrb_map[rbStart + max_rbSize + bwpStart] & slbitmap)) + while (pdsch->rbStart + max_rbSize <= rbStop && !(vrb_map[pdsch->rbStart + max_rbSize + bwpStart] & slbitmap)) max_rbSize++; bool res = false; while (res == false && pdsch->mcs < 10) { - res = nr_find_nb_rb(nr_get_Qm_dl(pdsch->mcs, mcsTableIdx), - nr_get_code_rate_dl(pdsch->mcs, mcsTableIdx), + pdsch->Qm = nr_get_Qm_dl(pdsch->mcs, mcsTableIdx); + pdsch->R = nr_get_code_rate_dl(pdsch->mcs, mcsTableIdx); + res = nr_find_nb_rb(pdsch->Qm, + pdsch->R, 1, // no transform precoding for DL 1, // single layer tda_info->nrOfSymbols, @@ -310,59 +307,56 @@ static uint32_t get_tbs_bch(NR_sched_pdsch_t *pdsch, num_total_bytes, 1, // min_rbSize max_rbSize, - &TBS, - &rbSize); + &pdsch->tb_size, + &pdsch->rbSize); if (!res) pdsch->mcs++; } break; } } - AssertFatal(TBS >= num_total_bytes, + AssertFatal(pdsch->tb_size >= num_total_bytes, "Couldn't allocate enough resources for %d bytes in SIB PDSCH (rbStart %d, rbSize %d, bwpSize %d)\n", num_total_bytes, - rbStart, - rbSize, + pdsch->rbStart, + pdsch->rbSize, bwpSize); - pdsch->rbSize = rbSize; - pdsch->rbStart = rbStart; - LOG_D(NR_MAC, "mcs=%i, startSymbolIndex = %i, nrOfSymbols = %i, rbSize = %i, TBS = %i, dmrs_length %d, N_PRB_DMRS = %d, mappingtype = %d\n", pdsch->mcs, tda_info->startSymbolIndex, tda_info->nrOfSymbols, - rbSize, - TBS, + pdsch->rbSize, + pdsch->tb_size, pdsch->dmrs_parms.N_DMRS_SLOT, N_PRB_DMRS, tda_info->mapping_type); - return TBS; } -static uint32_t schedule_control_sib1(gNB_MAC_INST *gNB_mac, - int CC_id, - NR_sched_pdcch_t *pdcch, - NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config, - int time_domain_allocation, - NR_pdsch_dmrs_t *dmrs_parms, - NR_tda_info_t *tda_info, - uint8_t candidate_idx, - int beam, - uint16_t num_total_bytes) +static NR_sched_pdsch_t schedule_control_sib1(gNB_MAC_INST *gNB_mac, + int CC_id, + NR_sched_pdcch_t *pdcch, + NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config, + int time_domain_allocation, + NR_pdsch_dmrs_t *dmrs_parms, + NR_tda_info_t *tda_info, + uint8_t candidate_idx, + int beam, + uint16_t num_total_bytes) { AssertFatal(gNB_mac->sched_ctrlCommon, "sched_ctrlCommon is NULL\n"); NR_COMMON_channels_t *cc = &gNB_mac->common_channels[CC_id]; uint16_t *vrb_map = cc->vrb_map[beam]; - NR_sched_pdsch_t *pdsch = &gNB_mac->sched_ctrlCommon->sched_pdsch; - pdsch->bwp_info = get_pdsch_bwp_start_size(gNB_mac, NULL); - pdsch->time_domain_allocation = time_domain_allocation; - pdsch->dmrs_parms = *dmrs_parms; - pdsch->tda_info = *tda_info; - pdsch->nrOfLayers = 1; - pdsch->pm_index = 0; - pdsch->mcs = 0; // starting from mcs 0 + NR_sched_pdsch_t pdsch = { + .bwp_info = get_pdsch_bwp_start_size(gNB_mac, NULL), + .time_domain_allocation = time_domain_allocation, + .dmrs_parms = *dmrs_parms, + .tda_info = *tda_info, + .nrOfLayers = 1, + .pm_index = 0, + .mcs = 0, // starting from mcs 0 + }; gNB_mac->sched_ctrlCommon->num_total_bytes = num_total_bytes; uint8_t nr_of_candidates = 0; @@ -383,12 +377,7 @@ static uint32_t schedule_control_sib1(gNB_MAC_INST *gNB_mac, AssertFatal(gNB_mac->sched_ctrlCommon->cce_index >= 0, "Could not find CCE for coreset0\n"); - uint32_t TBS = get_tbs_bch(&gNB_mac->sched_ctrlCommon->sched_pdsch, - gNB_mac->sched_ctrlCommon->num_total_bytes, - vrb_map); - - pdsch->R = nr_get_code_rate_dl(pdsch->mcs, 0); - pdsch->Qm = nr_get_Qm_dl(pdsch->mcs, 0); + update_rb_mcs_tbs(&pdsch, gNB_mac->sched_ctrlCommon->num_total_bytes, vrb_map); // Mark the corresponding RBs as used fill_pdcch_vrb_map(gNB_mac, @@ -397,10 +386,10 @@ static uint32_t schedule_control_sib1(gNB_MAC_INST *gNB_mac, gNB_mac->sched_ctrlCommon->cce_index, gNB_mac->sched_ctrlCommon->aggregation_level, beam); - for (int rb = 0; rb < pdsch->rbSize; rb++) { + for (int rb = 0; rb < pdsch.rbSize; rb++) { vrb_map[rb + type0_PDCCH_CSS_config->cset_start_rb] |= SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols); } - return TBS; + return pdsch; } static void nr_fill_nfapi_dl_SIB_pdu(gNB_MAC_INST *gNB_mac, @@ -578,22 +567,21 @@ void schedule_nr_sib1(module_id_t module_idP, NR_COMMON_channels_t *cc = &gNB_mac->common_channels[0]; // Configure sched_ctrlCommon for SIB1 - uint32_t TBS = schedule_control_sib1(gNB_mac, - CC_id, - &sched_pdcch, - type0_PDCCH_CSS_config, - time_domain_allocation, - &dmrs_parms, - &tda_info, - candidate_idx, - beam.idx, - cc->sib1_bcch_length); + NR_sched_pdsch_t sched_pdsch = schedule_control_sib1(gNB_mac, + CC_id, + &sched_pdcch, + type0_PDCCH_CSS_config, + time_domain_allocation, + &dmrs_parms, + &tda_info, + candidate_idx, + beam.idx, + cc->sib1_bcch_length); - gNB_mac->sched_ctrlCommon->sched_pdsch.tb_size = TBS; nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body; int pdu_index = gNB_mac->pdu_index[0]++; nr_fill_nfapi_dl_SIB_pdu(gNB_mac, - &gNB_mac->sched_ctrlCommon->sched_pdsch, + &sched_pdsch, &sched_pdcch, gNB_mac->sched_ctrlCommon->search_space, gNB_mac->sched_ctrlCommon->coreset, @@ -609,11 +597,11 @@ void schedule_nr_sib1(module_id_t module_idP, nfapi_nr_pdu_t *tx_req = &TX_req->pdu_list[ntx_req]; // Data to be transmitted - memcpy(tx_req->TLVs[0].value.direct, cc->sib1_bcch_pdu, TBS); + memcpy(tx_req->TLVs[0].value.direct, cc->sib1_bcch_pdu, sched_pdsch.tb_size); tx_req->PDU_index = pdu_index; tx_req->num_TLV = 1; - tx_req->TLVs[0].length = TBS; + tx_req->TLVs[0].length = sched_pdsch.tb_size; tx_req->PDU_length = compute_PDU_length(tx_req->num_TLV, tx_req->TLVs[0].length); TX_req->Number_of_PDUs++; TX_req->SFN = frameP; @@ -718,9 +706,7 @@ static void other_sib_sched_control(module_id_t module_idP, uint16_t *vrb_map = cc->vrb_map[beam.idx]; uint8_t *sib_bcch_pdu = cc->other_sib_bcch_pdu[payload_idx]; int num_total_bytes = cc->other_sib_bcch_length[payload_idx]; - sched_pdsch_otherSI.tb_size = get_tbs_bch(&sched_pdsch_otherSI, num_total_bytes, vrb_map); - sched_pdsch_otherSI.R = nr_get_code_rate_dl(sched_pdsch_otherSI.mcs, 0); - sched_pdsch_otherSI.Qm = nr_get_Qm_dl(sched_pdsch_otherSI.mcs, 0); + update_rb_mcs_tbs(&sched_pdsch_otherSI, num_total_bytes, vrb_map); for (int rb = 0; rb < sched_pdsch_otherSI.rbSize; rb++) { vrb_map[rb + type0_PDCCH_CSS_config->cset_start_rb] |= SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols); @@ -747,10 +733,10 @@ static void other_sib_sched_control(module_id_t module_idP, // Data to be transmitted memcpy(tx_req->TLVs[0].value.direct, sib_bcch_pdu, sched_pdsch_otherSI.tb_size); - tx_req->PDU_length = sched_pdsch_otherSI.tb_size; tx_req->PDU_index = pdu_index; tx_req->num_TLV = 1; - tx_req->TLVs[0].length = sched_pdsch_otherSI.tb_size + 2; + tx_req->TLVs[0].length = sched_pdsch_otherSI.tb_size; + tx_req->PDU_length = compute_PDU_length(tx_req->num_TLV, tx_req->TLVs[0].length); TX_req->Number_of_PDUs++; TX_req->SFN = frame; TX_req->Slot = slot; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 44c9072a15..d848cf99c8 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -321,46 +321,41 @@ int nr_write_ce_dlsch_pdu(module_id_t module_idP, return offset; } -static void nr_store_dlsch_buffer(module_id_t module_id, frame_t frame, slot_t slot) +static uint32_t update_dlsch_buffer(frame_t frame, slot_t slot, NR_UE_info_t *UE) { - UE_iterator(RC.nrmac[module_id]->UE_info.connected_ue_list, UE) { - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - sched_ctrl->num_total_bytes = 0; - sched_ctrl->dl_pdus_total = 0; + NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + sched_ctrl->num_total_bytes = 0; + sched_ctrl->dl_pdus_total = 0; - /* loop over all activated logical channels */ - // Note: DL_SCH_LCID_DCCH, DL_SCH_LCID_DCCH1, DL_SCH_LCID_DTCH - for (int i = 0; i < seq_arr_size(&sched_ctrl->lc_config); ++i) { - const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, i); - const int lcid = c->lcid; - const uint16_t rnti = UE->rnti; - LOG_D(NR_MAC, "In %s: UE %x: LCID %d\n", __FUNCTION__, rnti, lcid); - memset(&sched_ctrl->rlc_status[lcid], 0, sizeof(sched_ctrl->rlc_status[lcid])); - if (c->suspended) - continue; - if (lcid == DL_SCH_LCID_DTCH && nr_timer_is_active(&sched_ctrl->transm_interrupt)) - continue; - sched_ctrl->rlc_status[lcid] = nr_mac_rlc_status_ind(rnti, frame, lcid); + /* loop over all activated logical channels */ + for (int i = 0; i < seq_arr_size(&sched_ctrl->lc_config); ++i) { + const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, i); + const int lcid = c->lcid; + const uint16_t rnti = UE->rnti; + LOG_D(NR_MAC, "UE %x: LCID %d\n", rnti, lcid); + memset(&sched_ctrl->rlc_status[lcid], 0, sizeof(sched_ctrl->rlc_status[lcid])); + if (c->suspended) + continue; + if (lcid == DL_SCH_LCID_DTCH && nr_timer_is_active(&sched_ctrl->transm_interrupt)) + continue; + sched_ctrl->rlc_status[lcid] = nr_mac_rlc_status_ind(rnti, frame, lcid); - if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0) - continue; + if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0) + continue; - sched_ctrl->dl_pdus_total += sched_ctrl->rlc_status[lcid].pdus_in_buffer; - sched_ctrl->num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer; - LOG_D(MAC, - "[gNB %d][%4d.%2d] %s%d->DLSCH, RLC status for UE %d: %d bytes in buffer, total DL buffer size = %d bytes, %d total PDU bytes, %s TA command\n", - module_id, - frame, - slot, - lcid < 4 ? "DCCH":"DTCH", - lcid, - UE->rnti, - sched_ctrl->rlc_status[lcid].bytes_in_buffer, - sched_ctrl->num_total_bytes, - sched_ctrl->dl_pdus_total, - sched_ctrl->ta_apply ? "send":"do not send"); - } + sched_ctrl->dl_pdus_total += sched_ctrl->rlc_status[lcid].pdus_in_buffer; + sched_ctrl->num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer; + LOG_D(MAC, + "%4d.%2d UE %04x LCID %d status: %d bytes, total buffer %d bytes %d PDUs\n", + frame, + slot, + UE->rnti, + lcid, + sched_ctrl->rlc_status[lcid].bytes_in_buffer, + sched_ctrl->num_total_bytes, + sched_ctrl->dl_pdus_total); } + return sched_ctrl->num_total_bytes; } void finish_nr_dl_harq(NR_UE_sched_ctrl_t *sched_ctrl, int harq_pid) @@ -422,29 +417,30 @@ bwp_info_t get_pdsch_bwp_start_size(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE) return bwp_info; } -static bool allocate_dl_retransmission(module_id_t module_id, - frame_t frame, - slot_t slot, +static bool allocate_dl_retransmission(gNB_MAC_INST *nr_mac, + post_process_pdsch_t *pp_pdsch, int *n_rb_sched, NR_UE_info_t *UE, int beam_idx, int current_harq_pid) { - + frame_t frame = pp_pdsch->frame; + slot_t slot = pp_pdsch->slot; int CC_id = 0; - gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; + const NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels->ServingCellConfigCommon; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; - NR_sched_pdsch_t *retInfo = &sched_ctrl->harq_processes[current_harq_pid].sched_pdsch; - NR_sched_pdsch_t *curInfo = &sched_ctrl->sched_pdsch; + NR_sched_pdsch_t new_sched = sched_ctrl->harq_processes[current_harq_pid].sched_pdsch; + int layers = get_dl_nrOfLayers(sched_ctrl, dl_bwp->dci_format); + int pm_index = get_pm_index(nr_mac, UE, dl_bwp->dci_format, layers, nr_mac->radio_config.pdsch_AntennaPorts.XP); // If the RI changed between current rtx and a previous transmission // we need to verify if it is not decreased // othwise it wouldn't be possible to transmit the same TBS - int layers = (curInfo->nrOfLayers < retInfo->nrOfLayers) ? curInfo->nrOfLayers : retInfo->nrOfLayers; - int pm_index = (curInfo->nrOfLayers < retInfo->nrOfLayers) ? curInfo->pm_index : retInfo->pm_index; + layers = (layers < new_sched.nrOfLayers) ? layers : new_sched.nrOfLayers; + pm_index = (layers < new_sched.nrOfLayers) ? pm_index : new_sched.pm_index; const int coresetid = sched_ctrl->coreset->controlResourceSetId; const int tda = get_dl_tda(nr_mac, slot); @@ -463,11 +459,11 @@ static bool allocate_dl_retransmission(module_id_t module_id, if (!temp_tda.valid_tda) return false; - bool reuse_old_tda = (retInfo->tda_info.startSymbolIndex == temp_tda.startSymbolIndex) && (retInfo->tda_info.nrOfSymbols <= temp_tda.nrOfSymbols); + bool reuse_old_tda = (new_sched.tda_info.startSymbolIndex == temp_tda.startSymbolIndex) && (new_sched.tda_info.nrOfSymbols <= temp_tda.nrOfSymbols); LOG_D(NR_MAC, "[UE %x] %s old TDA, %s number of layers\n", UE->rnti, reuse_old_tda ? "reuse" : "do not reuse", - layers == retInfo->nrOfLayers ? "same" : "different"); + layers == new_sched.nrOfLayers ? "same" : "different"); uint16_t *rballoc_mask = nr_mac->common_channels[CC_id].vrb_map[beam_idx]; @@ -476,13 +472,13 @@ static bool allocate_dl_retransmission(module_id_t module_id, int rbStop = bwp_info.bwpStart + bwp_info.bwpSize - 1; int rbSize = 0; - if (reuse_old_tda && layers == retInfo->nrOfLayers) { + if (reuse_old_tda && layers == new_sched.nrOfLayers) { /* Check that there are enough resources for retransmission */ - while (rbSize < retInfo->rbSize) { + while (rbSize < new_sched.rbSize) { rbStart += rbSize; /* last iteration rbSize was not enough, skip it */ rbSize = 0; - const uint16_t slbitmap = SL_to_bitmap(retInfo->tda_info.startSymbolIndex, retInfo->tda_info.nrOfSymbols); + const uint16_t slbitmap = SL_to_bitmap(new_sched.tda_info.startSymbolIndex, new_sched.tda_info.nrOfSymbols); while (rbStart < rbStop && (rballoc_mask[rbStart] & slbitmap)) rbStart++; @@ -491,8 +487,9 @@ static bool allocate_dl_retransmission(module_id_t module_id, return false; } - while (rbStart + rbSize <= rbStop && !(rballoc_mask[rbStart + rbSize] & slbitmap) && rbSize < retInfo->rbSize) + while (rbStart + rbSize <= rbStop && !(rballoc_mask[rbStart + rbSize] & slbitmap) && rbSize < new_sched.rbSize) rbSize++; + DevAssert(rbSize > 0); } } else { /* the retransmission will use a different time domain allocation, check @@ -503,42 +500,48 @@ static bool allocate_dl_retransmission(module_id_t module_id, while (rbStart < rbStop && (rballoc_mask[rbStart] & slbitmap)) rbStart++; + if (rbStart >= rbStop) { + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate DL retransmission: no resources\n", UE->rnti, frame, slot); + return false; + } + while (rbStart + rbSize <= rbStop && !(rballoc_mask[rbStart + rbSize] & slbitmap)) rbSize++; + DevAssert(rbSize > 0); uint32_t new_tbs; uint16_t new_rbSize; - bool success = nr_find_nb_rb(retInfo->Qm, - retInfo->R, + bool success = nr_find_nb_rb(new_sched.Qm, + new_sched.R, 1, // no transform precoding for DL layers, temp_tda.nrOfSymbols, temp_dmrs.N_PRB_DMRS * temp_dmrs.N_DMRS_SLOT, - retInfo->tb_size, + new_sched.tb_size, 1, /* minimum of 1RB: need to find exact TBS, don't preclude any number */ rbSize, &new_tbs, &new_rbSize); - if (!success || new_tbs != retInfo->tb_size) { + if (!success || new_tbs != new_sched.tb_size) { LOG_D(NR_MAC, "[UE %04x][%4d.%2d] allocation of DL retransmission failed: new TBS %d of new TDA does not match old TBS %d\n", UE->rnti, frame, slot, new_tbs, - retInfo->tb_size); + new_sched.tb_size); return false; /* the maximum TBsize we might have is smaller than what we need */ } /* we can allocate it. Overwrite the time_domain_allocation, the number * of RBs, and the new TB size. The rest is done below */ - retInfo->tb_size = new_tbs; - retInfo->rbSize = new_rbSize; - retInfo->time_domain_allocation = tda; - retInfo->nrOfLayers = layers; - retInfo->pm_index = pm_index; - retInfo->dmrs_parms = temp_dmrs; - retInfo->tda_info = temp_tda; + new_sched.tb_size = new_tbs; + new_sched.rbSize = new_rbSize; + new_sched.time_domain_allocation = tda; + new_sched.nrOfLayers = layers; + new_sched.pm_index = pm_index; + new_sched.dmrs_parms = temp_dmrs; + new_sched.tda_info = temp_tda; } /* Find a free CCE */ @@ -573,24 +576,26 @@ static bool allocate_dl_retransmission(module_id_t module_id, sched_ctrl->cce_index = CCEIndex; fill_pdcch_vrb_map(nr_mac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, beam_idx); - /* just reuse from previous scheduling opportunity, set new start RB */ - sched_ctrl->sched_pdsch = *retInfo; - sched_ctrl->sched_pdsch.rbStart = rbStart - bwp_info.bwpStart; - sched_ctrl->sched_pdsch.pucch_allocation = alloc; - sched_ctrl->sched_pdsch.bwp_info = bwp_info; - /* retransmissions: directly allocate */ - *n_rb_sched -= sched_ctrl->sched_pdsch.rbSize; - for (int rb = rbStart; rb < sched_ctrl->sched_pdsch.rbSize; rb++) - rballoc_mask[rb] |= SL_to_bitmap(retInfo->tda_info.startSymbolIndex, retInfo->tda_info.nrOfSymbols); + new_sched.rbStart = rbStart - bwp_info.bwpStart; + new_sched.pucch_allocation = alloc; + new_sched.bwp_info = bwp_info; + + post_process_dlsch(nr_mac, pp_pdsch, UE, &new_sched); + + /* retransmissions: directly allocate */ + *n_rb_sched -= new_sched.rbSize; + + for (int rb = rbStart; rb < new_sched.rbSize; rb++) + rballoc_mask[rb] |= SL_to_bitmap(new_sched.tda_info.startSymbolIndex, new_sched.tda_info.nrOfSymbols); return true; } -static uint32_t pf_tbs[3][29]; // pre-computed, approximate TBS values for PF coefficient typedef struct UEsched_s { float coef; NR_UE_info_t * UE; + int selected_mcs; } UEsched_t; static int comparator(const void *p, const void *q) @@ -604,15 +609,16 @@ static int comparator(const void *p, const void *q) return 0; } -static void pf_dl(module_id_t module_id, - frame_t frame, - slot_t slot, +static void pf_dl(gNB_MAC_INST *mac, + post_process_pdsch_t *pp_pdsch, NR_UE_info_t **UE_list, int max_num_ue, int num_beams, int n_rb_sched[num_beams]) { - gNB_MAC_INST *mac = RC.nrmac[module_id]; + frame_t frame = pp_pdsch->frame; + slot_t slot = pp_pdsch->slot; + NR_ServingCellConfigCommon_t *scc=mac->common_channels[0].ServingCellConfigCommon; // UEs that could be scheduled UEsched_t UE_sched[MAX_MOBILES_PER_GNB + 1] = {0}; @@ -631,16 +637,23 @@ static void pf_dl(module_id_t module_id, if (!nr_mac_ue_is_active(UE)) continue; - const NR_mac_dir_stats_t *stats = &UE->mac_stats.dl; - NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; + NR_mac_dir_stats_t *stats = &UE->mac_stats.dl; /* get the PID of a HARQ process awaiting retrnasmission, or -1 otherwise */ - sched_pdsch->dl_harq_pid = sched_ctrl->retrans_dl_harq.head; + int harq_pid = sched_ctrl->retrans_dl_harq.head; /* Calculate Throughput */ const float a = 0.01f; - const uint32_t b = UE->mac_stats.dl.current_bytes; + const uint32_t b = stats->current_bytes; UE->dl_thr_ue = (1 - a) * UE->dl_thr_ue + a * b; + stats->current_bytes = 0; + stats->current_rbs = 0; + + /* Check if this UE should get TA (every 100 frames). If we add the CE, + * ta_apply will be reset */ + if (frame == ((sched_ctrl->ta_frame + 100) % 1024)) + sched_ctrl->ta_apply = true; + int total_rem_ues = 0; for (int i = 0; i < num_beams; i++) total_rem_ues += remainUEs[i]; @@ -648,12 +661,12 @@ static void pf_dl(module_id_t module_id, continue; /* retransmission */ - if (sched_pdsch->dl_harq_pid >= 0) { + if (harq_pid >= 0) { NR_beam_alloc_t beam = beam_allocation_procedure(&mac->beam_info, frame, slot, UE->UE_beam_index, slots_per_frame); bool sch_ret = beam.idx >= 0; /* Allocate retransmission */ if (sch_ret) - sch_ret = allocate_dl_retransmission(module_id, frame, slot, &n_rb_sched[beam.idx], UE, beam.idx, sched_pdsch->dl_harq_pid); + sch_ret = allocate_dl_retransmission(mac, pp_pdsch, &n_rb_sched[beam.idx], UE, beam.idx, harq_pid); if (!sch_ret) { LOG_D(NR_MAC, "[UE %04x][%4d.%2d] DL retransmission could not be allocated\n", UE->rnti, frame, slot); reset_beam_status(&mac->beam_info, frame, slot, UE->UE_beam_index, slots_per_frame, beam.new_beam); @@ -674,6 +687,8 @@ static void pf_dl(module_id_t module_id, continue; } + update_dlsch_buffer(pp_pdsch->frame, pp_pdsch->slot, UE); + /* Check DL buffer and skip this UE if no bytes and no TA necessary */ if (sched_ctrl->num_total_bytes == 0 && frame != (sched_ctrl->ta_frame + 100) % 1024) continue; @@ -682,17 +697,16 @@ static void pf_dl(module_id_t module_id, const NR_bler_options_t *bo = &mac->dl_bler; const int max_mcs_table = current_BWP->mcsTableIdx == 1 ? 27 : 28; const int max_mcs = min(sched_ctrl->dl_max_mcs, max_mcs_table); + int selected_mcs; if (bo->harq_round_max == 1) { int new_mcs = min(bo->max_mcs, max_mcs); - sched_pdsch->mcs = max(bo->min_mcs, new_mcs); - sched_ctrl->dl_bler_stats.mcs = sched_pdsch->mcs; + selected_mcs = max(bo->min_mcs, new_mcs); + sched_ctrl->dl_bler_stats.mcs = selected_mcs; } else - sched_pdsch->mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->dl_bler_stats, max_mcs, frame); - sched_pdsch->nrOfLayers = get_dl_nrOfLayers(sched_ctrl, current_BWP->dci_format); - sched_pdsch->pm_index = - get_pm_index(mac, UE, current_BWP->dci_format, sched_pdsch->nrOfLayers, mac->radio_config.pdsch_AntennaPorts.XP); - const uint8_t Qm = nr_get_Qm_dl(sched_pdsch->mcs, current_BWP->mcsTableIdx); - const uint16_t R = nr_get_code_rate_dl(sched_pdsch->mcs, current_BWP->mcsTableIdx); + selected_mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->dl_bler_stats, max_mcs, frame); + int l = get_dl_nrOfLayers(sched_ctrl, current_BWP->dci_format); + const uint8_t Qm = nr_get_Qm_dl(selected_mcs, current_BWP->mcsTableIdx); + const uint16_t R = nr_get_code_rate_dl(selected_mcs, current_BWP->mcsTableIdx); uint32_t tbs = nr_compute_tbs(Qm, R, 1, /* rbSize */ @@ -700,7 +714,7 @@ static void pf_dl(module_id_t module_id, 0, /* N_PRB_DMRS * N_DMRS_SLOT */ 0 /* N_PRB_oh, 0 for initialBWP */, 0 /* tb_scaling */, - sched_pdsch->nrOfLayers) >> 3; + l) >> 3; float coeff_ue = (float) tbs / UE->dl_thr_ue; LOG_D(NR_MAC, "[UE %04x][%4d.%2d] b %d, thr_ue %f, tbs %d, coeff_ue %f\n", UE->rnti, @@ -713,6 +727,7 @@ static void pf_dl(module_id_t module_id, /* Create UE_sched list for UEs eligible for new transmission*/ UE_sched[numUE].coef = coeff_ue; UE_sched[numUE].UE = UE; + UE_sched[numUE].selected_mcs = selected_mcs; numUE++; } } @@ -753,33 +768,28 @@ static void pf_dl(module_id_t module_id, continue; } - NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; - sched_pdsch->dl_harq_pid = sched_ctrl->available_dl_harq.head; - /* MCS has been set above */ - sched_pdsch->time_domain_allocation = get_dl_tda(mac, slot); - AssertFatal(sched_pdsch->time_domain_allocation>=0,"Unable to find PDSCH time domain allocation in list\n"); + int tda = get_dl_tda(mac, slot); + AssertFatal(tda >= 0,"Unable to find PDSCH time domain allocation in list\n"); const int coresetid = sched_ctrl->coreset->controlResourceSetId; - sched_pdsch->tda_info = get_dl_tda_info(dl_bwp, + NR_tda_info_t tda_info = get_dl_tda_info(dl_bwp, sched_ctrl->search_space->searchSpaceType->present, - sched_pdsch->time_domain_allocation, + tda, scc->dmrs_TypeA_Position, 1, TYPE_C_RNTI_, coresetid, false); - AssertFatal(sched_pdsch->tda_info.valid_tda, "Invalid TDA from get_dl_tda_info\n"); + AssertFatal(tda_info.valid_tda, "Invalid TDA from get_dl_tda_info\n"); - NR_tda_info_t *tda_info = &sched_pdsch->tda_info; - - const uint16_t slbitmap = SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols); + const uint16_t slbitmap = SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols); uint16_t *rballoc_mask = mac->common_channels[CC_id].vrb_map[beam.idx]; - sched_pdsch->bwp_info = get_pdsch_bwp_start_size(mac, iterator->UE); + bwp_info_t bwp_info = get_pdsch_bwp_start_size(mac, iterator->UE); int rbStart = 0; // WRT BWP start - int rbStop = sched_pdsch->bwp_info.bwpSize - 1; - int bwp_start = sched_pdsch->bwp_info.bwpStart; + int rbStop = bwp_info.bwpSize - 1; + int bwp_start = bwp_info.bwpStart; // Freq-demain allocation while (rbStart < rbStop && (rballoc_mask[rbStart + bwp_start] & slbitmap)) rbStart++; @@ -825,7 +835,7 @@ static void pf_dl(module_id_t module_id, * allocation after CCE alloc fail would be more complex) */ int alloc = -1; - if (!get_FeedbackDisabled(iterator->UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, sched_pdsch->dl_harq_pid)) { + if (!get_FeedbackDisabled(iterator->UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, sched_ctrl->available_dl_harq.head)) { int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, ul_bwp->pucch_Config, CCEIndex); alloc = nr_acknack_scheduling(mac, iterator->UE, frame, slot, iterator->UE->UE_beam_index, r_pucch, 0); if (alloc < 0) { @@ -839,46 +849,57 @@ static void pf_dl(module_id_t module_id, sched_ctrl->cce_index = CCEIndex; fill_pdcch_vrb_map(mac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, beam.idx); - sched_pdsch->dmrs_parms = get_dl_dmrs_params(scc, dl_bwp, tda_info, sched_pdsch->nrOfLayers); - sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx); - sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx); - sched_pdsch->pucch_allocation = alloc; - uint32_t TBS = 0; - uint16_t rbSize; + int l = get_dl_nrOfLayers(sched_ctrl, dl_bwp->dci_format); + NR_sched_pdsch_t sched_pdsch = { + // rbSize below + .rbStart = rbStart, + .mcs = iterator->selected_mcs, + .R = nr_get_code_rate_dl(iterator->selected_mcs, dl_bwp->mcsTableIdx), + .Qm = nr_get_Qm_dl(iterator->selected_mcs, dl_bwp->mcsTableIdx), + // tb_size below + .dl_harq_pid = sched_ctrl->available_dl_harq.head, + .pucch_allocation = alloc, + .pm_index = get_pm_index(mac, iterator->UE, dl_bwp->dci_format, l, mac->radio_config.pdsch_AntennaPorts.XP), + .nrOfLayers = l, + .bwp_info = bwp_info, + .dmrs_parms = get_dl_dmrs_params(scc, dl_bwp, &tda_info, l), + .time_domain_allocation = tda, + .tda_info = tda_info, + }; + // Fix me: currently, the RLC does not give us the total number of PDUs // awaiting. Therefore, for the time being, we put a fixed overhead of 12 // (for 4 PDUs) and optionally + 2 for TA. Once RLC gives the number of // PDUs, we replace with 3 * numPDUs const int oh = 3 * 4 + 2 * (frame == (sched_ctrl->ta_frame + 100) % 1024); //const int oh = 3 * sched_ctrl->dl_pdus_total + 2 * (frame == (sched_ctrl->ta_frame + 100) % 1024); - nr_find_nb_rb(sched_pdsch->Qm, - sched_pdsch->R, + nr_find_nb_rb(sched_pdsch.Qm, + sched_pdsch.R, 1, // no transform precoding for DL - sched_pdsch->nrOfLayers, - tda_info->nrOfSymbols, - sched_pdsch->dmrs_parms.N_PRB_DMRS * sched_pdsch->dmrs_parms.N_DMRS_SLOT, + sched_pdsch.nrOfLayers, + tda_info.nrOfSymbols, + sched_pdsch.dmrs_parms.N_PRB_DMRS * sched_pdsch.dmrs_parms.N_DMRS_SLOT, sched_ctrl->num_total_bytes + oh, min_rbSize, max_rbSize, - &TBS, - &rbSize); - sched_pdsch->rbSize = rbSize; - sched_pdsch->rbStart = rbStart; - sched_pdsch->tb_size = TBS; - /* transmissions: directly allocate */ - n_rb_sched[beam.idx] -= sched_pdsch->rbSize; + &sched_pdsch.tb_size, + &sched_pdsch.rbSize); - for (int rb = bwp_start; rb < sched_pdsch->rbSize; rb++) - rballoc_mask[rb + sched_pdsch->rbStart] |= slbitmap; + post_process_dlsch(mac, pp_pdsch, iterator->UE, &sched_pdsch); + + /* transmissions: directly allocate */ + n_rb_sched[beam.idx] -= sched_pdsch.rbSize; + + for (int rb = bwp_start; rb < sched_pdsch.rbSize; rb++) + rballoc_mask[rb + sched_pdsch.rbStart] |= slbitmap; remainUEs[beam.idx]--; iterator++; } } -static void nr_dlsch_preprocessor(module_id_t module_id, frame_t frame, slot_t slot) +static void nr_dlsch_preprocessor(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch) { - gNB_MAC_INST *mac = RC.nrmac[module_id]; NR_UEs_t *UE_info = &mac->UE_info; if (UE_info->connected_ue_list[0] == NULL) @@ -891,9 +912,6 @@ static void nr_dlsch_preprocessor(module_id_t module_id, frame_t frame, slot_t s for (int i = 0; i < num_beams; i++) n_rb_sched[i] = bw; - /* Retrieve amount of data to send for this UE */ - nr_store_dlsch_buffer(module_id, frame, slot); - int average_agg_level = 4; // TODO find a better estimation int max_sched_ues = bw / (average_agg_level * NR_NB_REG_PER_CCE); @@ -901,34 +919,11 @@ static void nr_dlsch_preprocessor(module_id_t module_id, frame_t frame, slot_t s max_sched_ues = min(max_sched_ues, MAX_DCI_CORESET); /* proportional fair scheduling algorithm */ - pf_dl(module_id, frame, slot, UE_info->connected_ue_list, max_sched_ues, num_beams, n_rb_sched); + pf_dl(mac, pp_pdsch, UE_info->connected_ue_list, max_sched_ues, num_beams, n_rb_sched); } -nr_pp_impl_dl nr_init_dlsch_preprocessor(int CC_id) { - /* during initialization: no mutex needed */ - /* in the PF algorithm, we have to use the TBsize to compute the coefficient. - * This would include the number of DMRS symbols, which in turn depends on - * the time domain allocation. In case we are in a mixed slot, we do not want - * to recalculate all these values just, and therefore we provide a look-up - * table which should approximately give us the TBsize */ - for (int mcsTableIdx = 0; mcsTableIdx < 3; ++mcsTableIdx) { - for (int mcs = 0; mcs < 29; ++mcs) { - if (mcs > 27 && mcsTableIdx == 1) - continue; - - const uint8_t Qm = nr_get_Qm_dl(mcs, mcsTableIdx); - const uint16_t R = nr_get_code_rate_dl(mcs, mcsTableIdx); - pf_tbs[mcsTableIdx][mcs] = nr_compute_tbs(Qm, - R, - 1, /* rbSize */ - 10, /* hypothetical number of slots */ - 0, /* N_PRB_DMRS * N_DMRS_SLOT */ - 0 /* N_PRB_oh, 0 for initialBWP */, - 0 /* tb_scaling */, - 1 /* nrOfLayers */) >> 3; - } - } - +nr_pp_impl_dl nr_init_dlsch_preprocessor(int CC_id) +{ return nr_dlsch_preprocessor; } @@ -1010,6 +1005,371 @@ nfapi_nr_dl_tti_pdsch_pdu_rel15_t *prepare_pdsch_pdu(nfapi_nr_dl_tti_request_pdu return pdsch_pdu; } +void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE_info_t *UE, NR_sched_pdsch_t *sched_pdsch) +{ + int CC_id = 0; + int module_id = nr_mac->Mod_id; + frame_t frame = pdsch->frame; + slot_t slot = pdsch->slot; + + const NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels[CC_id].ServingCellConfigCommon; + NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP; + + const rnti_t rnti = UE->rnti; + + /* POST processing */ + const uint8_t nrOfLayers = sched_pdsch->nrOfLayers; + const uint32_t TBS = sched_pdsch->tb_size; + int8_t current_harq_pid = sched_pdsch->dl_harq_pid; + + if (current_harq_pid < 0) { + /* PP has not selected a specific HARQ Process, get a new one */ + current_harq_pid = sched_ctrl->available_dl_harq.head; + AssertFatal(current_harq_pid >= 0, + "no free HARQ process available for UE %04x\n", + UE->rnti); + remove_front_nr_list(&sched_ctrl->available_dl_harq); + sched_pdsch->dl_harq_pid = current_harq_pid; + } else { + /* PP selected a specific HARQ process. Check whether it will be a new + * transmission or a retransmission, and remove from the corresponding + * list */ + if (sched_ctrl->harq_processes[current_harq_pid].round == 0) + remove_nr_list(&sched_ctrl->available_dl_harq, current_harq_pid); + else + remove_nr_list(&sched_ctrl->retrans_dl_harq, current_harq_pid); + } + + NR_tda_info_t *tda_info = &sched_pdsch->tda_info; + NR_pdsch_dmrs_t *dmrs_parms = &sched_pdsch->dmrs_parms; + NR_UE_harq_t *harq = &sched_ctrl->harq_processes[current_harq_pid]; + NR_sched_pucch_t *pucch = NULL; + DevAssert(!harq->is_waiting); + if (sched_pdsch->pucch_allocation < 0) { + finish_nr_dl_harq(sched_ctrl, current_harq_pid); + } else { + pucch = &sched_ctrl->sched_pucch[sched_pdsch->pucch_allocation]; + add_tail_nr_list(&sched_ctrl->feedback_dl_harq, current_harq_pid); + harq->feedback_frame = pucch->frame; + harq->feedback_slot = pucch->ul_slot; + harq->is_waiting = true; + } + UE->mac_stats.dl.rounds[harq->round]++; + LOG_D(NR_MAC, + "%4d.%2d [DLSCH/PDSCH/PUCCH] RNTI %04x DCI L %d start %3d RBs %3d startSymbol %2d nb_symbol %2d dmrspos %x MCS %2d nrOfLayers %d TBS %4d HARQ PID %2d round %d RV %d NDI %d dl_data_to_ULACK %d (%d.%d) PUCCH allocation %d TPC %d\n", + frame, + slot, + rnti, + sched_ctrl->aggregation_level, + sched_pdsch->rbStart, + sched_pdsch->rbSize, + tda_info->startSymbolIndex, + tda_info->nrOfSymbols, + dmrs_parms->dl_dmrs_symb_pos, + sched_pdsch->mcs, + nrOfLayers, + TBS, + current_harq_pid, + harq->round, + nr_get_rv(harq->round % 4), + harq->ndi, + pucch ? pucch->timing_indicator : 0, + pucch ? pucch->frame : 0, + pucch ? pucch->ul_slot : 0, + sched_pdsch->pucch_allocation, + sched_ctrl->tpc1); + DevAssert(sched_pdsch->rbSize > 0); + + const int bwp_id = current_BWP->bwp_id; + const int coresetid = sched_ctrl->coreset->controlResourceSetId; + + /* look up the PDCCH PDU for this CC, BWP, and CORESET. If it does not exist, create it */ + nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu = nr_mac->pdcch_pdu_idx[CC_id][coresetid]; + + if (!pdcch_pdu) { + LOG_D(NR_MAC, "creating pdcch pdu, pdcch_pdu = NULL. \n"); + nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdcch_pdu = &pdsch->dl_req->dl_tti_pdu_list[pdsch->dl_req->nPDUs]; + memset(dl_tti_pdcch_pdu, 0, sizeof(nfapi_nr_dl_tti_request_pdu_t)); + dl_tti_pdcch_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE; + dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); + pdsch->dl_req->nPDUs += 1; + pdcch_pdu = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; + LOG_D(NR_MAC,"Trying to configure DL pdcch for UE %04x, bwp %d, cs %d\n", UE->rnti, bwp_id, coresetid); + NR_ControlResourceSet_t *coreset = sched_ctrl->coreset; + nr_configure_pdcch(pdcch_pdu, coreset, &sched_ctrl->sched_pdcch); + nr_mac->pdcch_pdu_idx[CC_id][coresetid] = pdcch_pdu; + } + + nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &pdsch->dl_req->dl_tti_pdu_list[pdsch->dl_req->nPDUs]; + memset(dl_tti_pdsch_pdu, 0, sizeof(nfapi_nr_dl_tti_request_pdu_t)); + dl_tti_pdsch_pdu->PDUType = NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE; + dl_tti_pdsch_pdu->PDUSize = (uint8_t)(2 + sizeof(nfapi_nr_dl_tti_pdsch_pdu)); + pdsch->dl_req->nPDUs += 1; + + /* SCF222: PDU index incremented for each PDSCH PDU sent in TX control + * message. This is used to associate control information to data and is + * reset every slot. */ + const int pduindex = nr_mac->pdu_index[CC_id]++; + // TODO: verify the case where maxMIMO_Layers is NULL, in which case + // in principle maxMIMO_layers should be given by the maximum number of layers + // for PDSCH supported by the UE for the serving cell (5.4.2.1 of 38.212) + long maxMIMO_Layers = UE->sc_info.maxMIMO_Layers_PDSCH ? *UE->sc_info.maxMIMO_Layers_PDSCH : 1; + const int nl_tbslbrm = min(maxMIMO_Layers, 4); + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu = prepare_pdsch_pdu(dl_tti_pdsch_pdu, + nr_mac, + UE, + sched_pdsch, + current_BWP->pdsch_Config, + false, + harq->round, + rnti, + UE->UE_beam_index, + nl_tbslbrm, + pduindex); + + + LOG_D(NR_MAC,"Configuring DCI/PDCCH in %d.%d at CCE %d, rnti %x\n", frame,slot,sched_ctrl->cce_index,rnti); + /* Fill PDCCH DL DCI PDU */ + nfapi_nr_dl_dci_pdu_t *dci_pdu = prepare_dci_pdu(pdcch_pdu, + scc, + sched_ctrl->search_space, + sched_ctrl->coreset, + sched_ctrl->aggregation_level, + sched_ctrl->cce_index, + UE->UE_beam_index, + rnti); + pdcch_pdu->numDlDci++; + + /* DCI payload */ + const int rnti_type = TYPE_C_RNTI_; + dci_pdu_rel15_t dci_payload = prepare_dci_dl_payload(nr_mac, + UE, + rnti_type, + sched_ctrl->search_space->searchSpaceType->present, + pdsch_pdu, + sched_pdsch, + pucch, + current_harq_pid, + 0, + false); + + // Reset TPC to 0 dB to not request new gain multiple times before computing new value for SNR + sched_ctrl->tpc1 = 1; + NR_PDSCH_Config_t *pdsch_Config = current_BWP->pdsch_Config; + AssertFatal(pdsch_Config == NULL + || pdsch_Config->resourceAllocation == NR_PDSCH_Config__resourceAllocation_resourceAllocationType1, + "Only frequency resource allocation type 1 is currently supported\n"); + + LOG_D(NR_MAC, + "%4d.%2d DCI type 1 payload: freq_alloc %d (%d,%d,%d), " + "nrOfLayers %d, time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d tpc %d ti %d\n", + frame, + slot, + dci_payload.frequency_domain_assignment.val, + pdsch_pdu->rbStart, + pdsch_pdu->rbSize, + pdsch_pdu->BWPSize, + pdsch_pdu->nrOfLayers, + dci_payload.time_domain_assignment.val, + dci_payload.vrb_to_prb_mapping.val, + dci_payload.mcs, + dci_payload.tb_scaling, + dci_payload.ndi, + dci_payload.rv, + dci_payload.tpc, + pucch ? pucch->timing_indicator : 0); + + fill_dci_pdu_rel15(&UE->sc_info, + current_BWP, + &UE->current_UL_BWP, + dci_pdu, + &dci_payload, + current_BWP->dci_format, + rnti_type, + bwp_id, + sched_ctrl->search_space, + sched_ctrl->coreset, + UE->pdsch_HARQ_ACK_Codebook, + nr_mac->cset0_bwp_size); + + LOG_D(NR_MAC, + "coreset params: FreqDomainResource %llx, start_symbol %d n_symb %d\n", + (unsigned long long)pdcch_pdu->FreqDomainResource, + pdcch_pdu->StartSymbolIndex, + pdcch_pdu->DurationSymbols); + + if (harq->round != 0) { /* retransmission */ + /* we do not have to do anything, since we do not require to get data + * from RLC or encode MAC CEs. The TX_req structure is filled below + * or copy data to FAPI structures */ + LOG_D(NR_MAC, + "%d.%2d DL retransmission RNTI %04x HARQ PID %d round %d NDI %d\n", + frame, + slot, + rnti, + current_harq_pid, + harq->round, + harq->ndi); + if (!get_softmodem_params()->phy_test) + AssertFatal(harq->sched_pdsch.tb_size == TBS, + "UE %04x mismatch between scheduled TBS and buffered TB for HARQ PID %d\n", + UE->rnti, + current_harq_pid); + else if (harq->sched_pdsch.tb_size != TBS) + LOG_E(NR_MAC, + "Mismatch between scheduled TBS and buffered TB for HARQ PID %d. No RTX control in phy-test mode. " + "Possible causes: presence of CSI-RS or DLSCH scheduled in the mixed slot.\n", + current_harq_pid); + 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.buf, TBS)); + UE->mac_stats.dl.total_rbs_retx += sched_pdsch->rbSize; + nr_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 = allocate_transportBlock_buffer(&harq->transportBlock, TBS); + /* first, write all CEs that might be there */ + int written = nr_write_ce_dlsch_pdu(module_id, + sched_ctrl, + (unsigned char *)buf, + 255, // no drx + NULL); // contention res id + buf += written; + uint8_t *bufEnd = buf + TBS - written; + DevAssert(TBS > written); + int dlsch_total_bytes = 0; + /* next, get RLC data */ + start_meas(&nr_mac->rlc_data_req); + int sdus = 0; + + if (sched_ctrl->num_total_bytes > 0) { + /* loop over all activated logical channels */ + for (int i = 0; i < seq_arr_size(&sched_ctrl->lc_config); ++i) { + const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, i); + const int lcid = c->lcid; + + if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0) + continue; // no data for this LC tbs_size_t len = 0; + + int lcid_bytes=0; + while (bufEnd-buf > sizeof(NR_MAC_SUBHEADER_LONG) + 1 ) { + // we do not know how much data we will get from RLC, i.e., whether it + // will be longer than 256B or not. Therefore, reserve space for long header, then + // fetch data, then fill real length + NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) buf; + /* limit requested number of bytes to what preprocessor specified, or + * such that TBS is full */ + const rlc_buffer_occupancy_t ndata = min(sched_ctrl->rlc_status[lcid].bytes_in_buffer, + bufEnd-buf-sizeof(NR_MAC_SUBHEADER_LONG)); + tbs_size_t len = nr_mac_rlc_data_req(module_id, + rnti, + true, + lcid, + ndata, + (char *)buf+sizeof(NR_MAC_SUBHEADER_LONG)); + LOG_D(NR_MAC, + "%4d.%2d RNTI %04x: %d bytes from %s %d (ndata %d, remaining size %ld)\n", + frame, + slot, + rnti, + len, + lcid < 4 ? "DCCH" : "DTCH", + lcid, + ndata, + bufEnd-buf-sizeof(NR_MAC_SUBHEADER_LONG)); + + if (len == 0) + break; + + T(T_GNB_MAC_LCID_DL, T_INT(rnti), T_INT(frame), T_INT(slot), T_INT(lcid), T_INT(len * 8), T_INT(nr_rlc_tx_list_occupancy(rnti, lcid))); + header->R = 0; + header->F = 1; + header->LCID = lcid; + header->L = htons(len); + buf += len+sizeof(NR_MAC_SUBHEADER_LONG); + dlsch_total_bytes += len; + lcid_bytes += len; + sdus += 1; + } + + UE->mac_stats.dl.lc_bytes[lcid] += lcid_bytes; + } + } else if (get_softmodem_params()->phy_test || get_softmodem_params()->do_ra) { + /* we will need the large header, phy-test typically allocates all + * resources and fills to the last byte below */ + LOG_D(NR_MAC, "Configuring DL_TX in %d.%d: TBS %d of random data\n", frame, slot, TBS); + + if (bufEnd-buf > sizeof(NR_MAC_SUBHEADER_LONG) ) { + NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) buf; + // fill dlsch_buffer with random data + header->R = 0; + header->F = 1; + header->LCID = DL_SCH_LCID_PADDING; + buf += sizeof(NR_MAC_SUBHEADER_LONG); + header->L = htons(bufEnd-buf); + + for (; ((intptr_t)buf) % 4; buf++) + *buf = lrand48() & 0xff; + for (; buf < bufEnd - 3; buf += 4) { + uint32_t *buf32 = (uint32_t *)buf; + *buf32 = lrand48(); + } + for (; buf < bufEnd; buf++) + *buf = lrand48() & 0xff; + sdus +=1; + } + } + + stop_meas(&nr_mac->rlc_data_req); + + // Add padding header and zero rest out if there is space left + if (bufEnd-buf > 0) { + NR_MAC_SUBHEADER_FIXED *padding = (NR_MAC_SUBHEADER_FIXED *) buf; + padding->R = 0; + padding->LCID = DL_SCH_LCID_PADDING; + buf += 1; + memset(buf,0,bufEnd-buf); + buf=bufEnd; + } + + UE->mac_stats.dl.total_bytes += TBS; + UE->mac_stats.dl.current_bytes = TBS; + UE->mac_stats.dl.total_rbs += sched_pdsch->rbSize; + 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; + nr_mac->mac_stats.used_prb_aggregate += sched_pdsch->rbSize; + + /* save retransmission information */ + harq->sched_pdsch = *sched_pdsch; + /* save which time allocation has been used, to be used on + * retransmissions */ + harq->sched_pdsch.time_domain_allocation = sched_pdsch->time_domain_allocation; + + // ta command is sent, values are reset + if (sched_ctrl->ta_apply) { + sched_ctrl->ta_apply = false; + sched_ctrl->ta_frame = frame; + LOG_D(NR_MAC, "%d.%2d UE %04x TA scheduled, resetting TA frame\n", frame, slot, UE->rnti); + } + + T(T_GNB_MAC_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_BUFFER(harq->transportBlock.buf, TBS)); + T(T_GNB_MAC_DL, T_INT(rnti), T_INT(frame), T_INT(slot), T_INT(sched_pdsch->mcs), T_INT(TBS)); + } + + const int ntx_req = pdsch->TX_req->Number_of_PDUs; + nfapi_nr_pdu_t *tx_req = &pdsch->TX_req->pdu_list[ntx_req]; + tx_req->PDU_index = pduindex; + tx_req->num_TLV = 1; + tx_req->TLVs[0].length = TBS; + tx_req->PDU_length = compute_PDU_length(tx_req->num_TLV, tx_req->TLVs[0].length); + memcpy(tx_req->TLVs[0].value.direct, harq->transportBlock.buf, TBS); + pdsch->TX_req->Number_of_PDUs++; + pdsch->TX_req->SFN = frame; + pdsch->TX_req->Slot = slot; +} + void nr_schedule_ue_spec(module_id_t module_id, frame_t frame, slot_t slot, @@ -1017,6 +1377,8 @@ void nr_schedule_ue_spec(module_id_t module_id, nfapi_nr_tx_data_request_t *TX_req) { gNB_MAC_INST *gNB_mac = RC.nrmac[module_id]; + int CC_id = 0; + /* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */ AssertFatal(pthread_mutex_trylock(&gNB_mac->sched_lock) == EBUSY, "this function should be called with the scheduler mutex locked\n"); @@ -1024,390 +1386,14 @@ void nr_schedule_ue_spec(module_id_t module_id, if (!is_dl_slot(slot, &gNB_mac->frame_structure)) return; - /* PREPROCESSOR */ - gNB_mac->pre_processor_dl(module_id, frame, slot); - const int CC_id = 0; NR_ServingCellConfigCommon_t *scc = gNB_mac->common_channels[CC_id].ServingCellConfigCommon; - 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->connected_ue_list, UE) { - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP; + nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body; + post_process_pdsch_t pdsch = { frame, slot, dl_req, TX_req }; - if (!nr_mac_ue_is_active(UE) && !get_softmodem_params()->phy_test) - continue; + /* PREPROCESSOR */ + gNB_mac->pre_processor_dl(gNB_mac, &pdsch); - NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; - UE->mac_stats.dl.current_bytes = 0; - UE->mac_stats.dl.current_rbs = 0; - - /* update TA and set ta_apply every 100 frames. - * Possible improvement: take the periodicity from input file. - * If such UE is not scheduled now, it will be by the preprocessor later. - * If we add the CE, ta_apply will be reset */ - if (frame == ((sched_ctrl->ta_frame + 100) % 1024) && !nr_timer_is_active(&sched_ctrl->transm_interrupt)) { - sched_ctrl->ta_apply = true; /* the timer is reset once TA CE is scheduled */ - LOG_D(NR_MAC, "[UE %04x][%d.%d] UL timing alignment procedures: setting flag for Timing Advance command\n", UE->rnti, frame, slot); - } - - if (sched_pdsch->rbSize <= 0) - continue; - - const rnti_t rnti = UE->rnti; - - /* POST processing */ - const uint8_t nrOfLayers = sched_pdsch->nrOfLayers; - const uint32_t TBS = sched_pdsch->tb_size; - int8_t current_harq_pid = sched_pdsch->dl_harq_pid; - - if (current_harq_pid < 0) { - /* PP has not selected a specific HARQ Process, get a new one */ - current_harq_pid = sched_ctrl->available_dl_harq.head; - AssertFatal(current_harq_pid >= 0, - "no free HARQ process available for UE %04x\n", - UE->rnti); - remove_front_nr_list(&sched_ctrl->available_dl_harq); - sched_pdsch->dl_harq_pid = current_harq_pid; - } else { - /* PP selected a specific HARQ process. Check whether it will be a new - * transmission or a retransmission, and remove from the corresponding - * list */ - if (sched_ctrl->harq_processes[current_harq_pid].round == 0) - remove_nr_list(&sched_ctrl->available_dl_harq, current_harq_pid); - else - remove_nr_list(&sched_ctrl->retrans_dl_harq, current_harq_pid); - } - - NR_tda_info_t *tda_info = &sched_pdsch->tda_info; - NR_pdsch_dmrs_t *dmrs_parms = &sched_pdsch->dmrs_parms; - NR_UE_harq_t *harq = &sched_ctrl->harq_processes[current_harq_pid]; - NR_sched_pucch_t *pucch = NULL; - DevAssert(!harq->is_waiting); - if (sched_pdsch->pucch_allocation < 0) { - finish_nr_dl_harq(sched_ctrl, current_harq_pid); - } else { - pucch = &sched_ctrl->sched_pucch[sched_pdsch->pucch_allocation]; - add_tail_nr_list(&sched_ctrl->feedback_dl_harq, current_harq_pid); - harq->feedback_frame = pucch->frame; - harq->feedback_slot = pucch->ul_slot; - harq->is_waiting = true; - } - UE->mac_stats.dl.rounds[harq->round]++; - LOG_D(NR_MAC, - "%4d.%2d [DLSCH/PDSCH/PUCCH] RNTI %04x DCI L %d start %3d RBs %3d startSymbol %2d nb_symbol %2d dmrspos %x MCS %2d nrOfLayers %d TBS %4d HARQ PID %2d round %d RV %d NDI %d dl_data_to_ULACK %d (%d.%d) PUCCH allocation %d TPC %d\n", - frame, - slot, - rnti, - sched_ctrl->aggregation_level, - sched_pdsch->rbStart, - sched_pdsch->rbSize, - tda_info->startSymbolIndex, - tda_info->nrOfSymbols, - dmrs_parms->dl_dmrs_symb_pos, - sched_pdsch->mcs, - nrOfLayers, - TBS, - current_harq_pid, - harq->round, - nr_get_rv(harq->round % 4), - harq->ndi, - pucch ? pucch->timing_indicator : 0, - pucch ? pucch->frame : 0, - pucch ? pucch->ul_slot : 0, - sched_pdsch->pucch_allocation, - sched_ctrl->tpc1); - - const int bwp_id = current_BWP->bwp_id; - const int coresetid = sched_ctrl->coreset->controlResourceSetId; - - /* look up the PDCCH PDU for this CC, BWP, and CORESET. If it does not exist, create it */ - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu = gNB_mac->pdcch_pdu_idx[CC_id][coresetid]; - - if (!pdcch_pdu) { - LOG_D(NR_MAC, "creating pdcch pdu, pdcch_pdu = NULL. \n"); - nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdcch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; - memset(dl_tti_pdcch_pdu, 0, sizeof(nfapi_nr_dl_tti_request_pdu_t)); - dl_tti_pdcch_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE; - dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); - dl_req->nPDUs += 1; - pdcch_pdu = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; - LOG_D(NR_MAC,"Trying to configure DL pdcch for UE %04x, bwp %d, cs %d\n", UE->rnti, bwp_id, coresetid); - NR_ControlResourceSet_t *coreset = sched_ctrl->coreset; - nr_configure_pdcch(pdcch_pdu, coreset, &sched_ctrl->sched_pdcch); - gNB_mac->pdcch_pdu_idx[CC_id][coresetid] = pdcch_pdu; - } - - nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; - memset(dl_tti_pdsch_pdu, 0, sizeof(nfapi_nr_dl_tti_request_pdu_t)); - dl_tti_pdsch_pdu->PDUType = NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE; - dl_tti_pdsch_pdu->PDUSize = (uint8_t)(2 + sizeof(nfapi_nr_dl_tti_pdsch_pdu)); - dl_req->nPDUs += 1; - /* SCF222: PDU index incremented for each PDSCH PDU sent in TX control - * message. This is used to associate control information to data and is - * reset every slot. */ - const int pduindex = gNB_mac->pdu_index[CC_id]++; - // TODO: verify the case where maxMIMO_Layers is NULL, in which case - // in principle maxMIMO_layers should be given by the maximum number of layers - // for PDSCH supported by the UE for the serving cell (5.4.2.1 of 38.212) - long maxMIMO_Layers = UE->sc_info.maxMIMO_Layers_PDSCH ? *UE->sc_info.maxMIMO_Layers_PDSCH : 1; - const int nl_tbslbrm = min(maxMIMO_Layers, 4); - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu = prepare_pdsch_pdu(dl_tti_pdsch_pdu, - gNB_mac, - UE, - sched_pdsch, - current_BWP->pdsch_Config, - false, - harq->round, - rnti, - UE->UE_beam_index, - nl_tbslbrm, - pduindex); - - - LOG_D(NR_MAC,"Configuring DCI/PDCCH in %d.%d at CCE %d, rnti %x\n", frame,slot,sched_ctrl->cce_index,rnti); - /* Fill PDCCH DL DCI PDU */ - nfapi_nr_dl_dci_pdu_t *dci_pdu = prepare_dci_pdu(pdcch_pdu, - scc, - sched_ctrl->search_space, - sched_ctrl->coreset, - sched_ctrl->aggregation_level, - sched_ctrl->cce_index, - UE->UE_beam_index, - rnti); - pdcch_pdu->numDlDci++; - - /* DCI payload */ - const int rnti_type = TYPE_C_RNTI_; - dci_pdu_rel15_t dci_payload = prepare_dci_dl_payload(gNB_mac, - UE, - rnti_type, - sched_ctrl->search_space->searchSpaceType->present, - pdsch_pdu, - sched_pdsch, - pucch, - current_harq_pid, - 0, - false); - - // Reset TPC to 0 dB to not request new gain multiple times before computing new value for SNR - sched_ctrl->tpc1 = 1; - NR_PDSCH_Config_t *pdsch_Config = current_BWP->pdsch_Config; - AssertFatal(pdsch_Config == NULL - || pdsch_Config->resourceAllocation == NR_PDSCH_Config__resourceAllocation_resourceAllocationType1, - "Only frequency resource allocation type 1 is currently supported\n"); - - LOG_D(NR_MAC, - "%4d.%2d DCI type 1 payload: freq_alloc %d (%d,%d,%d), " - "nrOfLayers %d, time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d tpc %d ti %d\n", - frame, - slot, - dci_payload.frequency_domain_assignment.val, - pdsch_pdu->rbStart, - pdsch_pdu->rbSize, - pdsch_pdu->BWPSize, - pdsch_pdu->nrOfLayers, - dci_payload.time_domain_assignment.val, - dci_payload.vrb_to_prb_mapping.val, - dci_payload.mcs, - dci_payload.tb_scaling, - dci_payload.ndi, - dci_payload.rv, - dci_payload.tpc, - pucch ? pucch->timing_indicator : 0); - - fill_dci_pdu_rel15(&UE->sc_info, - current_BWP, - &UE->current_UL_BWP, - dci_pdu, - &dci_payload, - current_BWP->dci_format, - rnti_type, - bwp_id, - sched_ctrl->search_space, - sched_ctrl->coreset, - UE->pdsch_HARQ_ACK_Codebook, - gNB_mac->cset0_bwp_size); - - LOG_D(NR_MAC, - "coreset params: FreqDomainResource %llx, start_symbol %d n_symb %d\n", - (unsigned long long)pdcch_pdu->FreqDomainResource, - pdcch_pdu->StartSymbolIndex, - pdcch_pdu->DurationSymbols); - - if (harq->round != 0) { /* retransmission */ - /* we do not have to do anything, since we do not require to get data - * from RLC or encode MAC CEs. The TX_req structure is filled below - * or copy data to FAPI structures */ - LOG_D(NR_MAC, - "%d.%2d DL retransmission RNTI %04x HARQ PID %d round %d NDI %d\n", - frame, - slot, - rnti, - current_harq_pid, - harq->round, - harq->ndi); - if (!get_softmodem_params()->phy_test) - AssertFatal(harq->sched_pdsch.tb_size == TBS, - "UE %04x mismatch between scheduled TBS and buffered TB for HARQ PID %d\n", - UE->rnti, - current_harq_pid); - else if (harq->sched_pdsch.tb_size != TBS) - LOG_E(NR_MAC, - "Mismatch between scheduled TBS and buffered TB for HARQ PID %d. No RTX control in phy-test mode. " - "Possible causes: presence of CSI-RS or DLSCH scheduled in the mixed slot.\n", - current_harq_pid); - 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.buf, 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 = allocate_transportBlock_buffer(&harq->transportBlock, TBS); - /* first, write all CEs that might be there */ - int written = nr_write_ce_dlsch_pdu(module_id, - sched_ctrl, - (unsigned char *)buf, - 255, // no drx - NULL); // contention res id - buf += written; - uint8_t *bufEnd = buf + TBS - written; - DevAssert(TBS > written); - int dlsch_total_bytes = 0; - /* next, get RLC data */ - start_meas(&gNB_mac->rlc_data_req); - int sdus = 0; - - if (sched_ctrl->num_total_bytes > 0) { - /* loop over all activated logical channels */ - for (int i = 0; i < seq_arr_size(&sched_ctrl->lc_config); ++i) { - const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, i); - const int lcid = c->lcid; - - if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0) - continue; // no data for this LC tbs_size_t len = 0; - - int lcid_bytes=0; - while (bufEnd-buf > sizeof(NR_MAC_SUBHEADER_LONG) + 1 ) { - // we do not know how much data we will get from RLC, i.e., whether it - // will be longer than 256B or not. Therefore, reserve space for long header, then - // fetch data, then fill real length - NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) buf; - /* limit requested number of bytes to what preprocessor specified, or - * such that TBS is full */ - const rlc_buffer_occupancy_t ndata = min(sched_ctrl->rlc_status[lcid].bytes_in_buffer, - bufEnd-buf-sizeof(NR_MAC_SUBHEADER_LONG)); - tbs_size_t len = nr_mac_rlc_data_req(module_id, - rnti, - true, - lcid, - ndata, - (char *)buf+sizeof(NR_MAC_SUBHEADER_LONG)); - LOG_D(NR_MAC, - "%4d.%2d RNTI %04x: %d bytes from %s %d (ndata %d, remaining size %ld)\n", - frame, - slot, - rnti, - len, - lcid < 4 ? "DCCH" : "DTCH", - lcid, - ndata, - bufEnd-buf-sizeof(NR_MAC_SUBHEADER_LONG)); - - if (len == 0) - break; - - T(T_GNB_MAC_LCID_DL, T_INT(rnti), T_INT(frame), T_INT(slot), T_INT(lcid), T_INT(len * 8), T_INT(nr_rlc_tx_list_occupancy(rnti, lcid))); - header->R = 0; - header->F = 1; - header->LCID = lcid; - header->L = htons(len); - buf += len+sizeof(NR_MAC_SUBHEADER_LONG); - dlsch_total_bytes += len; - lcid_bytes += len; - sdus += 1; - } - - UE->mac_stats.dl.lc_bytes[lcid] += lcid_bytes; - } - } else if (get_softmodem_params()->phy_test || get_softmodem_params()->do_ra) { - /* we will need the large header, phy-test typically allocates all - * resources and fills to the last byte below */ - LOG_D(NR_MAC, "Configuring DL_TX in %d.%d: TBS %d of random data\n", frame, slot, TBS); - - if (bufEnd-buf > sizeof(NR_MAC_SUBHEADER_LONG) ) { - NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) buf; - // fill dlsch_buffer with random data - header->R = 0; - header->F = 1; - header->LCID = DL_SCH_LCID_PADDING; - buf += sizeof(NR_MAC_SUBHEADER_LONG); - header->L = htons(bufEnd-buf); - - for (; ((intptr_t)buf) % 4; buf++) - *buf = lrand48() & 0xff; - for (; buf < bufEnd - 3; buf += 4) { - uint32_t *buf32 = (uint32_t *)buf; - *buf32 = lrand48(); - } - for (; buf < bufEnd; buf++) - *buf = lrand48() & 0xff; - sdus +=1; - } - } - - stop_meas(&gNB_mac->rlc_data_req); - - // Add padding header and zero rest out if there is space left - if (bufEnd-buf > 0) { - NR_MAC_SUBHEADER_FIXED *padding = (NR_MAC_SUBHEADER_FIXED *) buf; - padding->R = 0; - padding->LCID = DL_SCH_LCID_PADDING; - buf += 1; - memset(buf,0,bufEnd-buf); - buf=bufEnd; - } - - UE->mac_stats.dl.total_bytes += TBS; - UE->mac_stats.dl.current_bytes = TBS; - UE->mac_stats.dl.total_rbs += sched_pdsch->rbSize; - 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; - /* save which time allocation has been used, to be used on - * retransmissions */ - harq->sched_pdsch.time_domain_allocation = sched_pdsch->time_domain_allocation; - - // ta command is sent, values are reset - if (sched_ctrl->ta_apply) { - sched_ctrl->ta_apply = false; - sched_ctrl->ta_frame = frame; - LOG_D(NR_MAC, "%d.%2d UE %04x TA scheduled, resetting TA frame\n", frame, slot, UE->rnti); - } - - T(T_GNB_MAC_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_BUFFER(harq->transportBlock.buf, TBS)); - T(T_GNB_MAC_DL, T_INT(rnti), T_INT(frame), T_INT(slot), T_INT(sched_pdsch->mcs), T_INT(TBS)); - } - - const int ntx_req = TX_req->Number_of_PDUs; - nfapi_nr_pdu_t *tx_req = &TX_req->pdu_list[ntx_req]; - tx_req->PDU_index = pduindex; - tx_req->num_TLV = 1; - tx_req->TLVs[0].length = TBS; - tx_req->PDU_length = compute_PDU_length(tx_req->num_TLV, tx_req->TLVs[0].length); - memcpy(tx_req->TLVs[0].value.direct, harq->transportBlock.buf, TBS); - TX_req->Number_of_PDUs++; - TX_req->SFN = frame; - TX_req->Slot = slot; - /* mark UE as scheduled */ - sched_pdsch->rbSize = 0; - } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 5ec7bf781d..f9121b3125 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -55,9 +55,11 @@ uint32_t target_dl_bw = 50; uint64_t dlsch_slot_bitmap = (1<<1); /* schedules whole bandwidth for first user, all the time */ -void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot) +void nr_preprocessor_phytest(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch) { - gNB_MAC_INST *mac = RC.nrmac[module_id]; + frame_t frame = pp_pdsch->frame; + slot_t slot = pp_pdsch->slot; + /* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */ int slot_period = slot % mac->frame_structure.numb_slots_period; if (!is_xlsch_in_slot(dlsch_slot_bitmap, slot_period)) @@ -86,9 +88,6 @@ void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot) if(!tda_info.valid_tda) return; - sched_ctrl->sched_pdsch.tda_info = tda_info; - sched_ctrl->sched_pdsch.time_domain_allocation = tda; - /* find largest unallocated chunk */ const int bwpSize = dl_bwp->BWPSize; const int BWPStart = dl_bwp->BWPStart; @@ -142,12 +141,11 @@ void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot) 0); AssertFatal(CCEIndex >= 0, "Could not find CCE for UE %04x\n", UE->rnti); - NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; - if (sched_pdsch->dl_harq_pid == -1) - sched_pdsch->dl_harq_pid = sched_ctrl->available_dl_harq.head; - int alloc = -1; - if (!get_FeedbackDisabled(UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, sched_pdsch->dl_harq_pid)) { + int harq_pid = sched_ctrl->retrans_dl_harq.head; + if (harq_pid < 0) + harq_pid = sched_ctrl->available_dl_harq.head; + if (!get_FeedbackDisabled(UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, harq_pid)) { int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, UE->current_UL_BWP.pucch_Config, CCEIndex); alloc = nr_acknack_scheduling(mac, UE, frame, slot, 0, r_pucch, 0); if (alloc < 0) { @@ -165,42 +163,38 @@ void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot) sched_ctrl->aggregation_level, beam); - //AssertFatal(alloc, - // "could not find uplink slot for PUCCH (RNTI %04x@%d.%d)!\n", - // rnti, frame, slot); - - sched_pdsch->pucch_allocation = alloc; - sched_pdsch->rbStart = rbStart; - sched_pdsch->rbSize = rbSize; - sched_pdsch->bwp_info = get_pdsch_bwp_start_size(mac, UE); - sched_pdsch->dmrs_parms = get_dl_dmrs_params(scc, - dl_bwp, - &tda_info, - target_dl_Nl); - - sched_pdsch->mcs = target_dl_mcs; - sched_pdsch->nrOfLayers = target_dl_Nl; - sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx); - sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx); + NR_sched_pdsch_t sched_pdsch = { + .rbSize = rbSize, + .rbStart = rbStart, + .mcs = target_dl_mcs, + .R = nr_get_code_rate_dl(target_dl_mcs, dl_bwp->mcsTableIdx), + .Qm = nr_get_Qm_dl(target_dl_mcs, dl_bwp->mcsTableIdx), + // tbSize further below + .dl_harq_pid = sched_ctrl->retrans_dl_harq.head, // PID of HARQ awaiting retransmission, or -1 otherwise + .pucch_allocation = alloc, + .pm_index = 0, + .nrOfLayers = target_dl_Nl, + .bwp_info = get_pdsch_bwp_start_size(mac, UE), + .dmrs_parms = get_dl_dmrs_params(scc, dl_bwp, &tda_info, target_dl_Nl), + .time_domain_allocation = tda, + .tda_info = tda_info, + }; sched_ctrl->dl_bler_stats.mcs = target_dl_mcs; /* for logging output */ - sched_pdsch->tb_size = nr_compute_tbs(sched_pdsch->Qm, - sched_pdsch->R, - sched_pdsch->rbSize, - tda_info.nrOfSymbols, - sched_pdsch->dmrs_parms.N_PRB_DMRS * sched_pdsch->dmrs_parms.N_DMRS_SLOT, - 0 /* N_PRB_oh, 0 for initialBWP */, - 0 /* tb_scaling */, - sched_pdsch->nrOfLayers) - >> 3; + sched_pdsch.tb_size = nr_compute_tbs(sched_pdsch.Qm, + sched_pdsch.R, + sched_pdsch.rbSize, + tda_info.nrOfSymbols, + sched_pdsch.dmrs_parms.N_PRB_DMRS * sched_pdsch.dmrs_parms.N_DMRS_SLOT, + 0 /* N_PRB_oh, 0 for initialBWP */, + 0 /* tb_scaling */, + target_dl_Nl) + >> 3; - /* get the PID of a HARQ process awaiting retransmission, or -1 otherwise */ - sched_pdsch->dl_harq_pid = sched_ctrl->retrans_dl_harq.head; + post_process_dlsch(mac, pp_pdsch, UE, &sched_pdsch); /* mark the corresponding RBs as used */ - for (int rb = 0; rb < sched_pdsch->rbSize; rb++) - vrb_map[rb + sched_pdsch->rbStart + BWPStart] = SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols); - - if ((frame&127) == 0) LOG_D(MAC,"phytest: %d.%d DL mcs %d, DL rbStart %d, DL rbSize %d\n", frame, slot, sched_pdsch->mcs, rbStart,rbSize); + for (int rb = 0; rb < sched_pdsch.rbSize; rb++) + vrb_map[rb + sched_pdsch.rbStart + BWPStart] = SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols); } uint32_t target_ul_mcs = 9; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 4e55941420..a81841d9c0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2974,9 +2974,6 @@ NR_UE_info_t *get_new_nr_ue_inst(uid_allocator_t *uia, rnti_t rnti, NR_CellGroup NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; sched_ctrl->ta_update = 31; - /* set illegal time domain allocation to force recomputation of all fields */ - sched_ctrl->sched_pdsch.time_domain_allocation = -1; - /* Set default BWPs */ AssertFatal(UE->sc_info.n_ul_bwp <= NR_MAX_NUM_BWP, "uplinkBWP_ToAddModList has %d BWP!\n", UE->sc_info.n_ul_bwp); @@ -3033,18 +3030,17 @@ bool transition_ra_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE) * To remove the UE, use mac_remove_nr_ue(). */ bool add_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE) { + NR_SCHED_ENSURE_LOCKED(&nr_mac->sched_lock); + LOG_I(NR_MAC, "Adding new UE context with RNTI 0x%04x\n", UE->rnti); NR_UEs_t *UE_info = &nr_mac->UE_info; dump_nr_list(UE_info->connected_ue_list); AssertFatal(!UE->ra, "UE in connected cannot have RA process\n"); - NR_SCHED_LOCK(&UE_info->mutex); - bool success = add_UE_to_list(MAX_MOBILES_PER_GNB, UE_info->connected_ue_list, UE); if (!success) { LOG_E(NR_MAC,"Try to add UE %04x but the list is full\n", UE->rnti); delete_nr_ue_data(UE, NULL, &UE_info->uid_allocator); - NR_SCHED_UNLOCK(&UE_info->mutex); return false; } @@ -3057,7 +3053,6 @@ bool add_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE) init_bler_stats(&nr_mac->dl_bler, &sched_ctrl->dl_bler_stats, nr_mac->frame); init_bler_stats(&nr_mac->ul_bler, &sched_ctrl->ul_bler_stats, nr_mac->frame); - NR_SCHED_UNLOCK(&UE_info->mutex); dump_nr_list(UE_info->connected_ue_list); return true; } @@ -3110,9 +3105,7 @@ void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti) /* already mutex protected */ NR_SCHED_ENSURE_LOCKED(&nr_mac->sched_lock); NR_UEs_t *UE_info = &nr_mac->UE_info; - NR_SCHED_LOCK(&UE_info->mutex); NR_UE_info_t *UE = remove_UE_from_list(MAX_MOBILES_PER_GNB + 1, UE_info->connected_ue_list, rnti); - NR_SCHED_UNLOCK(&UE_info->mutex); if (UE) delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator); else diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index e689a8a978..27ecbdcbd0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -678,6 +678,8 @@ static void evaluate_cqi_report(uint8_t *payload, const int cqi_idx = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb; const int mcs_table = UE->current_DL_BWP.mcsTableIdx; sched_ctrl->dl_max_mcs = get_mcs_from_cqi(mcs_table, cqi_Table, cqi_idx); + + LOG_D(MAC, "Reported CQI = %d, dl_max_mcs %d\n", temp_cqi, sched_ctrl->dl_max_mcs); } static uint8_t evaluate_pmi_report(uint8_t *payload, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index f923a2c9ec..94325bf26b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1834,6 +1834,10 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, const uint16_t slbitmap = SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols); while (rbStart < bwpSize && (rballoc_mask[rbStart + bwpStart] & slbitmap)) rbStart++; + if (rbStart >= bwpSize) { + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate UL retransmission: no resources\n", UE->rnti, frame, slot); + return false; + } int rbSize = 0; while (rbStart + rbSize < bwpSize && !(rballoc_mask[rbStart + bwpStart + rbSize] & slbitmap)) rbSize++; @@ -1909,7 +1913,6 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, return true; } -static uint32_t ul_pf_tbs[5][29]; // pre-computed, approximate TBS values for PF coefficient typedef struct UEsched_s { float coef; bool sched_inactive; @@ -2065,8 +2068,8 @@ static int pf_ul(gNB_MAC_INST *nrmac, const int max_mcs_table = (current_BWP->mcs_table == 0 || current_BWP->mcs_table == 2) ? 28 : 27; const int max_mcs = min(bo->max_mcs, max_mcs_table); /* no per-user maximum MCS yet */ int selected_mcs; + int nrOfLayers = get_ul_nrOfLayers(sched_ctrl, current_BWP->dci_format); if (bo->harq_round_max == 1) { - int nrOfLayers = get_ul_nrOfLayers(sched_ctrl, current_BWP->dci_format); selected_mcs = get_mcs_from_SINRx10(current_BWP->mcs_table, sched_ctrl->pusch_snrx10, nrOfLayers); selected_mcs = min(max_mcs, selected_mcs); selected_mcs = max(bo->min_mcs, selected_mcs); @@ -2078,7 +2081,17 @@ static int pf_ul(gNB_MAC_INST *nrmac, /* Create UE_sched for UEs eligibale for new data transmission*/ /* Calculate coefficient*/ - const uint32_t tbs = ul_pf_tbs[current_BWP->mcs_table][selected_mcs]; + const uint8_t Qm = nr_get_Qm_dl(selected_mcs, current_BWP->mcs_table); + const uint16_t R = nr_get_code_rate_dl(selected_mcs, current_BWP->mcs_table); + const uint32_t tbs = nr_compute_tbs(Qm, + R, + 1, /* rbSize */ + 10, /* hypothetical number of slots */ + 0, /* N_PRB_DMRS * N_DMRS_SLOT */ + 0 /* N_PRB_oh, 0 for initialBWP */, + 0 /* tb_scaling */, + nrOfLayers) + >> 3; float coeff_ue = (float) tbs / UE->ul_thr_ue; bool sched_inactive = B == 0 && do_sched; LOG_D(NR_MAC, "[UE %04x][%4d.%2d] b %d, ul_thr_ue %f, tbs %d, coeff_ue %f, sched_inactive %d\n", @@ -2703,32 +2716,6 @@ static void nr_ulsch_preprocessor(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp nr_pp_impl_ul nr_init_ulsch_preprocessor(int CC_id) { - /* during initialization: no mutex needed */ - /* in the PF algorithm, we have to use the TBsize to compute the coefficient. - * This would include the number of DMRS symbols, which in turn depends on - * the time domain allocation. In case we are in a mixed slot, we do not want - * to recalculate all these values, and therefore we provide a look-up table - * which should approximately(!) give us the TBsize. In particular, the - * number of symbols, the number of DMRS symbols, and the exact Qm and R, are - * not correct*/ - for (int mcsTableIdx = 0; mcsTableIdx < 5; ++mcsTableIdx) { - for (int mcs = 0; mcs < 29; ++mcs) { - if (mcs > 27 && (mcsTableIdx == 1 || mcsTableIdx == 3 || mcsTableIdx == 4)) - continue; - const uint8_t Qm = nr_get_Qm_ul(mcs, mcsTableIdx); - const uint16_t R = nr_get_code_rate_ul(mcs, mcsTableIdx); - /* note: we do not update R/Qm based on low MCS or pi2BPSK */ - ul_pf_tbs[mcsTableIdx][mcs] = nr_compute_tbs(Qm, - R, - 1, /* rbSize */ - 10, /* hypothetical number of slots */ - 0, /* N_PRB_DMRS * N_DMRS_SLOT */ - 0 /* N_PRB_oh, 0 for initialBWP */, - 0 /* tb_scaling */, - 1 /* nrOfLayers */) - >> 3; - } - } return nr_ulsch_preprocessor; } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index f04b28b8da..cfe02755b2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -145,7 +145,7 @@ uint16_t nr_mac_compute_RIV(uint16_t N_RB_DL, uint16_t RBstart, uint16_t Lcrbs); /* \brief preprocessor for phytest: schedules UE_id 0 with fixed MCS on all * freq resources */ -void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot); +void nr_preprocessor_phytest(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch); /* \brief UL preprocessor for phytest: schedules UE_id 0 with fixed MCS on a * fixed set of resources */ void nr_ul_preprocessor_phytest(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp_pusch); @@ -504,5 +504,6 @@ void prepare_du_configuration_update(gNB_MAC_INST *mac, void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group); +void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE_info_t *UE, NR_sched_pdsch_t *sched_pdsch); void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE_info_t *UE, NR_sched_pusch_t *sched_pusch); #endif /*__LAYER2_NR_MAC_PROTO_H__*/ diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index fa66125bf7..f3f070b0e7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -87,7 +87,6 @@ void *nrmac_stats_thread(void *arg) { char *p = output; NR_SCHED_LOCK(&gNB->sched_lock); p += dump_mac_stats(gNB, p, end - p, false); - NR_SCHED_UNLOCK(&gNB->sched_lock); p += snprintf(p, end - p, "\n"); p += print_meas_log(&gNB->gNB_scheduler, "gNB_scheduler", NULL, NULL, p, end - p); p += print_meas_log(&gNB->rx_ulsch_sdu, "rx_ulsch_sdu", NULL, NULL, p, end - p); @@ -97,10 +96,17 @@ void *nrmac_stats_thread(void *arg) { p += print_meas_log(&gNB->rlc_data_req, "rlc_data_req", NULL, NULL, p, end - p); p += print_meas_log(&gNB->nr_srs_ri_computation_timer, "UL-RI computation time", NULL, NULL, p, end - p); p += print_meas_log(&gNB->nr_srs_tpmi_computation_timer, "UL-TPMI computation time", NULL, NULL, p, end - p); - fwrite(output, p - output, 1, file); - fflush(file); + NR_SCHED_UNLOCK(&gNB->sched_lock); + size_t len = p - output; + if (fwrite(output, len, 1, file) != 1 || fflush(file) != 0) { + LOG_E(NR_MAC, "error while writing nrMAC_stats.log: %d, %s\n", errno, strerror(errno)); + break; + } sleep(1); - fseek(file,0,SEEK_SET); + if (ftruncate(fileno(file), 0) != 0 || fseek(file, 0, SEEK_SET) != 0) { + LOG_E(NR_MAC, "error while writing nrMAC_stats.log: %d, %s\n", errno, strerror(errno)); + break; + } } fclose(file); return NULL; @@ -112,6 +118,19 @@ void clear_mac_stats(gNB_MAC_INST *gNB) { } } +static char *st_append(char *start, const char *end, const char *format, ...) +{ + size_t space = end - start; + va_list args; + va_start(args, format); + size_t written = vsnprintf(start, space, format, args); + va_end(args); + if (written <= space) + return start + written; + else + return (char *)end; +} + size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset_rsrp) { const char *begin = output; @@ -121,46 +140,45 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset * scheduler to be locked*/ NR_SCHED_ENSURE_LOCKED(&gNB->sched_lock); - NR_SCHED_LOCK(&gNB->UE_info.mutex); UE_iterator(gNB->UE_info.connected_ue_list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_mac_stats_t *stats = &UE->mac_stats; const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0; const int avg_sinrx10 = stats->num_sinr_meas > 0 ? stats->cumul_sinrx10 / stats->num_sinr_meas : 0; - output += snprintf(output, end - output, "UE RNTI %04x CU-UE-ID ", UE->rnti); + output = st_append(output, end, "UE RNTI %04x CU-UE-ID ", UE->rnti); if (du_exists_f1_ue_data(UE->rnti)) { f1_ue_data_t ued = du_get_f1_ue_data(UE->rnti); - output += snprintf(output, end - output, "%d", ued.secondary_ue); + output = st_append(output, end, "%d", ued.secondary_ue); } else { - output += snprintf(output, end - output, "(none)"); + output = st_append(output, end, "(none)"); } bool in_sync = !sched_ctrl->ul_failure; - output += snprintf(output, - end - output, + output = st_append(output, + end, " %s PH %d dB PCMAX %d dBm", in_sync ? "in-sync" : "out-of-sync", sched_ctrl->ph, sched_ctrl->pcmax); if (stats->num_rsrp_meas) - output += snprintf(output, end - output, ", average RSRP %d (%d meas)", avg_rsrp, stats->num_rsrp_meas); + output = st_append(output, end, ", average RSRP %d (%d meas)", avg_rsrp, stats->num_rsrp_meas); if (stats->num_sinr_meas) { - output += snprintf(output, - end - output, + output = st_append(output, + end, ", average SINR %d.%d (%d meas)", avg_sinrx10 / 10, avg_sinrx10 % 10, stats->num_sinr_meas); } - output += snprintf(output, end - output, "\n"); + output = st_append(output, end, "\n"); if(sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report) - output += snprintf(output, - end - output, + output = st_append(output, + end, "UE %04x: CQI %d, RI %d, PMI (%d,%d)\n", UE->rnti, sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb, @@ -169,18 +187,18 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2); if (stats->srs_stats[0] != '\0') { - output += snprintf(output, end - output, "UE %04x: %s\n", UE->rnti, stats->srs_stats); + output = st_append(output, end, "UE %04x: %s\n", UE->rnti, stats->srs_stats); } - output += snprintf(output, - end - output, + output = st_append(output, + end, "UE %04x: dlsch_rounds ", UE->rnti); - output += snprintf(output, end - output, "%"PRIu64, stats->dl.rounds[0]); + output = st_append(output, end, "%"PRIu64, stats->dl.rounds[0]); for (int i = 1; i < gNB->dl_bler.harq_round_max; i++) - output += snprintf(output, end - output, "/%"PRIu64, stats->dl.rounds[i]); + output = st_append(output, end, "/%"PRIu64, stats->dl.rounds[i]); - output += snprintf(output, - end - output, + output = st_append(output, + end, ", dlsch_errors %"PRIu64", pucch0_DTX %d, BLER %.5f MCS (%d) %d CCE fail %d\n", stats->dl.errors, stats->pucch0_DTX, @@ -194,15 +212,15 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset stats->num_sinr_meas = 0; stats->cumul_sinrx10 = 0; } - output += snprintf(output, - end - output, + output = st_append(output, + end, "UE %04x: ulsch_rounds ", UE->rnti); - output += snprintf(output, end - output, "%"PRIu64, stats->ul.rounds[0]); + output = st_append(output, end, "%"PRIu64, stats->ul.rounds[0]); for (int i = 1; i < gNB->ul_bler.harq_round_max; i++) - output += snprintf(output, end - output, "/%"PRIu64, stats->ul.rounds[i]); + output = st_append(output, end, "/%"PRIu64, stats->ul.rounds[i]); - output += snprintf(output, - end - output, + output = st_append(output, + end, ", ulsch_errors %"PRIu64", ulsch_DTX %d, BLER %.5f MCS (%d) %d (Qm %d deltaMCS %d dB) NPRB %d SNR %d.%d dB CCE fail %d\n", stats->ul.errors, stats->ulsch_DTX, @@ -215,15 +233,15 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset sched_ctrl->pusch_snrx10 / 10, sched_ctrl->pusch_snrx10 % 10, sched_ctrl->ul_cce_fail); - output += snprintf(output, - end - output, + output = st_append(output, + end, "UE %04x: MAC: TX %14"PRIu64" RX %14"PRIu64" bytes\n", UE->rnti, stats->dl.total_bytes, stats->ul.total_bytes); for (int i = 0; i < seq_arr_size(&sched_ctrl->lc_config); i++) { const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, i); - output += snprintf(output, - end - output, + output = st_append(output, + end, "UE %04x: LCID %d: TX %14"PRIu64" RX %14"PRIu64" bytes\n", UE->rnti, c->lcid, @@ -231,7 +249,7 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset stats->ul.lc_bytes[c->lcid]); } } - NR_SCHED_UNLOCK(&gNB->UE_info.mutex); + DevAssert(output <= end); return output - begin; } @@ -296,9 +314,10 @@ void mac_top_init_gNB(ngran_node_t node_type, RC.nrmac[i]->cset0_bwp_start = 0; RC.nrmac[i]->cset0_bwp_size = 0; + RC.nrmac[i]->print_ue_stats = true; + pthread_mutex_init(&RC.nrmac[i]->sched_lock, NULL); - pthread_mutex_init(&RC.nrmac[i]->UE_info.mutex, NULL); uid_linear_allocator_init(&RC.nrmac[i]->UE_info.uid_allocator); if (get_softmodem_params()->phy_test) { diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index dfad999e76..d6a9ae1497 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -639,8 +639,6 @@ typedef struct { /// PHR info: nominal UE transmit power levels (dBm) int pcmax; - /// Sched PDSCH: scheduling decisions, copied into HARQ and cleared every TTI - NR_sched_pdsch_t sched_pdsch; /// UE-estimated maximum MCS (from CSI-RS) uint8_t dl_max_mcs; @@ -803,7 +801,6 @@ typedef struct { typedef struct { /// scheduling control info // last element always NULL - pthread_mutex_t mutex; NR_UE_info_t *connected_ue_list[MAX_MOBILES_PER_GNB + 1]; NR_UE_info_t *access_ue_list[NR_NB_RA_PROC_MAX + 1]; // bitmap of CSI-RS already scheduled in current slot @@ -826,7 +823,18 @@ typedef struct { nr_beam_mode_t beam_mode; } NR_beam_info_t; -#define UE_iterator(BaSe, VaR) NR_UE_info_t ** VaR##pptr=BaSe, *VaR; while ((VaR=*(VaR##pptr++))) +#define UE_iterator(BaSe, VaR) for (NR_UE_info_t **VaR##pptr=BaSe, *VaR=*VaR##pptr; VaR; VaR=*(++VaR##pptr)) + +typedef struct { + /// current frame + frame_t frame; + /// current slot + slot_t slot; + /// FAPI DL req in which allocations are made + nfapi_nr_dl_tti_request_body_t *dl_req; + /// TX_data request holds the actual data + nfapi_nr_tx_data_request_t *TX_req; +} post_process_pdsch_t; typedef struct { /// current frame for DCI @@ -843,7 +851,7 @@ typedef struct { struct gNB_MAC_INST_s; typedef struct gNB_MAC_INST_s gNB_MAC_INST; -typedef void (*nr_pp_impl_dl)(module_id_t mod_id, frame_t frame, slot_t slot); +typedef void (*nr_pp_impl_dl)(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pp_pdsch); typedef void (*nr_pp_impl_ul)(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp_pusch); typedef struct f1_config_t { @@ -981,6 +989,11 @@ typedef struct gNB_MAC_INST_s { f1_config_t f1_config; int16_t frame; + /// number of UEs to exceed to disable stats + int stats_max_ue; + /// if stats are currently enabled + bool print_ue_stats; + pthread_mutex_t sched_lock; mac_stats_t mac_stats;