diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index 0e44a7f8bd6f184923f7798791b933422768fc7f..c1d3ba7ce63bcf8bbff80fab466cfbb3f75ace63 100644 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -556,6 +556,14 @@ typedef struct eNB_proc_t_s { te_params tep; /// set of scheduling variables RXn-TXnp4 threads eNB_rxtx_proc_t proc_rxtx[2]; +#if defined(UE_EXPANSION) || defined(UE_EXPANSION_SIM2) + pthread_t pthread_pre_scd; + /// condition variable for time processing thread + pthread_cond_t cond_pre_scd; + /// mutex for time thread + pthread_mutex_t mutex_pre_scd; + int instance_pre_scd; +#endif } eNB_proc_t; diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 6122b9a50bf2e6cc18dffdadeb275065b78bc6fe..62da6dbacdf7cb586eda1c09bc46c923c50f7878 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -629,7 +629,9 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, { int mbsfn_status[MAX_NUM_CCs]; +#if defined(UE_EXPANSION) || defined(UE_EXPANSION_SIM2) protocol_ctxt_t ctxt; +#endif int CC_id, i; //,next_i; UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; @@ -704,6 +706,7 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, } +#if defined(UE_EXPANSION) || defined(UE_EXPANSION_SIM2) PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frameP, subframeP, module_idP); @@ -711,6 +714,7 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, rrc_rx_tx(&ctxt, 0, // eNB index, unused in eNB CC_id); +#endif #if defined(Rel10) || defined(Rel14) diff --git a/openair2/LAYER2/MAC/extern.h b/openair2/LAYER2/MAC/extern.h index 58c801e8dd785b0f72aaaf5ba05e0d415a9bd190..9f29af5b9bae85ef5e32bd1a4973605848f95d6a 100644 --- a/openair2/LAYER2/MAC/extern.h +++ b/openair2/LAYER2/MAC/extern.h @@ -107,4 +107,16 @@ extern int last_dlsch_ue_id[MAX_NUM_CCs]; extern int last_ulsch_ue_id[MAX_NUM_CCs]; #endif +#if defined(UE_EXPANSION) || defined(UE_EXPANSION_SIM2) +extern uint16_t pre_nb_rbs_required[2][MAX_NUM_CCs][NUMBER_OF_UE_MAX]; +extern uint8_t dlsch_ue_select_tbl_in_use; +extern uint8_t new_dlsch_ue_select_tbl_in_use; +extern boolean_t pre_scd_activeUE[NUMBER_OF_UE_MAX]; +extern eNB_UE_STATS pre_scd_eNB_UE_stats[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; +/// sorted downlink component carrier for the scheduler +extern int pre_scd_ordered_CCids[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; +/// number of downlink active component carrier +extern int pre_scd_numactiveCCs[NUMBER_OF_UE_MAX]; +#endif + #endif //DEF_H diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index a68be45f4ba2acfb02abe90ed5fade9a68637d00..bedd37165cc4697965a7178758d4f04b4e80bc0e 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -547,6 +547,161 @@ void sort_UEs(module_id_t Mod_idP, int frameP, sub_frame_t subframeP) #endif } +#if defined(UE_EXPANSION) || defined(UE_EXPANSION_SIM2) +void pre_scd_nb_rbs_required( module_id_t module_idP, + frame_t frameP, + sub_frame_t subframeP, + int min_rb_unit[MAX_NUM_CCs], + uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX]) +{ + int CC_id,UE_id, lc_id,i, j, tmp, N_RB_DL;; + UE_TEMPLATE UE_template; + eNB_UE_STATS *eNB_UE_stats, *eNB_UE_stats_i, *eNB_UE_stats_j; + rnti_t rnti; + mac_rlc_status_resp_t rlc_status; + uint16_t TBS = 0; + + memset(nb_rbs_required, 0, sizeof(uint16_t)*MAX_NUM_CCs*NUMBER_OF_UE_MAX); + + for (UE_id = 0; UE_id <NUMBER_OF_UE_MAX; UE_id++) { + if (pre_scd_activeUE[UE_id] != TRUE) + continue; + + // store dlsch buffer + + // clear logical channel interface variables + UE_template.dl_buffer_total = 0; + UE_template.dl_pdus_total = 0; + + rnti = UE_RNTI(module_idP, UE_id); + + for (lc_id = DCCH; lc_id <= DTCH; lc_id++) { + UE_template.dl_buffer_info[lc_id] = 0; + UE_template.dl_pdus_in_buffer[lc_id] = 0; + UE_template.dl_buffer_head_sdu_creation_time[lc_id] = 0; + UE_template.dl_buffer_head_sdu_remaining_size_to_send[lc_id] = 0; + rlc_status = + mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, + ENB_FLAG_YES, MBMS_FLAG_NO, lc_id, 0); + UE_template.dl_buffer_info[lc_id] = rlc_status.bytes_in_buffer; //storing the dlsch buffer for each logical channel + UE_template.dl_pdus_in_buffer[lc_id] = rlc_status.pdus_in_buffer; + UE_template.dl_buffer_head_sdu_creation_time[lc_id] = rlc_status.head_sdu_creation_time; + UE_template.dl_buffer_head_sdu_creation_time_max = + cmax(UE_template.dl_buffer_head_sdu_creation_time_max, + rlc_status.head_sdu_creation_time); + UE_template.dl_buffer_head_sdu_remaining_size_to_send[lc_id] = + rlc_status.head_sdu_remaining_size_to_send; + UE_template.dl_buffer_head_sdu_is_segmented[lc_id] = rlc_status.head_sdu_is_segmented; + UE_template.dl_buffer_total += UE_template.dl_buffer_info[lc_id]; //storing the total dlsch buffer + UE_template.dl_pdus_total += UE_template.dl_pdus_in_buffer[lc_id]; + +#ifdef DEBUG_eNB_SCHEDULER + /* note for dl_buffer_head_sdu_remaining_size_to_send[i] : + * 0 if head SDU has not been segmented (yet), else remaining size not already segmented and sent + */ + if (UE_template.dl_buffer_info[lc_id] > 0) + LOG_D(MAC, + "[eNB %d] Frame %d Subframe %d : RLC status for UE %d %x in LCID%d: total of %d pdus and size %d, head sdu queuing time %d, remaining size %d, is segmeneted %d \n", + module_idP, frameP, subframeP, UE_id, rnti, + lc_id, UE_template.dl_pdus_in_buffer[lc_id], + UE_template.dl_buffer_info[lc_id], + UE_template.dl_buffer_head_sdu_creation_time[lc_id], + UE_template. + dl_buffer_head_sdu_remaining_size_to_send[lc_id], + UE_template.dl_buffer_head_sdu_is_segmented[lc_id]); +#endif + } + + if (UE_template.dl_buffer_total > 0) + LOG_D(MAC, + "[eNB %d] Frame %d Subframe %d : RLC status for UE %d %x: total DL buffer size %d and total number of pdu %d \n", + module_idP, frameP, subframeP, UE_id,rnti, + UE_template.dl_buffer_total, + UE_template.dl_pdus_total); + // end of store dlsch buffer + + // assgin rbs required + // Calculate the number of RBs required by each UE on the basis of logical channel's buffer + //update CQI information across component carriers + for (i = 0; i < pre_scd_numactiveCCs[UE_id]; i++) { + CC_id = pre_scd_ordered_CCids[i][UE_id]; + eNB_UE_stats = &pre_scd_eNB_UE_stats[CC_id][UE_id]; + + eNB_UE_stats->dlsch_mcs1 = 28; + } + + // provide the list of CCs sorted according to MCS + for (i = 0; i < pre_scd_numactiveCCs[UE_id]; i++) { + eNB_UE_stats_i = + &pre_scd_eNB_UE_stats[pre_scd_ordered_CCids[i][UE_id]][UE_id]; + for (j = i + 1; j < pre_scd_numactiveCCs[UE_id]; j++) { + DevAssert(j < MAX_NUM_CCs); + eNB_UE_stats_j = + &pre_scd_eNB_UE_stats[pre_scd_ordered_CCids[j][UE_id]][UE_id]; + if (eNB_UE_stats_j->dlsch_mcs1 + > eNB_UE_stats_i->dlsch_mcs1) { + tmp = pre_scd_ordered_CCids[i][UE_id]; + pre_scd_ordered_CCids[i][UE_id] = + pre_scd_ordered_CCids[j][UE_id]; + pre_scd_ordered_CCids[j][UE_id] = tmp; + } + } + } + + if (UE_template.dl_buffer_total > 0) { + LOG_D(MAC, "[preprocessor] assign RB for UE %d\n", UE_id); + + for (i = 0; i < pre_scd_numactiveCCs[UE_id]; i++) { + CC_id = pre_scd_ordered_CCids[i][UE_id]; + eNB_UE_stats = &pre_scd_eNB_UE_stats[CC_id][UE_id]; + + if (eNB_UE_stats->dlsch_mcs1 == 0) { + nb_rbs_required[CC_id][UE_id] = 4; // don't let the TBS get too small + } else { + nb_rbs_required[CC_id][UE_id] = + min_rb_unit[CC_id]; + } + + TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, + nb_rbs_required[CC_id][UE_id]); + + LOG_D(MAC, + "[preprocessor] start RB assignement for UE %d CC_id %d dl buffer %d (RB unit %d, MCS %d, TBS %d) \n", + UE_id, CC_id, + UE_template.dl_buffer_total, + nb_rbs_required[CC_id][UE_id], + eNB_UE_stats->dlsch_mcs1, TBS); + + N_RB_DL = + to_prb( + RC.mac[module_idP]->common_channels[CC_id].mib->message.dl_Bandwidth); + + /* calculating required number of RBs for each UE */ + while (TBS + < UE_template.dl_buffer_total) { + nb_rbs_required[CC_id][UE_id] += + min_rb_unit[CC_id]; + if (nb_rbs_required[CC_id][UE_id] > N_RB_DL) { + TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, N_RB_DL); + nb_rbs_required[CC_id][UE_id] = N_RB_DL; + break; + } + + TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, + nb_rbs_required[CC_id][UE_id]); + } // end of while + LOG_D(MAC, + "[eNB %d] Frame %d Subframe %d: UE %d on CC %d: RB unit %d, nb_required RB %d (TBS %d, mcs %d)\n", + module_idP, frameP, subframeP, UE_id, CC_id, + min_rb_unit[CC_id], + nb_rbs_required[CC_id][UE_id], TBS, + eNB_UE_stats->dlsch_mcs1); + } + } + } +} +#endif + #ifdef UE_EXPANSION int cc_id_end(uint8_t *cc_id_flag ) { @@ -1010,7 +1165,7 @@ void dlsch_scheduler_pre_processor (module_id_t Mod_id, } } - +#if (!defined(UE_EXPANSION_SIM2)) &&(!defined(UE_EXPANSION)) // Store the DLSCH buffer for each logical channel store_dlsch_buffer(Mod_id, frameP, subframeP); @@ -1019,6 +1174,9 @@ void dlsch_scheduler_pre_processor (module_id_t Mod_id, // Calculate the number of RBs required by each UE on the basis of logical channel's buffer assign_rbs_required(Mod_id, frameP, subframeP, nb_rbs_required, min_rb_unit); +#else + memcpy(nb_rbs_required, pre_nb_rbs_required[dlsch_ue_select_tbl_in_use] , sizeof(uint16_t)*MAX_NUM_CCs*NUMBER_OF_UE_MAX); +#endif #ifdef UE_EXPANSION dlsch_scheduler_pre_ue_select(Mod_id,frameP,subframeP, mbsfn_flag,nb_rbs_required,dlsch_ue_select); diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 2525f134f457c0b1542c70cd2876bac3d6e45714..565c6109d2d4d9775c5d22d85cb31cc4c3c2b940 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -227,6 +227,13 @@ void dlsch_scheduler_pre_processor_allocate (module_id_t Mod_id, unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]); +#if defined(UE_EXPANSION) || defined(UE_EXPANSION_SIM2) +void pre_scd_nb_rbs_required(module_id_t module_idP, + frame_t frameP, + sub_frame_t subframeP, + int min_rb_unit[MAX_NUM_CCs], + uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX]); +#endif /* \brief Function to trigger the eNB scheduling procedure. It is called by PHY at the beginning of each subframe, \f$n$\f and generates all DLSCH allocations for subframe \f$n\f$ and ULSCH allocations for subframe \f$n+k$\f. @param Mod_id Instance ID of eNB diff --git a/openair2/LAYER2/MAC/vars.h b/openair2/LAYER2/MAC/vars.h index 9882bf75457a6a832554a7745e78d41d4e45ce73..b6db7fe79e5b1aff6e67e6d7114034207cbea621 100644 --- a/openair2/LAYER2/MAC/vars.h +++ b/openair2/LAYER2/MAC/vars.h @@ -150,4 +150,17 @@ DLSCH_UE_SELECT dlsch_ue_select[MAX_NUM_CCs]; int last_dlsch_ue_id[MAX_NUM_CCs] = {-1}; int last_ulsch_ue_id[MAX_NUM_CCs] = {-1}; #endif + +#if defined(UE_EXPANSION) || defined(UE_EXPANSION_SIM2) +uint16_t pre_nb_rbs_required[2][MAX_NUM_CCs][NUMBER_OF_UE_MAX]; +uint8_t dlsch_ue_select_tbl_in_use; +uint8_t new_dlsch_ue_select_tbl_in_use; +boolean_t pre_scd_activeUE[NUMBER_OF_UE_MAX]; +eNB_UE_STATS pre_scd_eNB_UE_stats[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; +/// sorted downlink component carrier for the scheduler +int pre_scd_ordered_CCids[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; +/// number of downlink active component carrier +int pre_scd_numactiveCCs[NUMBER_OF_UE_MAX]; +#endif + #endif diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 33e6b0684b4cb4d595bd855723ae698076d73985..9b46ae7f32f5a1db02b739285602a12d93207e06 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -95,6 +95,10 @@ unsigned short config_frames[4] = {2,9,11,13}; #include "T.h" +#if defined(UE_EXPANSION) || defined(UE_EXPANSION_SIM2) +#include "pdcp.h" +#endif + //#define DEBUG_THREADS 1 //#define USRP_DEBUG 1 @@ -496,6 +500,62 @@ void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { } #endif +#if defined(UE_EXPANSION) || defined(UE_EXPANSION_SIM2) +void* pre_scd_thread( void* param ){ + static int eNB_pre_scd_status; + protocol_ctxt_t ctxt; + int frame; + int subframe; + int min_rb_unit[MAX_NUM_CCs]; + int CC_id; + int Mod_id; + PHY_VARS_eNB *eNB= (PHY_VARS_eNB *)param; + eNB_proc_t *proc = &eNB->proc; + Mod_id = eNB->Mod_id; + + frame = 0; + subframe = 4; + thread_top_init("pre_scd_thread",0,870000,1000000,1000000); + + while (!oai_exit) { + if(oai_exit){ + break; + } + pthread_mutex_lock(&proc->mutex_pre_scd ); + if (proc->instance_pre_scd < 0) { + pthread_cond_wait(&proc->cond_pre_scd, &proc->mutex_pre_scd); + } + pthread_mutex_unlock(&proc->mutex_pre_scd); + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, Mod_id, ENB_FLAG_YES, + NOT_A_RNTI, frame, subframe, + eNB->Mod_id); + pdcp_run(&ctxt); + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + + rrc_rx_tx(&ctxt, 0, // eNB index, unused in eNB + CC_id); + min_rb_unit[CC_id] = get_min_rb_unit(Mod_id, CC_id); + } + + pre_scd_nb_rbs_required(Mod_id, frame, subframe,min_rb_unit,pre_nb_rbs_required[new_dlsch_ue_select_tbl_in_use]); + + if (subframe==9) { + subframe=0; + frame++; + frame&=1023; + } else { + subframe++; + } + pthread_mutex_lock(&proc->mutex_pre_scd ); + proc->instance_pre_scd--; + pthread_mutex_unlock(&proc->mutex_pre_scd); + } + eNB_pre_scd_status = 0; + return &eNB_pre_scd_status; +} +#endif + /*! * \brief The prach receive thread of eNB. * \param param is a \ref eNB_proc_t structure which contains the info what to process. @@ -652,6 +712,14 @@ void init_eNB_proc(int inst) { // attr_te = &proc->attr_te; #endif +#if defined(UE_EXPANSION) || defined(UE_EXPANSION_SIM2) + proc->instance_pre_scd = -1; + pthread_mutex_init( &proc->mutex_pre_scd, NULL); + pthread_cond_init( &proc->cond_pre_scd, NULL); + pthread_create(&proc->pthread_pre_scd, NULL, pre_scd_thread, eNB); + pthread_setname_np(proc->pthread_pre_scd, "pre_scd_thread"); +#endif + if (eNB->single_thread_flag==0) { pthread_create( &proc_rxtx[0].pthread_rxtx, attr0, eNB_thread_rxtx, &proc_rxtx[0] ); pthread_create( &proc_rxtx[1].pthread_rxtx, attr1, eNB_thread_rxtx, &proc_rxtx[1] ); @@ -738,6 +806,13 @@ void kill_eNB_proc(int inst) { pthread_mutex_destroy( &proc->mutex_prach_br ); pthread_cond_destroy( &proc->cond_prach_br ); #endif +#if defined(UE_EXPANSION) || defined(UE_EXPANSION_SIM2) + proc->instance_pre_scd = 0; + pthread_cond_signal( &proc->cond_pre_scd ); + pthread_join( proc->pthread_pre_scd, (void**)&status ); + pthread_mutex_destroy( &proc->mutex_pre_scd ); + pthread_cond_destroy( &proc->cond_pre_scd ); +#endif LOG_I(PHY, "Destroying UL_INFO mutex\n"); pthread_mutex_destroy(&eNB->UL_INFO_mutex); int i; diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index ea8c35ced0264fb78d8421f024f3251b9b43edd6..430f1e64268ff79544df59dbb423f488fb17b3bf 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -1396,6 +1396,9 @@ static void* ru_thread( void* param ) { // set default return value ru_thread_status = 0; +#if defined(UE_EXPANSION) || defined(UE_EXPANSION_SIM2) + dlsch_ue_select_tbl_in_use = 1; +#endif // set default return value @@ -1503,6 +1506,36 @@ static void* ru_thread( void* param ) { // If this proc is to provide synchronization, do so wakeup_slaves(proc); +#if defined(UE_EXPANSION) || defined(UE_EXPANSION_SIM2) + new_dlsch_ue_select_tbl_in_use = dlsch_ue_select_tbl_in_use; + dlsch_ue_select_tbl_in_use = !dlsch_ue_select_tbl_in_use; + memcpy(&pre_scd_eNB_UE_stats,&RC.mac[ru->eNB_list[0]->Mod_id]->UE_list.eNB_UE_stats, sizeof(eNB_UE_STATS)*MAX_NUM_CCs*NUMBER_OF_UE_MAX); + memcpy(&pre_scd_activeUE, &RC.mac[ru->eNB_list[0]->Mod_id]->UE_list.active, sizeof(boolean_t)*NUMBER_OF_UE_MAX); + memcpy(&pre_scd_ordered_CCids, &RC.mac[ru->eNB_list[0]->Mod_id]->UE_list.ordered_CCids, sizeof(int)*MAX_NUM_CCs*NUMBER_OF_UE_MAX); + memcpy(&pre_scd_numactiveCCs, &RC.mac[ru->eNB_list[0]->Mod_id]->UE_list.numactiveCCs, sizeof(int)*NUMBER_OF_UE_MAX); + if (pthread_mutex_lock(&ru->eNB_list[0]->proc.mutex_pre_scd)!= 0) { + LOG_E( MAC, "[eNB] error locking MAC proc mutex for eNB pre scd\n"); + exit_fun("error locking mutex_time"); + } + + ru->eNB_list[0]->proc.instance_pre_scd++; + + if (ru->eNB_list[0]->proc.instance_pre_scd == 0) { + if (pthread_cond_signal(&ru->eNB_list[0]->proc.cond_pre_scd) != 0) { + LOG_E( MAC, "[eNB] ERROR pthread_cond_signal for eNB time sync\n" ); + exit_fun( "ERROR pthread_cond_signal cond_pre_scd" ); + } + }else{ + LOG_E( MAC, "[eNB] frame %d subframe %d rxtx busy instance_pre_scd %d\n", + frame,subframe,ru->eNB_list[0]->proc.instance_pre_scd ); + } + + if (pthread_mutex_unlock(&ru->eNB_list[0]->proc.mutex_pre_scd)!= 0) { + LOG_E( MAC, "[eNB] error unlocking mutex_pre_scd mutex for eNB pre scd\n"); + exit_fun("error unlocking mutex_pre_scd"); + } +#endif + // wakeup all eNB processes waiting for this RU if (ru->num_eNB>0) wakeup_eNBs(ru);