diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 91a63a0a2e..3812ec4a7f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -615,6 +615,8 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, LOG_I(NR_MAC,"Modified UE_id %d/%x with CellGroup\n",UE_id,rnti); process_CellGroup(CellGroup,&UE_info->UE_sched_ctrl[UE_id]); NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + sched_ctrl->update_pdsch_ps = true; + sched_ctrl->update_pusch_ps = true; const NR_PDSCH_ServingCellConfig_t *pdsch = servingCellConfig ? servingCellConfig->pdsch_ServingCellConfig->choice.setup : NULL; if (sched_ctrl->available_dl_harq.len == 0) { // add all available DL HARQ processes for this UE in SA diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index ba854608c5..f2d3474f3f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -346,6 +346,9 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, LOG_I(NR_MAC,"Frame.Slot %d.%d\n%s\n",frame,slot,stats_output); } + // This schedules the BWP switching + schedule_nr_bwp_switch(module_idP, frame, slot); + // This schedules MIB schedule_nr_mib(module_idP, frame, slot); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index c7cd6a435d..ff1c2587cf 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -500,14 +500,14 @@ void nr_store_dlsch_buffer(module_id_t module_id, 0); stop_meas(&RC.nrmac[module_id]->rlc_status_ind); } - if(sched_ctrl->rlc_status[DL_SCH_LCID_DCCH].bytes_in_buffer > 0){ + if(sched_ctrl->rlc_status[DL_SCH_LCID_DCCH].bytes_in_buffer > 0) { lcid = DL_SCH_LCID_DCCH; - } - else if (sched_ctrl->rlc_status[DL_SCH_LCID_DCCH1].bytes_in_buffer > 0) - { + } else if (sched_ctrl->rlc_status[DL_SCH_LCID_DCCH1].bytes_in_buffer > 0) { lcid = DL_SCH_LCID_DCCH1; - }else{ - lcid = DL_SCH_LCID_DTCH; + } else if (sched_ctrl->bwp_switch_info.bwp_switch_state != BWP_SWITCH_RUNNING) { + lcid = DL_SCH_LCID_DTCH; + } else { + continue; } sched_ctrl->num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer; @@ -577,8 +577,10 @@ bool allocate_dl_retransmission(module_id_t module_id, } /* check whether we need to switch the TDA allocation since the last * (re-)transmission */ - if (ps->time_domain_allocation != tda) + if (ps->time_domain_allocation != tda || sched_ctrl->update_pdsch_ps) { nr_set_pdsch_semi_static(scc, cg, sched_ctrl->active_bwp, bwpd, tda, f, ps); + sched_ctrl->update_pdsch_ps = false; + } } else { /* the retransmission will use a different time domain allocation, check * that we have enough resources */ @@ -838,8 +840,10 @@ void pf_dl(module_id_t module_id, NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; const long f = (sched_ctrl->active_bwp || bwpd) ? sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats : 0; - if (ps->time_domain_allocation != tda) + if (ps->time_domain_allocation != tda || sched_ctrl->update_pdsch_ps) { nr_set_pdsch_semi_static(scc, UE_info->CellGroup[UE_id], sched_ctrl->active_bwp, bwpd, tda, f, ps); + sched_ctrl->update_pdsch_ps = false; + } const uint16_t slbitmap = SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols); // Freq-demain allocation @@ -964,6 +968,70 @@ nr_pp_impl_dl nr_init_fr1_dlsch_preprocessor(module_id_t module_id, int CC_id) return nr_fr1_dlsch_preprocessor; } +void nr_bwp_switch(module_id_t module_id, + frame_t frame, + sub_frame_t slot, + int UE_id, + int bwp_id) { + + NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + + switch(sched_ctrl->bwp_switch_info.bwp_switch_state) { + + case BWP_SWITCH_TO_START: + LOG_W(NR_MAC,"(%d.%d) [UE_id %d] Schedule BWP switch from bwp_id %ld to %d\n", + frame, slot, UE_id, UE_info->UE_sched_ctrl[UE_id].active_bwp->bwp_Id, bwp_id); + sched_ctrl->bwp_switch_info.bwp_switch_timer = 0; + sched_ctrl->bwp_switch_info.bwp_switch_state = BWP_SWITCH_RUNNING; + nr_mac_rrc_bwp_switch_req(module_id, frame, slot, UE_info->rnti[UE_id], bwp_id); + break; + + case BWP_SWITCH_RUNNING: + sched_ctrl->bwp_switch_info.bwp_switch_timer++; + if(sched_ctrl->bwp_switch_info.bwp_switch_timer == sched_ctrl->bwp_switch_info.bwp_switch_delay) { + const NR_ServingCellConfig_t *servingCellConfig = UE_info->CellGroup[UE_id] ? UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated : NULL; + const struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList = servingCellConfig ? servingCellConfig->downlinkBWP_ToAddModList : NULL; + const int bwp_id = servingCellConfig && servingCellConfig->firstActiveDownlinkBWP_Id ? + *servingCellConfig->firstActiveDownlinkBWP_Id : 0; + sched_ctrl->active_bwp = bwpList && bwp_id > 0 ? bwpList->list.array[bwp_id - 1] : NULL; + const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig ? servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList : NULL; + const int ubwp_id = servingCellConfig && servingCellConfig->uplinkConfig && servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id ? + *servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id : 0; + sched_ctrl->active_ubwp = ubwpList && ubwp_id > 0 ? ubwpList->list.array[ubwp_id - 1] : NULL; + sched_ctrl->bwp_switch_info.bwp_switch_state = BWP_SWITCH_INACTIVE; + } + break; + + case BWP_SWITCH_INACTIVE: + break; + + default: + AssertFatal(1==0,"Invalid bwp switch state\n"); + break; + } +} + +void schedule_nr_bwp_switch(module_id_t module_id, + frame_t frame, + sub_frame_t slot) { + + NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; + const NR_list_t *UE_list = &UE_info->list; + + // TODO: Implementation of a algorithm to perform: + // - the BWP switch trigger: sched_ctrl->bwp_switch_info.bwp_switch_state = BWP_SWITCH_TO_START + // - the BWP selection: sched_ctrl->bwp_switch_info.next_bwp = bwp_id + + for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + if(sched_ctrl->bwp_switch_info.bwp_switch_state > BWP_SWITCH_INACTIVE) { + nr_bwp_switch(module_id, frame, slot, UE_id, sched_ctrl->bwp_switch_info.next_bwp); + } + } + +} + void nr_schedule_ue_spec(module_id_t module_id, frame_t frame, sub_frame_t slot) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 407c325cff..072757aaed 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2076,6 +2076,11 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP, NR_CellGroupConfig_t *CellG scc, genericParameters, NULL); + sched_ctrl->bwp_switch_info.current_bwp = bwp_id; + sched_ctrl->bwp_switch_info.next_bwp = -1; + sched_ctrl->bwp_switch_info.bwp_switch_timer = 0; + sched_ctrl->bwp_switch_info.bwp_switch_state = BWP_SWITCH_INACTIVE; + sched_ctrl->bwp_switch_info.bwp_switch_delay = 40; const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig ? servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList : NULL; if (ubwpList) AssertFatal(ubwpList->list.count <= NR_MAX_NUM_BWP, "uplinkBWP_ToAddModList has %d BWP!\n", diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index af77767ea2..6286d99f29 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -983,8 +983,11 @@ bool allocate_ul_retransmission(module_id_t module_id, if (ps->time_domain_allocation != tda || ps->dci_format != dci_format - || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) + || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data + || sched_ctrl->update_pusch_ps) { nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); + sched_ctrl->update_pusch_ps = false; + } LOG_D(NR_MAC, "%s(): retransmission keeping TDA %d and TBS %d\n", __func__, tda, retInfo->tb_size); } else { /* the retransmission will use a different time domain allocation, check @@ -1163,6 +1166,10 @@ void pf_ul(module_id_t module_id, if (B == 0 && !do_sched) continue; + if(sched_ctrl->bwp_switch_info.bwp_switch_state == BWP_SWITCH_RUNNING) { + continue; + } + /* Schedule UE on SR or UL inactivity and no data (otherwise, will be scheduled * based on data to transmit) */ if (B == 0 && do_sched) { @@ -1220,8 +1227,11 @@ void pf_ul(module_id_t module_id, const int tda = sched_ctrl->active_ubwp ? nrmac->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; if (ps->time_domain_allocation != tda || ps->dci_format != dci_format - || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) + || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data + || sched_ctrl->update_pusch_ps) { nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); + sched_ctrl->update_pusch_ps = false; + } NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; sched_pusch->mcs = 9; update_ul_ue_R_Qm(sched_pusch, ps); @@ -1337,8 +1347,11 @@ void pf_ul(module_id_t module_id, const int tda = sched_ctrl->active_ubwp ? nrmac->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; if (ps->time_domain_allocation != tda || ps->dci_format != dci_format - || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) + || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data + || sched_ctrl->update_pusch_ps) { nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); + sched_ctrl->update_pusch_ps = false; + } update_ul_ue_R_Qm(sched_pusch, ps); /* Calculate the current scheduling bytes and the necessary RBs */ diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index c8c8b40fc9..a33d494c58 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -64,6 +64,10 @@ void clear_nr_nfapi_information(gNB_MAC_INST * gNB, void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame_rxP, sub_frame_t slot_rxP); +void schedule_nr_bwp_switch(module_id_t module_id, + frame_t frame, + sub_frame_t slot); + /* \brief main DL scheduler function. Calls a preprocessor to decide on * resource allocation, then "post-processes" resource allocation (nFAPI * messages, statistics, HARQ handling, CEs, ... */ diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 3db5326d39..9a00c381be 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -551,6 +551,20 @@ typedef struct NR_UE_ul_harq { NR_sched_pusch_t sched_pusch; } NR_UE_ul_harq_t; +typedef enum { + BWP_SWITCH_INACTIVE = 0, + BWP_SWITCH_TO_START, + BWP_SWITCH_RUNNING +} NR_BWP_switch_states_t; + +typedef struct NR_BWP_switch_info { + NR_BWP_Id_t current_bwp; + NR_BWP_Id_t next_bwp; + int bwp_switch_timer; + uint8_t bwp_switch_delay; + NR_BWP_switch_states_t bwp_switch_state; +} NR_BWP_switch_info_t; + /*! \brief scheduling control information set through an API */ #define MAX_CSI_REPORTS 48 typedef struct { @@ -558,6 +572,10 @@ typedef struct { NR_BWP_Downlink_t *active_bwp; /// the currently active BWP in UL NR_BWP_Uplink_t *active_ubwp; + + /// the state of bwp switch procedure + NR_BWP_switch_info_t bwp_switch_info; + /// CCE index and aggregation, should be coherent with cce_list NR_SearchSpace_t *search_space; NR_ControlResourceSet_t *coreset; @@ -624,7 +642,8 @@ typedef struct { int ul_failure; struct CSI_Report CSI_report[MAX_CSI_REPORTS]; bool SR; - + bool update_pdsch_ps; + bool update_pusch_ps; /// information about every HARQ process NR_UE_harq_t harq_processes[NR_MAX_NB_HARQ_PROCESSES]; /// HARQ processes that are free diff --git a/openair2/RRC/NR/L2_nr_interface.c b/openair2/RRC/NR/L2_nr_interface.c index cb29ecf347..3fa47389b2 100644 --- a/openair2/RRC/NR/L2_nr_interface.c +++ b/openair2/RRC/NR/L2_nr_interface.c @@ -304,6 +304,19 @@ uint16_t mac_rrc_nr_data_req(const module_id_t Mod_idP, } +int8_t nr_mac_rrc_bwp_switch_req(const module_id_t module_idP, + const frame_t frameP, + const sub_frame_t sub_frameP, + const rnti_t rntiP, + const int bwp_id) { + + struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[module_idP], rntiP); + + protocol_ctxt_t ctxt; + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, GNB_FLAG_YES, rntiP, frameP, sub_frameP, 0); + nr_rrc_reconfiguration_req(ue_context_p, &ctxt, bwp_id); +} + int8_t nr_mac_rrc_data_ind(const module_id_t module_idP, const int CC_id, const frame_t frameP, diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 87a4d20cff..0c0849e362 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -2493,7 +2493,9 @@ int16_t do_RRCReconfiguration( enc_rval.failed_type->name, enc_rval.encoded); return -1; } - xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)cellGroupConfig); + if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { + xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig); + } ie->nonCriticalExtension->masterCellGroup = calloc(1,sizeof(OCTET_STRING_t)); ie->nonCriticalExtension->masterCellGroup->buf = masterCellGroup_buf; @@ -2502,9 +2504,9 @@ int16_t do_RRCReconfiguration( dl_dcch_msg.message.choice.c1->choice.rrcReconfiguration->criticalExtensions.choice.rrcReconfiguration = ie; - //if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { - xer_fprint(stdout, &asn_DEF_NR_DL_DCCH_Message, (void *)&dl_dcch_msg); - //} + if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { + xer_fprint(stdout, &asn_DEF_NR_DL_DCCH_Message, (void *)&dl_dcch_msg); + } enc_rval = uper_encode_to_buffer(&asn_DEF_NR_DL_DCCH_Message, NULL, diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index a4e6d13a7d..fd54afe484 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -178,6 +178,12 @@ int nr_rrc_mac_remove_ue(module_id_t mod_idP, rnti_t rntiP); +int8_t nr_mac_rrc_bwp_switch_req(const module_id_t module_idP, + const frame_t frameP, + const sub_frame_t sub_frameP, + const rnti_t rntiP, + const int bwp_id); + int8_t nr_mac_rrc_data_ind( const module_id_t module_idP, const int CC_id, @@ -191,6 +197,10 @@ int8_t nr_mac_rrc_data_ind( const boolean_t brOption ); +int nr_rrc_reconfiguration_req(rrc_gNB_ue_context_t *const ue_context_pP, + protocol_ctxt_t *const ctxt_pP, + const int bwp_id); + int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, const uint8_t *buffer, int buffer_length, diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index d7e6c4f9d4..dbc37cfc45 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1775,6 +1775,44 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( } //----------------------------------------------------------------------------- +int nr_rrc_reconfiguration_req(rrc_gNB_ue_context_t *const ue_context_pP, + protocol_ctxt_t *const ctxt_pP, + const int bwp_id) { + + uint8_t buffer[RRC_BUF_SIZE]; + memset(buffer, 0, sizeof(buffer)); + uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); + + NR_CellGroupConfig_t *masterCellGroup = ue_context_pP->ue_context.masterCellGroup; + *masterCellGroup->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id = bwp_id; + *masterCellGroup->spCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id = bwp_id; + *masterCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id = bwp_id; + + uint16_t size = do_RRCReconfiguration(ctxt_pP, + buffer, + sizeof(buffer), + xid, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + masterCellGroup); + + nr_rrc_data_req(ctxt_pP, + DCCH, + rrc_gNB_mui++, + SDU_CONFIRM_NO, + size, + buffer, + PDCP_TRANSMISSION_MODE_CONTROL); + + return 0; +} + /*------------------------------------------------------------------------------*/ int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, const uint8_t *buffer,