From 43036eb83d54e818e4273ae1b6e6351e8c75e244 Mon Sep 17 00:00:00 2001 From: sriharsha Date: Thu, 28 Sep 2023 14:33:02 +0200 Subject: [PATCH 1/5] Add implementation of logical channel prioritization at UE - Reorder the logical channels based on priority - Handling of configuration and release of logical channel bearer - Add changes in the implementation of lcp procedure for equal priority logical channels - Restructure the lcp parameters as a separate structure - Further code clean up --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 127 +++- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 56 +- openair2/LAYER2/NR_MAC_UE/mac_proto.h | 14 + openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 16 +- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 625 +++++++++++++++---- 5 files changed, 677 insertions(+), 161 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index b1624126bb..adca3def49 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -30,6 +30,8 @@ * \warning */ +#define _GNU_SOURCE + //#include "mac_defs.h" #include #include "NR_MAC_UE/mac_proto.h" @@ -39,6 +41,32 @@ #include "executables/softmodem-common.h" #include "SCHED_NR/phy_frame_config_nr.h" +const long logicalChannelGroup0_NR = 0; +typedef struct NR_LogicalChannelConfig__ul_SpecificParameters LcConfig_UlParamas_t; + +const LcConfig_UlParamas_t NR_LCSRB1 = { + .priority = 1, + .prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity, + .logicalChannelGroup = (long *)&logicalChannelGroup0_NR}; + +const LcConfig_UlParamas_t NR_LCSRB2 = { + .priority = 3, + .prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity, + .logicalChannelGroup = (long *)&logicalChannelGroup0_NR}; + +const LcConfig_UlParamas_t NR_LCSRB3 = { + .priority = 1, + .prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity, + .logicalChannelGroup = (long *)&logicalChannelGroup0_NR}; + +// these are the default values for SRB configurations(SRB1 and SRB2) as mentioned in 36.331 pg 258-259 +const NR_LogicalChannelConfig_t NR_SRB1_logicalChannelConfig_defaultValue = {.ul_SpecificParameters = + (LcConfig_UlParamas_t *)&NR_LCSRB1}; +const NR_LogicalChannelConfig_t NR_SRB2_logicalChannelConfig_defaultValue = {.ul_SpecificParameters = + (LcConfig_UlParamas_t *)&NR_LCSRB2}; +const NR_LogicalChannelConfig_t NR_SRB3_logicalChannelConfig_defaultValue = {.ul_SpecificParameters = + (LcConfig_UlParamas_t *)&NR_LCSRB3}; + void set_tdd_config_nr_ue(fapi_nr_tdd_table_t *tdd_table, int mu, NR_TDD_UL_DL_Pattern_t *pattern) @@ -511,26 +539,107 @@ void configure_ss_coreset(NR_UE_MAC_INST_t *mac, mac->BWP_coresets[i] = NULL; } +static int lcid_cmp(const void *lcid1, const void *lcid2, void *mac_inst) +{ + uint8_t id1 = *(uint8_t *)lcid1; + uint8_t id2 = *(uint8_t *)lcid2; + NR_UE_MAC_INST_t *mac = (NR_UE_MAC_INST_t *)mac_inst; + + NR_LogicalChannelConfig_t **lc_config = &mac->logicalChannelConfig[0]; + + AssertFatal(id1 > 0 && id2 > 0, "undefined logical channel identity\n"); + AssertFatal(lc_config[id1 - 1] != NULL || lc_config[id2 - 1] != NULL, "logical channel configuration should be available\n"); + + return (lc_config[id1 - 1]->ul_SpecificParameters->priority - lc_config[id2 - 1]->ul_SpecificParameters->priority); +} + +void nr_release_mac_config_logicalChannelBearer(module_id_t module_id, long channel_identity) +{ + NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); + if (mac->logicalChannelConfig[channel_identity - 1] != NULL) { + mac->logicalChannelConfig[channel_identity - 1] = NULL; + memset(&mac->scheduling_info.lc_sched_info[channel_identity - 1], 0, sizeof(NR_LC_SCHEDULING_INFO)); + } else { + LOG_E(NR_MAC, "Trying to release a non configured logical channel bearer %li\n", channel_identity); + } +} + +void nr_configure_mac_config_logicalChannelBearer(module_id_t module_id, + long channel_identity, + NR_LogicalChannelConfig_t *lc_config) +{ + NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); + + LOG_I(NR_MAC, "[MACLogicalChannelConfig]Applying RRC Logical Channel Config %d to lcid %li\n", module_id, channel_identity); + mac->logicalChannelConfig[channel_identity - 1] = lc_config; + + // initialize the variable Bj for every LCID + mac->scheduling_info.lc_sched_info[channel_identity - 1].Bj = 0; + + // store the bucket size + int pbr = nr_get_pbr(lc_config->ul_SpecificParameters->prioritisedBitRate); + int bsd = nr_get_ms_bucketsizeduration(lc_config->ul_SpecificParameters->bucketSizeDuration); + + // in infinite pbr, the bucket is saturated by pbr + if (lc_config->ul_SpecificParameters->prioritisedBitRate + == NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity) { + bsd = 1; + } + mac->scheduling_info.lc_sched_info[channel_identity - 1].bucket_size = pbr * bsd; + + if (lc_config->ul_SpecificParameters->logicalChannelGroup != NULL) + mac->scheduling_info.lc_sched_info[channel_identity - 1].LCGID = *lc_config->ul_SpecificParameters->logicalChannelGroup; + else + mac->scheduling_info.lc_sched_info[channel_identity - 1].LCGID = 0; +} + void nr_rrc_mac_config_req_ue_logicalChannelBearer(module_id_t module_id, struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_toadd_list, struct NR_CellGroupConfig__rlc_BearerToReleaseList *rlc_torelease_list) { NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); - if (rlc_toadd_list) { - for (int i = 0; i < rlc_toadd_list->list.count; i++) { - NR_RLC_BearerConfig_t *rlc_bearer = rlc_toadd_list->list.array[i]; - int id = rlc_bearer->logicalChannelIdentity - 1; - mac->active_RLC_bearer[id] = true; - } - } if (rlc_torelease_list) { for (int i = 0; i < rlc_torelease_list->list.count; i++) { if (rlc_torelease_list->list.array[i]) { - int id = *rlc_torelease_list->list.array[i] - 1; - mac->active_RLC_bearer[id] = false; + int lc_identity = *rlc_torelease_list->list.array[i]; + nr_release_mac_config_logicalChannelBearer(module_id, lc_identity); } } } + if (rlc_toadd_list) { + for (int i = 0; i < rlc_toadd_list->list.count; i++) { + NR_RLC_BearerConfig_t *rlc_bearer = rlc_toadd_list->list.array[i]; + int lc_identity = rlc_bearer->logicalChannelIdentity; + mac->lc_ordered_info.lcids_ordered[i] = lc_identity; + NR_LogicalChannelConfig_t *mac_lc_config; + if (rlc_bearer->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity) { /* SRB */ + NR_SRB_Identity_t srb_id = rlc_bearer->servedRadioBearer->choice.srb_Identity; + if (rlc_bearer->mac_LogicalChannelConfig != NULL) { + mac_lc_config = rlc_bearer->mac_LogicalChannelConfig; + } else { + LOG_I(NR_RRC, "Applying the default logicalChannelConfig for SRB\n"); + if (srb_id == 1) + mac_lc_config = (NR_LogicalChannelConfig_t *)&NR_SRB1_logicalChannelConfig_defaultValue; + else if (srb_id == 2) + mac_lc_config = (NR_LogicalChannelConfig_t *)&NR_SRB2_logicalChannelConfig_defaultValue; + else if (srb_id == 3) + mac_lc_config = (NR_LogicalChannelConfig_t *)&NR_SRB3_logicalChannelConfig_defaultValue; + else + AssertFatal(1 == 0, "The logical id %d is not a valid SRB id %li\n", lc_identity, srb_id); + } + } else { /* DRB */ + mac_lc_config = rlc_bearer->mac_LogicalChannelConfig; + AssertFatal(mac_lc_config != NULL, "For DRB, it should be mandatorily present\n"); + } + nr_configure_mac_config_logicalChannelBearer(module_id, lc_identity, mac_lc_config); + } + + // reorder the logical channels as per its priority + qsort_r((void *)mac->lc_ordered_info.lcids_ordered, rlc_toadd_list->list.count, sizeof(uint32_t), lcid_cmp, (void *)mac); + for (uint8_t i = 0; i < rlc_toadd_list->list.count; i++) { + mac->lc_ordered_info.logicalChannelConfig_ordered[i] = mac->logicalChannelConfig[mac->lc_ordered_info.lcids_ordered[i] - 1]; + } + } } void configure_current_BWP(NR_UE_MAC_INST_t *mac, diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 068890f620..fe94212f73 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -171,24 +171,38 @@ typedef enum { RA_4STEP } nr_ra_type_e; +typedef struct { + // after multiplexing buffer remain for each lcid + int32_t LCID_buffer_remain; + // buffer status for each lcid + uint8_t LCID_status; + // Bj bucket usage per lcid + int32_t Bj; + // Bucket size per lcid + int32_t bucket_size; + // logical channel group id for each LCID + uint8_t LCGID; +} NR_LC_SCHEDULING_INFO; + +typedef struct { + // buffer status for each lcgid + uint8_t BSR; // should be more for mesh topology + // keep the number of bytes in rlc buffer for each lcgid + int32_t BSR_bytes; +} NR_LCG_SCHEDULING_INFO; + // LTE structure, might need to be adapted for NR typedef struct { - /// buffer status for each lcgid - uint8_t BSR[NR_MAX_NUM_LCGID]; // should be more for mesh topology - /// keep the number of bytes in rlc buffer for each lcgid - int32_t BSR_bytes[NR_MAX_NUM_LCGID]; - /// after multiplexing buffer remain for each lcid - int32_t LCID_buffer_remain[NR_MAX_NUM_LCID]; + // lcs scheduling info + NR_LC_SCHEDULING_INFO lc_sched_info[NR_MAX_NUM_LCID]; + // lcg scheduling info + NR_LCG_SCHEDULING_INFO lcg_sched_info[NR_MAX_NUM_LCGID]; /// sum of all lcid buffer size - uint16_t All_lcid_buffer_size_lastTTI; - /// buffer status for each lcid - uint8_t LCID_status[NR_MAX_NUM_LCID]; + uint16_t All_lcid_buffer_size_lastTTI; /// SR pending as defined in 38.321 uint8_t SR_pending; /// SR_COUNTER as defined in 38.321 uint16_t SR_COUNTER; - /// logical channel group ide for each LCID - uint8_t LCGID[NR_MAX_NUM_LCID]; /// retxBSR-Timer, default value is sf2560 uint16_t retxBSR_Timer; /// retxBSR_SF, number of subframe before triggering a regular BSR @@ -226,11 +240,6 @@ typedef struct { uint16_t extendedBSR_Sizes_r10; /// default value is false uint16_t extendedPHR_r10; - - //Bj bucket usage per lcid - int16_t Bj[NR_MAX_NUM_LCID]; - // Bucket size per lcid - int16_t bucket_size[NR_MAX_NUM_LCID]; } NR_UE_SCHEDULING_INFO; typedef enum { @@ -424,6 +433,14 @@ typedef struct ssb_list_info { uint8_t nb_tx_ssb; } ssb_list_info_t; +typedef struct nr_lcordered_info_s { + // logical channels ids ordered as per priority + int lcids_ordered[NR_MAX_NUM_LCID]; + + // logical channel configurations reordered as per priority + NR_LogicalChannelConfig_t *logicalChannelConfig_ordered[NR_MAX_NUM_LCID]; +} nr_lcordered_info_t; + /*!\brief Top level UE MAC structure */ typedef struct { NR_UE_L2_STATE_t state; @@ -508,8 +525,11 @@ typedef struct { /// BSR report flag management uint8_t BSR_reporting_active; - /// LogicalChannelConfig has bearer. - bool active_RLC_bearer[NR_MAX_NUM_LCID]; + // Pointers to LogicalChannelConfig indexed by LogicalChannelIdentity. Note NULL means LCHAN is inactive. + NR_LogicalChannelConfig_t *logicalChannelConfig[NR_MAX_NUM_LCID]; + + // order lc info + nr_lcordered_info_t lc_ordered_info; NR_UE_SCHEDULING_INFO scheduling_info; /// PHR diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 60c64ead12..9269b1c5e8 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -148,6 +148,20 @@ bool nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t uint8_t nr_locate_BsrIndexByBufferSize(const uint32_t *table, int size, int value); +/*! \fn int nr_get_pbr(uint8_t prioritizedbitrate) + \brief get the rate in kbps from the rate configured by the higher layer +\param[in] prioritizedbitrate +\return the rate in kbps +*/ +uint32_t nr_get_pbr(uint8_t prioritizedbitrate); + +/*! \fn int nr_get_ms_bucketsizeduration(uint8_t bucketSizeduration) + \brief get the time in ms from the bucket size duration configured by the higher layer +\param[in] bucketSize the bucket size duration +\return the time in ms +*/ +uint16_t nr_get_ms_bucketsizeduration(uint8_t bucketsizeduration); + /*! \fn int nr_get_sf_periodicBSRTimer(uint8_t periodicBSR_Timer) \brief get the number of subframe from the periodic BSR timer configured by the higher layers \param[in] periodicBSR_Timer timer for periodic BSR diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index f5902bed27..8b1382f23f 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -188,17 +188,11 @@ void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac) for (int i = 0; i < NR_MAX_NUM_LCID; i++) { LOG_D(NR_MAC, "Applying default logical channel config for LCGID %d\n", i); - mac->scheduling_info.Bj[i] = -1; - mac->scheduling_info.bucket_size[i] = -1; - - if (i < UL_SCH_LCID_DTCH) { // initialize all control channels lcgid to 0 - mac->scheduling_info.LCGID[i] = 0; - } else { // initialize all the data channels lcgid to 1 - mac->scheduling_info.LCGID[i] = 1; - } - - mac->scheduling_info.LCID_status[i] = LCID_EMPTY; - mac->scheduling_info.LCID_buffer_remain[i] = 0; + mac->scheduling_info.lc_sched_info[i].Bj = -1; + mac->scheduling_info.lc_sched_info[i].bucket_size = -1; + mac->scheduling_info.lc_sched_info[i].LCGID = 0; // defaults to 0 irrespective of SRB or DRB + mac->scheduling_info.lc_sched_info[i].LCID_status = LCID_EMPTY; + mac->scheduling_info.lc_sched_info[i].LCID_buffer_remain = 0; for (int k = 0; k < NR_MAX_HARQ_PROCESSES; k++) mac->first_ul_tx[k] = 1; } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index e5ecba5efc..5f7728eb3a 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -1095,6 +1095,35 @@ void nr_ue_ul_scheduler(nr_uplink_indication_t *ul_info) pthread_mutex_unlock(&ul_config->mutex_ul_config); } + // update Bj for all active lcids before LCP procedure + LOG_D(NR_MAC, "====================[Frame %d][Slot %d]Logical Channel Prioritization===========\n", frame_tx, slot_tx); + NR_LogicalChannelConfig_t **lc_bearer; + int *lcid_ptr; + for (lcid_ptr = mac->lc_ordered_info.lcids_ordered, lc_bearer = mac->lc_ordered_info.logicalChannelConfig_ordered; + (*lcid_ptr <= NR_MAX_NUM_LCID) && (*lc_bearer != NULL); + lcid_ptr++, lc_bearer++) { + int lcid = *lcid_ptr; + NR_LogicalChannelConfig_t *lcconfig = mac->logicalChannelConfig[lcid - 1]; + NR_LC_SCHEDULING_INFO *sched_lc = &mac->scheduling_info.lc_sched_info[lcid - 1]; + int32_t bucketSize_max = + sched_lc->bucket_size; // max amount of data that can be buffered/accumulated in a logical channel buffer + + /* + measure Bj + increment the value of Bj by product PBR * T + */ + int T = 1; // time elapsed since Bj was last incremented + int32_t bj = sched_lc->Bj; + bj += nr_get_pbr(lcconfig->ul_SpecificParameters->prioritisedBitRate) * T; + if (lcconfig->ul_SpecificParameters->prioritisedBitRate + == NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity) { + bj = nr_get_pbr(lcconfig->ul_SpecificParameters->prioritisedBitRate); + } + + // bj > max bucket size, set bj to max bucket size, as in ts38.321 5.4.3.1 Logical Channel Prioritization + sched_lc->Bj = min(bj, bucketSize_max); + } + // Call BSR procedure as described in Section 5.4.5 in 38.321 // First check ReTxBSR Timer because it is always configured @@ -1147,23 +1176,23 @@ bool nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { // Reset transmission status lcid_bytes_in_buffer[lcid - 1] = 0; - mac->scheduling_info.LCID_status[lcid - 1] = LCID_EMPTY; + mac->scheduling_info.lc_sched_info[lcid - 1].LCID_status = LCID_EMPTY; } for (int lcgid = 0; lcgid < NR_MAX_NUM_LCGID; lcgid++) { // Reset Buffer Info - mac->scheduling_info.BSR[lcgid] = 0; - mac->scheduling_info.BSR_bytes[lcgid] = 0; + mac->scheduling_info.lcg_sched_info[lcgid].BSR = 0; + mac->scheduling_info.lcg_sched_info[lcgid].BSR_bytes = 0; } //Get Buffer Occupancy and fill lcid_reordered_array for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { - if (mac->active_RLC_bearer[lcid - 1]) { // todo - int lcgid = mac->scheduling_info.LCGID[lcid - 1]; + if (mac->logicalChannelConfig[lcid - 1] != NULL) { // todo + int lcgid = mac->scheduling_info.lc_sched_info[lcid - 1].LCGID; // Store already available data to transmit per Group if (lcgid < NR_MAX_NUM_LCGID) { - lcgid_buffer_remain[lcgid] += mac->scheduling_info.LCID_buffer_remain[lcid - 1]; + lcgid_buffer_remain[lcgid] += mac->scheduling_info.lc_sched_info[lcid - 1].LCID_buffer_remain; } mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(module_idP, mac->crnti,gNB_index,frameP,slotP,ENB_FLAG_NO,MBMS_FLAG_NO, lcid, 0, 0); @@ -1173,13 +1202,13 @@ bool nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t if (rlc_status.bytes_in_buffer > 0) { LOG_D(NR_MAC,"[UE %d] PDCCH Tick : LCID%d LCGID%d has data to transmit =%d bytes at frame %d slot %d\n", module_idP, lcid,lcgid,rlc_status.bytes_in_buffer,frameP,slotP); - mac->scheduling_info.LCID_status[lcid - 1] = LCID_NOT_EMPTY; + mac->scheduling_info.lc_sched_info[lcid - 1].LCID_status = LCID_NOT_EMPTY; //Update BSR_bytes and position in lcid_reordered_array only if Group is defined if (lcgid < NR_MAX_NUM_LCGID) { num_lcid_with_data ++; // sum lcid buffer which has same lcgid - mac->scheduling_info.BSR_bytes[lcgid] += rlc_status.bytes_in_buffer; + mac->scheduling_info.lcg_sched_info[lcgid].BSR_bytes += rlc_status.bytes_in_buffer; //Fill in the array array_index = 0; @@ -1222,7 +1251,7 @@ bool nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t "[UE %d] PDCCH Tick : MAC BSR Triggered LCID%d LCGID%d data become available at frame %d slot %d\n", module_idP, lcid, - mac->scheduling_info.LCGID[lcid - 1], + mac->scheduling_info.lc_sched_info[lcid - 1].LCGID, frameP, slotP); break; @@ -1242,7 +1271,7 @@ bool nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t //Store Buffer Occupancy in remain buffers for next TTI for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { - mac->scheduling_info.LCID_buffer_remain[lcid - 1] = lcid_bytes_in_buffer[lcid - 1]; + mac->scheduling_info.lc_sched_info[lcid - 1].LCID_buffer_remain = lcid_bytes_in_buffer[lcid - 1]; } return bsr_regular_triggered; @@ -2632,7 +2661,7 @@ int nr_ue_get_sdu_mac_ce_pre(module_id_t module_idP, mac_ce_p->phr_header_len = 0; //sizeof(SCH_SUBHEADER_FIXED); int lcg_id = 0; while (lcg_id < NR_MAX_NUM_LCGID) { - if (mac->scheduling_info.BSR_bytes[lcg_id]) { + if (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes) { num_lcg_id_with_data++; } @@ -2713,11 +2742,17 @@ void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP, int lcg_id_bsr_trunc = 0; for (lcg_id = 0; lcg_id < NR_MAX_NUM_LCGID; lcg_id++) { if (mac_ce_p->bsr_ce_len == sizeof(NR_BSR_SHORT)) { - mac->scheduling_info.BSR[lcg_id] = nr_locate_BsrIndexByBufferSize(NR_SHORT_BSR_TABLE, NR_SHORT_BSR_TABLE_SIZE, mac->scheduling_info.BSR_bytes[lcg_id]); + mac->scheduling_info.lcg_sched_info[lcg_id].BSR = + nr_locate_BsrIndexByBufferSize(NR_SHORT_BSR_TABLE, + NR_SHORT_BSR_TABLE_SIZE, + mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes); } else { - mac->scheduling_info.BSR[lcg_id] = nr_locate_BsrIndexByBufferSize(NR_LONG_BSR_TABLE, NR_LONG_BSR_TABLE_SIZE, mac->scheduling_info.BSR_bytes[lcg_id]); + mac->scheduling_info.lcg_sched_info[lcg_id].BSR = + nr_locate_BsrIndexByBufferSize(NR_LONG_BSR_TABLE, + NR_LONG_BSR_TABLE_SIZE, + mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes); } - if (mac->scheduling_info.BSR_bytes[lcg_id]) { + if (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes) { num_lcg_id_with_data++; lcg_id_bsr_trunc = lcg_id; } @@ -2751,8 +2786,8 @@ void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP, // REPORT SHORT TRUNCATED BSR //Get LCGID of highest priority LCID with data (todo) for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { - lcg_id = mac->scheduling_info.LCGID[lcid - 1]; - if ((lcg_id < NR_MAX_NUM_LCGID) && (mac->scheduling_info.BSR_bytes[lcg_id])) { + lcg_id = mac->scheduling_info.lc_sched_info[lcid - 1].LCGID; + if ((lcg_id < NR_MAX_NUM_LCGID) && (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes)) { lcg_id_bsr_trunc = lcg_id; } } @@ -2778,25 +2813,29 @@ void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP, } else if (mac_ce_p->bsr_header_len == sizeof(NR_MAC_SUBHEADER_SHORT)) { mac_ce_p->bsr_s = NULL; mac_ce_p->bsr_t = NULL; - mac_ce_p->bsr_l->Buffer_size0 = mac->scheduling_info.BSR[0]; - mac_ce_p->bsr_l->Buffer_size1 = mac->scheduling_info.BSR[1]; - mac_ce_p->bsr_l->Buffer_size2 = mac->scheduling_info.BSR[2]; - mac_ce_p->bsr_l->Buffer_size3 = mac->scheduling_info.BSR[3]; - mac_ce_p->bsr_l->Buffer_size4 = mac->scheduling_info.BSR[4]; - mac_ce_p->bsr_l->Buffer_size5 = mac->scheduling_info.BSR[5]; - mac_ce_p->bsr_l->Buffer_size6 = mac->scheduling_info.BSR[6]; - mac_ce_p->bsr_l->Buffer_size7 = mac->scheduling_info.BSR[7]; - LOG_D(NR_MAC, "[UE %d] Frame %d subframe %d BSR Trig=%d report LONG BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d level LCGID4 %d,level LCGID5 %d,level LCGID6 %d,level LCGID7 %d)\n", - module_idP, frameP, subframe, + mac_ce_p->bsr_l->Buffer_size0 = mac->scheduling_info.lcg_sched_info[0].BSR; + mac_ce_p->bsr_l->Buffer_size1 = mac->scheduling_info.lcg_sched_info[1].BSR; + mac_ce_p->bsr_l->Buffer_size2 = mac->scheduling_info.lcg_sched_info[2].BSR; + mac_ce_p->bsr_l->Buffer_size3 = mac->scheduling_info.lcg_sched_info[3].BSR; + mac_ce_p->bsr_l->Buffer_size4 = mac->scheduling_info.lcg_sched_info[4].BSR; + mac_ce_p->bsr_l->Buffer_size5 = mac->scheduling_info.lcg_sched_info[5].BSR; + mac_ce_p->bsr_l->Buffer_size6 = mac->scheduling_info.lcg_sched_info[6].BSR; + mac_ce_p->bsr_l->Buffer_size7 = mac->scheduling_info.lcg_sched_info[7].BSR; + LOG_D(NR_MAC, + "[UE %d] Frame %d subframe %d BSR Trig=%d report LONG BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 " + "%d level LCGID4 %d,level LCGID5 %d,level LCGID6 %d,level LCGID7 %d)\n", + module_idP, + frameP, + subframe, mac->BSR_reporting_active, - mac->scheduling_info.BSR[0], - mac->scheduling_info.BSR[1], - mac->scheduling_info.BSR[2], - mac->scheduling_info.BSR[3], - mac->scheduling_info.BSR[4], - mac->scheduling_info.BSR[5], - mac->scheduling_info.BSR[6], - mac->scheduling_info.BSR[7]); + mac->scheduling_info.lcg_sched_info[0].BSR, + mac->scheduling_info.lcg_sched_info[1].BSR, + mac->scheduling_info.lcg_sched_info[2].BSR, + mac->scheduling_info.lcg_sched_info[3].BSR, + mac->scheduling_info.lcg_sched_info[4].BSR, + mac->scheduling_info.lcg_sched_info[5].BSR, + mac->scheduling_info.lcg_sched_info[6].BSR, + mac->scheduling_info.lcg_sched_info[7].BSR); } else if (mac_ce_p->bsr_header_len == sizeof(NR_MAC_SUBHEADER_FIXED)) { mac_ce_p->bsr_l = NULL; @@ -2804,19 +2843,27 @@ void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP, //Truncated BSR mac_ce_p->bsr_s = NULL; mac_ce_p->bsr_t->LcgID = lcg_id_bsr_trunc; - mac_ce_p->bsr_t->Buffer_size = mac->scheduling_info.BSR[lcg_id_bsr_trunc]; - LOG_D(NR_MAC, "[UE %d] Frame %d subframe %d BSR Trig=%d report TRUNCATED BSR with level %d for LCGID %d\n", - module_idP, frameP, subframe, + mac_ce_p->bsr_t->Buffer_size = mac->scheduling_info.lcg_sched_info[lcg_id_bsr_trunc].BSR; + LOG_D(NR_MAC, + "[UE %d] Frame %d subframe %d BSR Trig=%d report TRUNCATED BSR with level %d for LCGID %d\n", + module_idP, + frameP, + subframe, mac->BSR_reporting_active, - mac->scheduling_info.BSR[lcg_id_bsr_trunc], lcg_id_bsr_trunc); + mac->scheduling_info.lcg_sched_info[lcg_id_bsr_trunc].BSR, + lcg_id_bsr_trunc); } else { mac_ce_p->bsr_t = NULL; mac_ce_p->bsr_s->LcgID = lcg_id_bsr_trunc; - mac_ce_p->bsr_s->Buffer_size = mac->scheduling_info.BSR[lcg_id_bsr_trunc]; - LOG_D(NR_MAC, "[UE %d] Frame %d subframe %d BSR Trig=%d report SHORT BSR with level %d for LCGID %d\n", - module_idP, frameP, subframe, + mac_ce_p->bsr_s->Buffer_size = mac->scheduling_info.lcg_sched_info[lcg_id_bsr_trunc].BSR; + LOG_D(NR_MAC, + "[UE %d] Frame %d subframe %d BSR Trig=%d report SHORT BSR with level %d for LCGID %d\n", + module_idP, + frameP, + subframe, mac->BSR_reporting_active, - mac->scheduling_info.BSR[lcg_id_bsr_trunc], lcg_id_bsr_trunc); + mac->scheduling_info.lcg_sched_info[lcg_id_bsr_trunc].BSR, + lcg_id_bsr_trunc); } } @@ -2845,6 +2892,92 @@ void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP, } } +uint32_t get_count_lcids_same_priority(NR_UE_MAC_INST_t *mac, uint8_t start, uint8_t total_active_lcids, int *lcid_ordered_array) +{ + // count number of logical channels with same priority as curr_lcid + uint8_t same_priority_count = 0; + uint8_t curr_lcid = lcid_ordered_array[start]; + NR_LogicalChannelConfig_t *lc_config_curr = mac->logicalChannelConfig[curr_lcid - 1]; + for (uint8_t index = start; index < total_active_lcids; index++) { + uint8_t next_lcid = lcid_ordered_array[index]; + NR_LogicalChannelConfig_t *lc_config_next = mac->logicalChannelConfig[next_lcid - 1]; + if (lc_config_curr->ul_SpecificParameters->priority == lc_config_next->ul_SpecificParameters->priority) { + same_priority_count++; + } + } + return same_priority_count; +} + +long get_num_bytes_to_reqlc(NR_UE_MAC_INST_t *mac, + uint8_t same_priority_count, + uint8_t lc_num, + uint16_t buflen_remain_ep, + int16_t buflen_remain, + uint8_t round_id, + uint32_t *bytes_read_fromlc, + long *target) +{ + /* Calculates the number of bytes the logical channel should request from the correcponding RLC buffer*/ + NR_LogicalChannelConfig_t *lc_config = mac->logicalChannelConfig[lc_num - 1]; + long pbr = nr_get_pbr(lc_config->ul_SpecificParameters->prioritisedBitRate); + int32_t lcid_remain_buffer = mac->scheduling_info.lc_sched_info[lc_num - 1].LCID_buffer_remain; + *target = (same_priority_count > 1) ? min(buflen_remain_ep, pbr) : pbr; + + long num_remaining_bytes = 0; + long num_bytes_requested = 0; + if (round_id == 0) { // initial round + uint16_t pdu_remain = (same_priority_count > 1) ? buflen_remain_ep : buflen_remain; + num_bytes_requested = (pdu_remain < pbr) ? min(pdu_remain, lcid_remain_buffer) : min(pbr, lcid_remain_buffer); + num_remaining_bytes = *target - bytes_read_fromlc[lc_num - 1]; + num_bytes_requested = min(num_bytes_requested, num_remaining_bytes); + } else { // from first round + if (same_priority_count > 1) { + num_bytes_requested = min(buflen_remain_ep, lcid_remain_buffer); + num_remaining_bytes = buflen_remain_ep - bytes_read_fromlc[lc_num - 1]; + num_bytes_requested = min(num_bytes_requested, num_remaining_bytes); + } else { + num_bytes_requested = min(buflen_remain, lcid_remain_buffer); + } + } + AssertFatal(num_remaining_bytes >= 0, "the total number of bytes allocated until target length is greater than expected\n"); + + return num_bytes_requested; +} + +bool get_dataavailability_buffers(uint8_t total_active_lcids, int *lcid_ordered_array, bool *data_status_lcbuffers) +{ + // check whether there is any data in the rlc buffer corresponding to active lcs + for (uint8_t id = 0; id < total_active_lcids; id++) { + int lcid = lcid_ordered_array[id]; + if (data_status_lcbuffers[lcid - 1]) { + return true; + } + } + return false; +} + +uint8_t select_logical_channels(NR_UE_MAC_INST_t *mac, uint8_t *num_active_lcids, int *active_lcids) +{ + // (TODO: selection of logical channels for logical channel prioritization procedure as per 5.4.3.1.2 Selection of logical + // channels, TS38.321) + + // selection of logical channels with Bj > 0 + + NR_LogicalChannelConfig_t **lc_bearer; + int *lcid_ptr; + for (lcid_ptr = mac->lc_ordered_info.lcids_ordered, lc_bearer = mac->lc_ordered_info.logicalChannelConfig_ordered; + (*lcid_ptr < NR_MAX_NUM_LCID) && (*lc_bearer != NULL); + lcid_ptr++, lc_bearer++) { + uint8_t lcid = *lcid_ptr; + if (mac->scheduling_info.lc_sched_info[lcid - 1].Bj > 0) { + active_lcids[*num_active_lcids] = lcid; + LOG_D(NR_MAC, "The available lcid is %d\n", active_lcids[*num_active_lcids]); + (*num_active_lcids)++; + } + } + return 0; +} + /** * Function: to fetch data to be transmitted from RLC, place it in the ULSCH PDU buffer to generate the complete MAC PDU with sub-headers and MAC CEs according to ULSCH MAC PDU generation (6.1.2 TS 38.321) @@ -2886,113 +3019,256 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP, //NR_POWER_HEADROOM_CMD phr; //mac_ce_p->phr_p = &phr; NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP); + + NR_UE_SCHEDULING_INFO *sched_info = &mac->scheduling_info; //int highest_priority = 16; const uint8_t sh_size = sizeof(NR_MAC_SUBHEADER_LONG); // Pointer used to build the MAC PDU by placing the RLC SDUs in the ULSCH buffer uint8_t *pdu = ulsch_buffer; - //nr_ue_get_sdu_mac_ce_pre updates all mac_ce related header field related to length + // variable used to build the lcids with positive Bj + int lcids_bj_pos[NR_MAX_NUM_LCID] = {0}; + uint8_t avail_lcids_count = 0; + + // variable used to store the lcid data status during lcp + bool lcids_data_status[NR_MAX_NUM_LCID] = {0}; + memset(lcids_data_status, 1, NR_MAX_NUM_LCID); + + long bytes_requested = 0; + + uint32_t lcp_allocation_counter = + 0; // in the first run all the lc are allocated as per bj and prioritized bit rate but in subsequent runs, no need to consider + // bj and prioritized bit rate but just consider priority + uint16_t buflen_ep = 0; // this variable holds the length in bytes in mac pdu when multiple equal priority channels are present + // because as per standard(TS38.321), all equal priority channels should be served equally + + // nr_ue_get_sdu_mac_ce_pre updates all mac_ce related header field related to length mac_ce_p->tot_mac_ce_len = nr_ue_get_sdu_mac_ce_pre(module_idP, CC_id, frameP, subframe, gNB_index, ulsch_buffer, buflen, mac_ce_p); mac_ce_p->total_mac_pdu_header_len = mac_ce_p->tot_mac_ce_len; LOG_D(NR_MAC, "In %s: [UE %d] [%d.%d] process UL transport block at with size TBS = %d bytes \n", __FUNCTION__, module_idP, frameP, subframe, buflen); - // Check for DCCH first - // TO DO: Multiplex in the order defined by the logical channel prioritization - for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { - if (!mac->active_RLC_bearer[lcid - 1]) - continue; - buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total + sh_size); + // selection of logical channels + select_logical_channels(mac, &avail_lcids_count, lcids_bj_pos); + LOG_D(NR_MAC, + "In %s: [UE %d] [%d.%d] number of active logical channels are %d \n", + __FUNCTION__, + module_idP, + frameP, + subframe, + avail_lcids_count); - LOG_D(NR_MAC, - "[UE %d] [%d.%d] UL-DXCH -> ULSCH, RLC with LCID 0x%02x (TBS %d bytes, sdu_length_total %d bytes, MAC header len %d " - "bytes, buflen_remain %d bytes)\n", - module_idP, - frameP, - subframe, - lcid, - buflen, - mac_ce_p->sdu_length_total, - mac_ce_p->tot_mac_ce_len, - buflen_remain); + // multiplex in the order of highest priority + do { + /* + go until there is space availabile in the MAC PDU and there is data available in RLC buffers of active logical channels + */ + uint8_t num_lcids_same_priority = 0; + uint8_t count_same_priority_lcids = 0; - while (buflen_remain > 0) { - // Pointer used to build the MAC sub-PDU headers in the ULSCH buffer for each SDU - NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) pdu; + // variable used to store the total bytes read from rlc for each lcid + uint32_t lcids_bytes_tot[NR_MAX_NUM_LCID] = {0}; - pdu += sh_size; + for (uint8_t id = 0; id < avail_lcids_count; id++) { + /* + loop over all logical channels in the order of priority. As stated in ts spec, in the first run, only prioritized + number of bytes are taken out from the correspondinf RLC buffers of all active logical channels and if there is still + space availble in the MAC PDU, then from the next run all the remaining data from the higher priority logical channel + is placed in the MAC PDU before going on to next high priority logical channel + */ + int lcid = lcids_bj_pos[id]; - sdu_length = mac_rlc_data_req(module_idP, - mac->crnti, - gNB_index, - frameP, - ENB_FLAG_NO, - MBMS_FLAG_NO, - lcid, - buflen_remain, - (char *)pdu, - 0, - 0); - - AssertFatal(buflen_remain >= sdu_length, - "LCID = 0x%02x RLC has segmented %d bytes but MAC has max %d remaining bytes\n", - lcid, - sdu_length, - buflen_remain); - - if (sdu_length > 0) { + // skip the logical channel if no data in the buffer initially or the data in the buffer was zero because it was written in to + // MAC PDU + LOG_D(NR_MAC, + "lcid %d - initial data in the buffer(%d) and buffer status (%d)\n", + lcid, + sched_info->lc_sched_info[lcid - 1].LCID_status, + lcids_data_status[lcid - 1]); + if (!sched_info->lc_sched_info[lcid - 1].LCID_status || !lcids_data_status[lcid - 1]) { LOG_D(NR_MAC, - "[UE %d] [%d.%d] UL-DXCH -> ULSCH, Generating UL MAC sub-PDU for SDU %d, length %d bytes, RB with LCID 0x%02x " - "(buflen (TBS) %d bytes)\n", - module_idP, - frameP, - subframe, - num_sdus + 1, - sdu_length, + "skipping the logical channel %d due to no initial data in the buffer(%d) or " + "buffer was emptied completely (%d) because it was written in to MAC PDU (remaining size = %d)\n", lcid, - buflen); - - header->R = 0; - header->F = 1; - header->LCID = lcid; - header->L = htons(sdu_length); - - #ifdef ENABLE_MAC_PAYLOAD_DEBUG - LOG_I(NR_MAC, "In %s: dumping MAC sub-header with length %d: \n", __FUNCTION__, sh_size); - log_dump(NR_MAC, header, sh_size, LOG_DUMP_CHAR, "\n"); - LOG_I(NR_MAC, "In %s: dumping MAC SDU with length %d \n", __FUNCTION__, sdu_length); - log_dump(NR_MAC, pdu, sdu_length, LOG_DUMP_CHAR, "\n"); - #endif - - pdu += sdu_length; - mac_ce_p->sdu_length_total += sdu_length; - mac_ce_p->total_mac_pdu_header_len += sh_size; - - num_sdus++; - - } else { - pdu -= sh_size; - LOG_D(NR_MAC, "no data to transmit for RB with LCID 0x%02x\n", lcid); - break; + sched_info->lc_sched_info[lcid - 1].LCID_status, + lcids_data_status[lcid - 1], + sched_info->lc_sched_info[lcid - 1].LCID_buffer_remain); + lcids_data_status[lcid - 1] = false; + continue; } + // count number of lc with same priority as lcid + if (!num_lcids_same_priority) { + num_lcids_same_priority = count_same_priority_lcids = + get_count_lcids_same_priority(mac, id, avail_lcids_count, lcids_bj_pos); + } + + LOG_D(NR_MAC, "Number of lcids with same priority as that of lcid %d is %d\n", lcid, count_same_priority_lcids); + buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total + sh_size); - //Update Buffer remain and BSR bytes after transmission - mac->scheduling_info.LCID_buffer_remain[lcid - 1] -= sdu_length; - mac->scheduling_info.BSR_bytes[mac->scheduling_info.LCGID[lcid - 1]] -= sdu_length; LOG_D(NR_MAC, - "[UE %d] Update BSR [%d.%d] BSR_bytes for LCG%d=%d\n", + "In %s: [UE %d] [%d.%d] UL-DXCH -> ULSCH, RLC with LCID 0x%02x (TBS %d bytes, sdu_length_total %d bytes, MAC header " + "len %d bytes," + "buflen_remain %d bytes)\n", + __FUNCTION__, module_idP, frameP, subframe, - mac->scheduling_info.LCGID[lcid - 1], - mac->scheduling_info.BSR_bytes[mac->scheduling_info.LCGID[lcid - 1]]); - if (mac->scheduling_info.BSR_bytes[mac->scheduling_info.LCGID[lcid - 1]] < 0) - mac->scheduling_info.BSR_bytes[mac->scheduling_info.LCGID[lcid - 1]] = 0; + lcid, + buflen, + mac_ce_p->sdu_length_total, + mac_ce_p->tot_mac_ce_len, + buflen_remain); + + if (num_lcids_same_priority == count_same_priority_lcids) { + buflen_ep = (buflen_remain - (count_same_priority_lcids * sh_size)) / count_same_priority_lcids; + } + + while (buflen_remain > 0) { + /* + loops until the requested number of bytes from MAC to RLC are placed in the MAC PDU. The number of requested bytes + depends on whether it is the first run or otherwise because in the first run only prioritited number of bytes of all + active logical channels in the order of priority are placed in the MAC PDU. The 'get_num_bytes_to_reqlc' calculates + the target number of bytes to request from RLC via 'mac_rlc_data_req' + */ + int32_t lcid_remain_buffer = sched_info->lc_sched_info[lcid - 1].LCID_buffer_remain; + LOG_D(NR_MAC, + "In %s: [UE %d] [%d.%d] lcp round = %d, remaining mac pdu length = %d, lcid buffer remaining = %d, lcid = %d \n", + __FUNCTION__, + module_idP, + frameP, + subframe, + lcp_allocation_counter, + buflen_remain, + lcid_remain_buffer, + lcid); + + // Pointer used to build the MAC sub-PDU headers in the ULSCH buffer for each SDU + NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *)pdu; + + pdu += sh_size; + + // number of bytes requested from RLC for each LCID + long target = 0; + bytes_requested = get_num_bytes_to_reqlc(mac, + count_same_priority_lcids, + lcid, + buflen_ep, + buflen_remain, + lcp_allocation_counter, + lcids_bytes_tot, + &target); + + LOG_D(NR_MAC, "number of bytes requested for lcid %d is %li\n", lcid, bytes_requested); + sdu_length = mac_rlc_data_req(module_idP, + mac->crnti, + gNB_index, + frameP, + ENB_FLAG_NO, + MBMS_FLAG_NO, + lcid, + bytes_requested, + (char *)pdu, + 0, + 0); + + AssertFatal(bytes_requested >= sdu_length, + "In %s: LCID = 0x%02x RLC has segmented %d bytes but MAC has max %li remaining bytes\n", + __FUNCTION__, + lcid, + sdu_length, + bytes_requested); + + // Decrement Bj by the total size of MAC SDUs(RLC PDU) served to logical channel + // currently the Bj is drecremented by size of MAC SDus everytime it is served to logical channel, so by this approach there + // will be more chance for lower priority logical channels to be served in the next TTI + // second approach can also be followed where Bj is decremented only in the first round but not in the subsequent rounds + sched_info->lc_sched_info[lcid - 1].Bj -= sdu_length; + LOG_D(NR_MAC, + "decrement Bj of the lcid %d by size of sdu length = %d and new Bj for lcid %d is %d\n", + lcid, + sdu_length, + lcid, + sched_info->lc_sched_info[lcid - 1].Bj); + + if (sdu_length > 0) { + LOG_D(NR_MAC, + "In %s: [UE %d] [%d.%d] UL-DXCH -> ULSCH, Generating UL MAC sub-PDU for SDU %d, length %d bytes, RB with LCID " + "0x%02x (buflen (TBS) %d bytes)\n", + __FUNCTION__, + module_idP, + frameP, + subframe, + num_sdus + 1, + sdu_length, + lcid, + buflen); + + header->R = 0; + header->F = 1; + header->LCID = lcid; + header->L = htons(sdu_length); + +#ifdef ENABLE_MAC_PAYLOAD_DEBUG + LOG_I(NR_MAC, "In %s: dumping MAC sub-header with length %d: \n", __FUNCTION__, sh_size); + log_dump(NR_MAC, header, sh_size, LOG_DUMP_CHAR, "\n"); + LOG_I(NR_MAC, "In %s: dumping MAC SDU with length %d \n", __FUNCTION__, sdu_length); + log_dump(NR_MAC, pdu, sdu_length, LOG_DUMP_CHAR, "\n"); +#endif + + pdu += sdu_length; + mac_ce_p->sdu_length_total += sdu_length; + mac_ce_p->total_mac_pdu_header_len += sh_size; + + num_sdus++; + } else { + pdu -= sh_size; + lcids_data_status[lcid - 1] = false; + num_lcids_same_priority--; + LOG_D(NR_MAC, "set the lcid %d to false\n", lcid); + LOG_D(NR_MAC, "In %s: no data to transmit for RB with LCID 0x%02x\n", __FUNCTION__, lcid); + break; + } + + buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total + sh_size); + + // Update Buffer remain and BSR bytes after transmission + NR_LC_SCHEDULING_INFO *lc_info = &sched_info->lc_sched_info[0]; + NR_LCG_SCHEDULING_INFO *lcg_info = &sched_info->lcg_sched_info[0]; + (lc_info + lcid - 1)->LCID_buffer_remain -= sdu_length; + (lcg_info + (lc_info + lcid - 1)->LCGID)->BSR_bytes -= sdu_length; + LOG_D(NR_MAC, + "[UE %d] Update BSR [%d.%d] BSR_bytes for LCG%d = %d\n", + module_idP, + frameP, + subframe, + (lc_info + lcid - 1)->LCGID, + (lcg_info + (lc_info + lcid - 1)->LCGID)->BSR_bytes); + if ((lcg_info + (lc_info + lcid - 1)->LCGID)->BSR_bytes < 0) + (lcg_info + (lc_info + lcid - 1)->LCGID)->BSR_bytes = 0; + + // update number of bytes served from the current lcid + lcids_bytes_tot[lcid - 1] += (sdu_length + (count_same_priority_lcids > 1 ? 1 : 0) * sh_size); + + if ((lcp_allocation_counter == 0 && lcids_bytes_tot[lcid - 1] >= target) + || (count_same_priority_lcids > 1 + && lcids_bytes_tot[lcid - 1] >= buflen_ep)) { // only prioritized bit rate should be taken from logical channel in + // the first lcp run except when infinity + LOG_D(NR_MAC, + "In %s: total number bytes read from rlc buffer for lcid %d are %d\n", + __FUNCTION__, + lcid, + lcids_bytes_tot[lcid - 1]); + num_lcids_same_priority--; + break; + } + } } - } + + lcp_allocation_counter++; + } while (buflen_remain > 0 && get_dataavailability_buffers(avail_lcids_count, lcids_bj_pos, lcids_data_status)); //nr_ue_get_sdu_mac_ce_post recalculates all mac_ce related header fields since buffer has been changed after mac_rlc_data_req. //Also, BSR padding is handled here after knowing mac_ce_p->sdu_length_total. @@ -3061,3 +3337,106 @@ void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UL_TIME_ALIG dl_config->number_pdus += 1; ul_time_alignment->ta_apply = false; } + +uint16_t nr_get_ms_bucketsizeduration(uint8_t bucketsizeduration) +{ + switch (bucketsizeduration) { + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50: + return 50; + + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms100: + return 100; + + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms150: + return 150; + + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms300: + return 300; + + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms500: + return 500; + + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms1000: + return 1000; + + default: + return 0; + } +} + +uint32_t nr_get_pbr(uint8_t prioritizedbitrate) +{ + int32_t pbr = -1; + switch (prioritizedbitrate) { + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps0: + pbr = 0; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8: + pbr = 8; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps16: + pbr = 16; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps32: + pbr = 32; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps64: + pbr = 64; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps128: + pbr = 128; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps256: + pbr = 256; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps512: + pbr = 512; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps1024: + pbr = 1024; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps2048: + pbr = 2048; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps4096: + pbr = 4096; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8192: + pbr = 8192; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps16384: + pbr = 16384; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps32768: + pbr = 32768; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps65536: + pbr = 65536; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity: + pbr = INT32_MAX; + break; + + default: + pbr = -1; + } + AssertFatal(pbr >= 0, "The proritized bit rate value is not one of the enum values\n"); + uint32_t pbr_bytes = + (prioritizedbitrate < NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity) ? pbr * 1000 : pbr; + return pbr_bytes; +} From e5ab3e022eb2ff650322b62b85e8386f382e106a Mon Sep 17 00:00:00 2001 From: sriharsha Date: Mon, 9 Oct 2023 11:04:58 +0200 Subject: [PATCH 2/5] Handling of mac-LogicalChannelConfig during reconfiguration --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 42 ++++++++++++++++++--------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index adca3def49..612eb03271 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -612,24 +612,38 @@ void nr_rrc_mac_config_req_ue_logicalChannelBearer(module_id_t module_id, int lc_identity = rlc_bearer->logicalChannelIdentity; mac->lc_ordered_info.lcids_ordered[i] = lc_identity; NR_LogicalChannelConfig_t *mac_lc_config; - if (rlc_bearer->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity) { /* SRB */ - NR_SRB_Identity_t srb_id = rlc_bearer->servedRadioBearer->choice.srb_Identity; + if (mac->logicalChannelConfig[lc_identity - 1] == NULL) { + /* setup of new LCID*/ + LOG_D(NR_MAC, "Establishing the logical channel %d\n", lc_identity); + AssertFatal(rlc_bearer->servedRadioBearer, "servedRadioBearer should be present for LCID establishment\n"); + if (rlc_bearer->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity) { /* SRB */ + NR_SRB_Identity_t srb_id = rlc_bearer->servedRadioBearer->choice.srb_Identity; + if (rlc_bearer->mac_LogicalChannelConfig != NULL) { + mac_lc_config = rlc_bearer->mac_LogicalChannelConfig; + } else { + LOG_I(NR_RRC, "Applying the default logicalChannelConfig for SRB\n"); + if (srb_id == 1) + mac_lc_config = (NR_LogicalChannelConfig_t *)&NR_SRB1_logicalChannelConfig_defaultValue; + else if (srb_id == 2) + mac_lc_config = (NR_LogicalChannelConfig_t *)&NR_SRB2_logicalChannelConfig_defaultValue; + else if (srb_id == 3) + mac_lc_config = (NR_LogicalChannelConfig_t *)&NR_SRB3_logicalChannelConfig_defaultValue; + else + AssertFatal(1 == 0, "The logical id %d is not a valid SRB id %li\n", lc_identity, srb_id); + } + } else { /* DRB */ + mac_lc_config = rlc_bearer->mac_LogicalChannelConfig; + AssertFatal(mac_lc_config != NULL, "For DRB, it should be mandatorily present\n"); + } + } else { + /* LC is already established, reconfiguring the LC */ + LOG_D(NR_MAC, "Logical channel %d is already established, Reconfiguring now\n", lc_identity); if (rlc_bearer->mac_LogicalChannelConfig != NULL) { mac_lc_config = rlc_bearer->mac_LogicalChannelConfig; } else { - LOG_I(NR_RRC, "Applying the default logicalChannelConfig for SRB\n"); - if (srb_id == 1) - mac_lc_config = (NR_LogicalChannelConfig_t *)&NR_SRB1_logicalChannelConfig_defaultValue; - else if (srb_id == 2) - mac_lc_config = (NR_LogicalChannelConfig_t *)&NR_SRB2_logicalChannelConfig_defaultValue; - else if (srb_id == 3) - mac_lc_config = (NR_LogicalChannelConfig_t *)&NR_SRB3_logicalChannelConfig_defaultValue; - else - AssertFatal(1 == 0, "The logical id %d is not a valid SRB id %li\n", lc_identity, srb_id); + /* Need M - Maintains current value */ + continue; } - } else { /* DRB */ - mac_lc_config = rlc_bearer->mac_LogicalChannelConfig; - AssertFatal(mac_lc_config != NULL, "For DRB, it should be mandatorily present\n"); } nr_configure_mac_config_logicalChannelBearer(module_id, lc_identity, mac_lc_config); } From f248b2fdff1eccc703676accbc1f548751fd00ed Mon Sep 17 00:00:00 2001 From: sriharsha Date: Tue, 10 Oct 2023 17:21:55 +0200 Subject: [PATCH 3/5] fix: avoid freeing rlc config structure --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 2 +- openair2/LAYER2/NR_MAC_UE/main_ue_nr.c | 2 +- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 6 +++--- openair2/RRC/NR/MESSAGES/asn1_msg.c | 6 ++++-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 612eb03271..a5bedece5f 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -649,7 +649,7 @@ void nr_rrc_mac_config_req_ue_logicalChannelBearer(module_id_t module_id, } // reorder the logical channels as per its priority - qsort_r((void *)mac->lc_ordered_info.lcids_ordered, rlc_toadd_list->list.count, sizeof(uint32_t), lcid_cmp, (void *)mac); + qsort_r(mac->lc_ordered_info.lcids_ordered, rlc_toadd_list->list.count, sizeof(uint32_t), lcid_cmp, mac); for (uint8_t i = 0; i < rlc_toadd_list->list.count; i++) { mac->lc_ordered_info.logicalChannelConfig_ordered[i] = mac->logicalChannelConfig[mac->lc_ordered_info.lcids_ordered[i] - 1]; } diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index 77c6fd6c8d..5ec205adaf 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -106,7 +106,7 @@ NR_UE_MAC_INST_t * nr_l2_init_ue(NR_UE_RRC_INST_t* rrc_inst) { nr_rrc_mac_config_req_ue_logicalChannelBearer(0, &rlc_toadd_list, NULL); // free memory - free_nr_noS1_bearer_config(&rbconfig, &rlc_rbconfig); + free_nr_noS1_bearer_config(&rbconfig, NULL); } } else { diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 5f7728eb3a..fc26b1e860 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -3072,9 +3072,9 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP, for (uint8_t id = 0; id < avail_lcids_count; id++) { /* - loop over all logical channels in the order of priority. As stated in ts spec, in the first run, only prioritized - number of bytes are taken out from the correspondinf RLC buffers of all active logical channels and if there is still - space availble in the MAC PDU, then from the next run all the remaining data from the higher priority logical channel + loop over all logical channels in the order of priority. As stated in TS138.321 Section 5.4.3.1, in the first run, only + prioritized number of bytes are taken out from the corresponding RLC buffers of all active logical channels and if there is + still space availble in the MAC PDU, then from the next run all the remaining data from the higher priority logical channel is placed in the MAC PDU before going on to next high priority logical channel */ int lcid = lcids_bj_pos[id]; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index c6115c555d..f5e060e251 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -460,8 +460,10 @@ void free_nr_noS1_bearer_config(NR_RadioBearerConfig_t **rbconfig, { ASN_STRUCT_FREE(asn_DEF_NR_RadioBearerConfig, *rbconfig); *rbconfig = NULL; - ASN_STRUCT_FREE(asn_DEF_NR_RLC_BearerConfig, *rlc_rbconfig); - *rlc_rbconfig = NULL; + if (rlc_rbconfig != NULL) { + ASN_STRUCT_FREE(asn_DEF_NR_RLC_BearerConfig, *rlc_rbconfig); + *rlc_rbconfig = NULL; + } } //------------------------------------------------------------------------------ From b0b8c90fd257ada6c4ba601a81217d2124d25158 Mon Sep 17 00:00:00 2001 From: Sriharsha Korada Date: Thu, 12 Oct 2023 15:17:11 +0200 Subject: [PATCH 4/5] clean up --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 40 ++- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 6 +- openair2/LAYER2/NR_MAC_UE/mac_proto.h | 7 - openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 374 +++++++++----------- 4 files changed, 211 insertions(+), 216 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index a5bedece5f..92f897433d 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -539,10 +539,10 @@ void configure_ss_coreset(NR_UE_MAC_INST_t *mac, mac->BWP_coresets[i] = NULL; } -static int lcid_cmp(const void *lcid1, const void *lcid2, void *mac_inst) +static int lcid_cmp(const void *lc1, const void *lc2, void *mac_inst) { - uint8_t id1 = *(uint8_t *)lcid1; - uint8_t id2 = *(uint8_t *)lcid2; + uint8_t id1 = ((nr_lcordered_info_t *)lc1)->lcids_ordered; + uint8_t id2 = ((nr_lcordered_info_t *)lc2)->lcids_ordered; NR_UE_MAC_INST_t *mac = (NR_UE_MAC_INST_t *)mac_inst; NR_LogicalChannelConfig_t **lc_config = &mac->logicalChannelConfig[0]; @@ -564,6 +564,32 @@ void nr_release_mac_config_logicalChannelBearer(module_id_t module_id, long chan } } +static uint16_t nr_get_ms_bucketsizeduration(uint8_t bucketsizeduration) +{ + switch (bucketsizeduration) { + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50: + return 50; + + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms100: + return 100; + + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms150: + return 150; + + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms300: + return 300; + + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms500: + return 500; + + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms1000: + return 1000; + + default: + return 0; + } +} + void nr_configure_mac_config_logicalChannelBearer(module_id_t module_id, long channel_identity, NR_LogicalChannelConfig_t *lc_config) @@ -610,7 +636,7 @@ void nr_rrc_mac_config_req_ue_logicalChannelBearer(module_id_t module_id, for (int i = 0; i < rlc_toadd_list->list.count; i++) { NR_RLC_BearerConfig_t *rlc_bearer = rlc_toadd_list->list.array[i]; int lc_identity = rlc_bearer->logicalChannelIdentity; - mac->lc_ordered_info.lcids_ordered[i] = lc_identity; + mac->lc_ordered_info[i].lcids_ordered = lc_identity; NR_LogicalChannelConfig_t *mac_lc_config; if (mac->logicalChannelConfig[lc_identity - 1] == NULL) { /* setup of new LCID*/ @@ -645,14 +671,12 @@ void nr_rrc_mac_config_req_ue_logicalChannelBearer(module_id_t module_id, continue; } } + mac->lc_ordered_info[i].logicalChannelConfig_ordered = mac_lc_config; nr_configure_mac_config_logicalChannelBearer(module_id, lc_identity, mac_lc_config); } // reorder the logical channels as per its priority - qsort_r(mac->lc_ordered_info.lcids_ordered, rlc_toadd_list->list.count, sizeof(uint32_t), lcid_cmp, mac); - for (uint8_t i = 0; i < rlc_toadd_list->list.count; i++) { - mac->lc_ordered_info.logicalChannelConfig_ordered[i] = mac->logicalChannelConfig[mac->lc_ordered_info.lcids_ordered[i] - 1]; - } + qsort_r(mac->lc_ordered_info, rlc_toadd_list->list.count, sizeof(nr_lcordered_info_t), lcid_cmp, mac); } } diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index fe94212f73..74d6056908 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -435,10 +435,10 @@ typedef struct ssb_list_info { typedef struct nr_lcordered_info_s { // logical channels ids ordered as per priority - int lcids_ordered[NR_MAX_NUM_LCID]; + int lcids_ordered; // logical channel configurations reordered as per priority - NR_LogicalChannelConfig_t *logicalChannelConfig_ordered[NR_MAX_NUM_LCID]; + NR_LogicalChannelConfig_t *logicalChannelConfig_ordered; } nr_lcordered_info_t; /*!\brief Top level UE MAC structure */ @@ -529,7 +529,7 @@ typedef struct { NR_LogicalChannelConfig_t *logicalChannelConfig[NR_MAX_NUM_LCID]; // order lc info - nr_lcordered_info_t lc_ordered_info; + nr_lcordered_info_t lc_ordered_info[NR_MAX_NUM_LCID]; NR_UE_SCHEDULING_INFO scheduling_info; /// PHR diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 9269b1c5e8..e60a05e9f0 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -155,13 +155,6 @@ uint8_t nr_locate_BsrIndexByBufferSize(const uint32_t *table, int size, */ uint32_t nr_get_pbr(uint8_t prioritizedbitrate); -/*! \fn int nr_get_ms_bucketsizeduration(uint8_t bucketSizeduration) - \brief get the time in ms from the bucket size duration configured by the higher layer -\param[in] bucketSize the bucket size duration -\return the time in ms -*/ -uint16_t nr_get_ms_bucketsizeduration(uint8_t bucketsizeduration); - /*! \fn int nr_get_sf_periodicBSRTimer(uint8_t periodicBSR_Timer) \brief get the number of subframe from the periodic BSR timer configured by the higher layers \param[in] periodicBSR_Timer timer for periodic BSR diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index fc26b1e860..34be53c672 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -1097,12 +1097,8 @@ void nr_ue_ul_scheduler(nr_uplink_indication_t *ul_info) // update Bj for all active lcids before LCP procedure LOG_D(NR_MAC, "====================[Frame %d][Slot %d]Logical Channel Prioritization===========\n", frame_tx, slot_tx); - NR_LogicalChannelConfig_t **lc_bearer; - int *lcid_ptr; - for (lcid_ptr = mac->lc_ordered_info.lcids_ordered, lc_bearer = mac->lc_ordered_info.logicalChannelConfig_ordered; - (*lcid_ptr <= NR_MAX_NUM_LCID) && (*lc_bearer != NULL); - lcid_ptr++, lc_bearer++) { - int lcid = *lcid_ptr; + for (nr_lcordered_info_t *lc_bearer = mac->lc_ordered_info; lc_bearer->logicalChannelConfig_ordered != NULL; lc_bearer++) { + int lcid = lc_bearer->lcids_ordered; NR_LogicalChannelConfig_t *lcconfig = mac->logicalChannelConfig[lcid - 1]; NR_LC_SCHEDULING_INFO *sched_lc = &mac->scheduling_info.lc_sched_info[lcid - 1]; int32_t bucketSize_max = @@ -2905,6 +2901,7 @@ uint32_t get_count_lcids_same_priority(NR_UE_MAC_INST_t *mac, uint8_t start, uin same_priority_count++; } } + LOG_D(NR_MAC, "Number of lcids with same priority as that of lcid %d is %d\n", curr_lcid, same_priority_count); return same_priority_count; } @@ -2940,6 +2937,7 @@ long get_num_bytes_to_reqlc(NR_UE_MAC_INST_t *mac, } } AssertFatal(num_remaining_bytes >= 0, "the total number of bytes allocated until target length is greater than expected\n"); + LOG_D(NR_MAC, "number of bytes requested for lcid %d is %li\n", lc_num, num_bytes_requested); return num_bytes_requested; } @@ -2962,22 +2960,165 @@ uint8_t select_logical_channels(NR_UE_MAC_INST_t *mac, uint8_t *num_active_lcids // channels, TS38.321) // selection of logical channels with Bj > 0 - - NR_LogicalChannelConfig_t **lc_bearer; - int *lcid_ptr; - for (lcid_ptr = mac->lc_ordered_info.lcids_ordered, lc_bearer = mac->lc_ordered_info.logicalChannelConfig_ordered; - (*lcid_ptr < NR_MAX_NUM_LCID) && (*lc_bearer != NULL); - lcid_ptr++, lc_bearer++) { - uint8_t lcid = *lcid_ptr; + for (nr_lcordered_info_t *lc_bearer = mac->lc_ordered_info; lc_bearer->logicalChannelConfig_ordered != NULL; lc_bearer++) { + uint8_t lcid = lc_bearer->lcids_ordered; if (mac->scheduling_info.lc_sched_info[lcid - 1].Bj > 0) { active_lcids[*num_active_lcids] = lcid; - LOG_D(NR_MAC, "The available lcid is %d\n", active_lcids[*num_active_lcids]); (*num_active_lcids)++; + LOG_D(NR_MAC, "The available lcid is %d with total active channels count = %d\n", lcid, *num_active_lcids); } } return 0; } +static bool fill_mac_sdu(module_id_t module_idP, + frame_t frameP, + sub_frame_t subframe, + uint8_t gNB_index, + uint16_t buflen, + int16_t *buflen_remain, + int lcid, + uint8_t **pdu, + uint32_t *counter, + uint8_t count_same_priority_lcids, + uint16_t buflen_ep, + uint32_t *lcids_bytes_tot, + uint16_t *num_sdus, + NR_UE_MAC_CE_INFO *mac_ce_p, + bool *lcids_data_status, + uint8_t *num_lcids_same_priority) +{ + NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP); + NR_UE_SCHEDULING_INFO *sched_info = &mac->scheduling_info; + const uint8_t sh_size = sizeof(NR_MAC_SUBHEADER_LONG); + + /* prepare the MAC sdu */ + int32_t lcid_remain_buffer = sched_info->lc_sched_info[lcid - 1].LCID_buffer_remain; + LOG_D(NR_MAC, + "In %s: [UE %d] [%d.%d] lcp round = %d, remaining mac pdu length = %d, lcid buffer remaining = %d, lcid = %d \n", + __FUNCTION__, + module_idP, + frameP, + subframe, + *counter, + *buflen_remain, + lcid_remain_buffer, + lcid); + + // Pointer used to build the MAC sub-PDU headers in the ULSCH buffer for each SDU + NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *)(*pdu); + + *pdu += sh_size; + + // number of bytes requested from RLC for each LCID + long target = 0; + long bytes_requested = + get_num_bytes_to_reqlc(mac, count_same_priority_lcids, lcid, buflen_ep, *buflen_remain, *counter, lcids_bytes_tot, &target); + + uint16_t sdu_length = mac_rlc_data_req(module_idP, + mac->crnti, + gNB_index, + frameP, + ENB_FLAG_NO, + MBMS_FLAG_NO, + lcid, + bytes_requested, + (char *)(*pdu), + 0, + 0); + + AssertFatal(bytes_requested >= sdu_length, + "In %s: LCID = 0x%02x RLC has segmented %d bytes but MAC has max %li remaining bytes\n", + __FUNCTION__, + lcid, + sdu_length, + bytes_requested); + + // Decrement Bj by the total size of MAC SDUs(RLC PDU) served to logical channel + // currently the Bj is drecremented by size of MAC SDus everytime it is served to logical channel, so by this approach there + // will be more chance for lower priority logical channels to be served in the next TTI + // second approach can also be followed where Bj is decremented only in the first round but not in the subsequent rounds + sched_info->lc_sched_info[lcid - 1].Bj -= sdu_length; + LOG_D(NR_MAC, + "decrement Bj of the lcid %d by size of sdu length = %d and new Bj for lcid %d is %d\n", + lcid, + sdu_length, + lcid, + sched_info->lc_sched_info[lcid - 1].Bj); + + if (sdu_length > 0) { + LOG_D(NR_MAC, + "In %s: [UE %d] [%d.%d] UL-DXCH -> ULSCH, Generating UL MAC sub-PDU for SDU %d, length %d bytes, RB with LCID " + "0x%02x (buflen (TBS) %d bytes)\n", + __FUNCTION__, + module_idP, + frameP, + subframe, + (*num_sdus) + 1, + sdu_length, + lcid, + buflen); + + header->R = 0; + header->F = 1; + header->LCID = lcid; + header->L = htons(sdu_length); + +#ifdef ENABLE_MAC_PAYLOAD_DEBUG + LOG_I(NR_MAC, "In %s: dumping MAC sub-header with length %d: \n", __FUNCTION__, sh_size); + log_dump(NR_MAC, header, sh_size, LOG_DUMP_CHAR, "\n"); + LOG_I(NR_MAC, "In %s: dumping MAC SDU with length %d \n", __FUNCTION__, sdu_length); + log_dump(NR_MAC, *pdu, sdu_length, LOG_DUMP_CHAR, "\n"); +#endif + + *pdu += sdu_length; + mac_ce_p->sdu_length_total += sdu_length; + mac_ce_p->total_mac_pdu_header_len += sh_size; + + (*num_sdus)++; + } else { + *pdu -= sh_size; + lcids_data_status[lcid - 1] = false; + (*num_lcids_same_priority)--; + LOG_D(NR_MAC, "In %s: no data to transmit for RB with LCID 0x%02x\n and hence set to false", __FUNCTION__, lcid); + return 0; + } + + *buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total + sh_size); + + // Update Buffer remain and BSR bytes after transmission + NR_LC_SCHEDULING_INFO *lc_info = &sched_info->lc_sched_info[0] + lcid - 1; + NR_LCG_SCHEDULING_INFO *lcg_info = &sched_info->lcg_sched_info[0]; + lc_info->LCID_buffer_remain -= sdu_length; + (lcg_info + lc_info->LCGID)->BSR_bytes -= sdu_length; + LOG_D(NR_MAC, + "[UE %d] Update BSR [%d.%d] BSR_bytes for LCG%d = %d\n", + module_idP, + frameP, + subframe, + lc_info->LCGID, + (lcg_info + lc_info->LCGID)->BSR_bytes); + if ((lcg_info + lc_info->LCGID)->BSR_bytes < 0) + (lcg_info + lc_info->LCGID)->BSR_bytes = 0; + + // update number of bytes served from the current lcid + lcids_bytes_tot[lcid - 1] += (sdu_length + (count_same_priority_lcids > 1 ? 1 : 0) * sh_size); + + if ((*counter == 0 && lcids_bytes_tot[lcid - 1] >= target) + || (count_same_priority_lcids > 1 + && lcids_bytes_tot[lcid - 1] >= buflen_ep)) { // only prioritized bit rate should be taken from logical channel in + // the first lcp run except when infinity + LOG_D(NR_MAC, + "In %s: total number bytes read from rlc buffer for lcid %d are %d\n", + __FUNCTION__, + lcid, + lcids_bytes_tot[lcid - 1]); + (*num_lcids_same_priority)--; + return 0; + } + return 1; +} + /** * Function: to fetch data to be transmitted from RLC, place it in the ULSCH PDU buffer to generate the complete MAC PDU with sub-headers and MAC CEs according to ULSCH MAC PDU generation (6.1.2 TS 38.321) @@ -3008,7 +3149,6 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP, //mac_ce_p->phr_ce_len = 0; //mac_ce_p->phr_header_len = 0; - uint16_t sdu_length = 0; uint16_t num_sdus = 0; mac_ce_p->sdu_length_total = 0; NR_BSR_SHORT bsr_short, bsr_truncated; @@ -3035,8 +3175,6 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP, bool lcids_data_status[NR_MAX_NUM_LCID] = {0}; memset(lcids_data_status, 1, NR_MAX_NUM_LCID); - long bytes_requested = 0; - uint32_t lcp_allocation_counter = 0; // in the first run all the lc are allocated as per bj and prioritized bit rate but in subsequent runs, no need to consider // bj and prioritized bit rate but just consider priority @@ -3051,13 +3189,6 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP, // selection of logical channels select_logical_channels(mac, &avail_lcids_count, lcids_bj_pos); - LOG_D(NR_MAC, - "In %s: [UE %d] [%d.%d] number of active logical channels are %d \n", - __FUNCTION__, - module_idP, - frameP, - subframe, - avail_lcids_count); // multiplex in the order of highest priority do { @@ -3081,19 +3212,7 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP, // skip the logical channel if no data in the buffer initially or the data in the buffer was zero because it was written in to // MAC PDU - LOG_D(NR_MAC, - "lcid %d - initial data in the buffer(%d) and buffer status (%d)\n", - lcid, - sched_info->lc_sched_info[lcid - 1].LCID_status, - lcids_data_status[lcid - 1]); if (!sched_info->lc_sched_info[lcid - 1].LCID_status || !lcids_data_status[lcid - 1]) { - LOG_D(NR_MAC, - "skipping the logical channel %d due to no initial data in the buffer(%d) or " - "buffer was emptied completely (%d) because it was written in to MAC PDU (remaining size = %d)\n", - lcid, - sched_info->lc_sched_info[lcid - 1].LCID_status, - lcids_data_status[lcid - 1], - sched_info->lc_sched_info[lcid - 1].LCID_buffer_remain); lcids_data_status[lcid - 1] = false; continue; } @@ -3104,8 +3223,6 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP, get_count_lcids_same_priority(mac, id, avail_lcids_count, lcids_bj_pos); } - LOG_D(NR_MAC, "Number of lcids with same priority as that of lcid %d is %d\n", lcid, count_same_priority_lcids); - buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total + sh_size); LOG_D(NR_MAC, @@ -3128,140 +3245,27 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP, while (buflen_remain > 0) { /* - loops until the requested number of bytes from MAC to RLC are placed in the MAC PDU. The number of requested bytes - depends on whether it is the first run or otherwise because in the first run only prioritited number of bytes of all - active logical channels in the order of priority are placed in the MAC PDU. The 'get_num_bytes_to_reqlc' calculates - the target number of bytes to request from RLC via 'mac_rlc_data_req' - */ - int32_t lcid_remain_buffer = sched_info->lc_sched_info[lcid - 1].LCID_buffer_remain; - LOG_D(NR_MAC, - "In %s: [UE %d] [%d.%d] lcp round = %d, remaining mac pdu length = %d, lcid buffer remaining = %d, lcid = %d \n", - __FUNCTION__, - module_idP, - frameP, - subframe, - lcp_allocation_counter, - buflen_remain, - lcid_remain_buffer, - lcid); - - // Pointer used to build the MAC sub-PDU headers in the ULSCH buffer for each SDU - NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *)pdu; - - pdu += sh_size; - - // number of bytes requested from RLC for each LCID - long target = 0; - bytes_requested = get_num_bytes_to_reqlc(mac, - count_same_priority_lcids, - lcid, - buflen_ep, - buflen_remain, - lcp_allocation_counter, - lcids_bytes_tot, - &target); - - LOG_D(NR_MAC, "number of bytes requested for lcid %d is %li\n", lcid, bytes_requested); - sdu_length = mac_rlc_data_req(module_idP, - mac->crnti, - gNB_index, - frameP, - ENB_FLAG_NO, - MBMS_FLAG_NO, - lcid, - bytes_requested, - (char *)pdu, - 0, - 0); - - AssertFatal(bytes_requested >= sdu_length, - "In %s: LCID = 0x%02x RLC has segmented %d bytes but MAC has max %li remaining bytes\n", - __FUNCTION__, - lcid, - sdu_length, - bytes_requested); - - // Decrement Bj by the total size of MAC SDUs(RLC PDU) served to logical channel - // currently the Bj is drecremented by size of MAC SDus everytime it is served to logical channel, so by this approach there - // will be more chance for lower priority logical channels to be served in the next TTI - // second approach can also be followed where Bj is decremented only in the first round but not in the subsequent rounds - sched_info->lc_sched_info[lcid - 1].Bj -= sdu_length; - LOG_D(NR_MAC, - "decrement Bj of the lcid %d by size of sdu length = %d and new Bj for lcid %d is %d\n", - lcid, - sdu_length, - lcid, - sched_info->lc_sched_info[lcid - 1].Bj); - - if (sdu_length > 0) { - LOG_D(NR_MAC, - "In %s: [UE %d] [%d.%d] UL-DXCH -> ULSCH, Generating UL MAC sub-PDU for SDU %d, length %d bytes, RB with LCID " - "0x%02x (buflen (TBS) %d bytes)\n", - __FUNCTION__, - module_idP, - frameP, - subframe, - num_sdus + 1, - sdu_length, - lcid, - buflen); - - header->R = 0; - header->F = 1; - header->LCID = lcid; - header->L = htons(sdu_length); - -#ifdef ENABLE_MAC_PAYLOAD_DEBUG - LOG_I(NR_MAC, "In %s: dumping MAC sub-header with length %d: \n", __FUNCTION__, sh_size); - log_dump(NR_MAC, header, sh_size, LOG_DUMP_CHAR, "\n"); - LOG_I(NR_MAC, "In %s: dumping MAC SDU with length %d \n", __FUNCTION__, sdu_length); - log_dump(NR_MAC, pdu, sdu_length, LOG_DUMP_CHAR, "\n"); -#endif - - pdu += sdu_length; - mac_ce_p->sdu_length_total += sdu_length; - mac_ce_p->total_mac_pdu_header_len += sh_size; - - num_sdus++; - } else { - pdu -= sh_size; - lcids_data_status[lcid - 1] = false; - num_lcids_same_priority--; - LOG_D(NR_MAC, "set the lcid %d to false\n", lcid); - LOG_D(NR_MAC, "In %s: no data to transmit for RB with LCID 0x%02x\n", __FUNCTION__, lcid); - break; - } - - buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total + sh_size); - - // Update Buffer remain and BSR bytes after transmission - NR_LC_SCHEDULING_INFO *lc_info = &sched_info->lc_sched_info[0]; - NR_LCG_SCHEDULING_INFO *lcg_info = &sched_info->lcg_sched_info[0]; - (lc_info + lcid - 1)->LCID_buffer_remain -= sdu_length; - (lcg_info + (lc_info + lcid - 1)->LCGID)->BSR_bytes -= sdu_length; - LOG_D(NR_MAC, - "[UE %d] Update BSR [%d.%d] BSR_bytes for LCG%d = %d\n", - module_idP, - frameP, - subframe, - (lc_info + lcid - 1)->LCGID, - (lcg_info + (lc_info + lcid - 1)->LCGID)->BSR_bytes); - if ((lcg_info + (lc_info + lcid - 1)->LCGID)->BSR_bytes < 0) - (lcg_info + (lc_info + lcid - 1)->LCGID)->BSR_bytes = 0; - - // update number of bytes served from the current lcid - lcids_bytes_tot[lcid - 1] += (sdu_length + (count_same_priority_lcids > 1 ? 1 : 0) * sh_size); - - if ((lcp_allocation_counter == 0 && lcids_bytes_tot[lcid - 1] >= target) - || (count_same_priority_lcids > 1 - && lcids_bytes_tot[lcid - 1] >= buflen_ep)) { // only prioritized bit rate should be taken from logical channel in - // the first lcp run except when infinity - LOG_D(NR_MAC, - "In %s: total number bytes read from rlc buffer for lcid %d are %d\n", - __FUNCTION__, - lcid, - lcids_bytes_tot[lcid - 1]); - num_lcids_same_priority--; + loops until the requested number of bytes from MAC to RLC are placed in the MAC PDU. The number of requested bytes + depends on whether it is the first run or otherwise because in the first run only prioritited number of bytes of all + active logical channels in the order of priority are placed in the MAC PDU. The 'get_num_bytes_to_reqlc' calculates + the target number of bytes to request from RLC via 'mac_rlc_data_req' + */ + if (!fill_mac_sdu(module_idP, + frameP, + subframe, + gNB_index, + buflen, + &buflen_remain, + lcid, + &pdu, + &lcp_allocation_counter, + count_same_priority_lcids, + buflen_ep, + lcids_bytes_tot, + &num_sdus, + mac_ce_p, + lcids_data_status, + &num_lcids_same_priority)) { break; } } @@ -3338,32 +3342,6 @@ void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UL_TIME_ALIG ul_time_alignment->ta_apply = false; } -uint16_t nr_get_ms_bucketsizeduration(uint8_t bucketsizeduration) -{ - switch (bucketsizeduration) { - case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50: - return 50; - - case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms100: - return 100; - - case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms150: - return 150; - - case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms300: - return 300; - - case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms500: - return 500; - - case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms1000: - return 1000; - - default: - return 0; - } -} - uint32_t nr_get_pbr(uint8_t prioritizedbitrate) { int32_t pbr = -1; From 31a63bc919a74bef3ef7baa58b355890267fcfb2 Mon Sep 17 00:00:00 2001 From: Sriharsha Korada Date: Thu, 16 Nov 2023 09:20:14 +0100 Subject: [PATCH 5/5] Update UE feature set --- doc/FEATURE_SET.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md index 55596ea556..831561e025 100644 --- a/doc/FEATURE_SET.md +++ b/doc/FEATURE_SET.md @@ -305,6 +305,7 @@ Furthermore, the gNB and UE support - HARQ procedures * ULSCH scheduler - Configuration of fapi PDU according to DCI + - Logical channel prioritization of 'data from any logical channel' * NR-CSIRS scheduler - Scheduling of NR-CSIRS reception - Fill UCI for CSI measurement reporting