/* * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under * the OAI Public License, Version 1.0 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * * http://www.openairinterface.org/?page_id=698 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org */ /*! \file eNB_scheduler.c * \brief eNB scheduler top level function operates on per subframe basis * \author Navid Nikaein and Raymond Knopp * \date 2010 - 2014 * \email: navid.nikaein@eurecom.fr * \version 0.5 * @ingroup _mac */ #include "assertions.h" #include "PHY/defs.h" #include "PHY/extern.h" #include "SCHED/defs.h" #include "SCHED/extern.h" #include "LAYER2/MAC/defs.h" #include "LAYER2/MAC/extern.h" #include "LAYER2/MAC/proto.h" #include "UTIL/LOG/log.h" #include "UTIL/LOG/vcd_signal_dumper.h" #include "UTIL/OPT/opt.h" #include "OCG.h" #include "OCG_extern.h" #include "RRC/LITE/extern.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" #if defined(FLEXRAN_AGENT_SB_IF) //Agent-related headers #include "flexran_agent_extern.h" #include "flexran_agent_mac.h" #include "flexran_agent_mac_proto.h" #endif #if defined(ENABLE_ITTI) # include "intertask_interface.h" #endif #define ENABLE_MAC_PAYLOAD_DEBUG #define DEBUG_eNB_SCHEDULER 1 extern RAN_CONTEXT_t RC; extern int phy_test; uint16_t pdcch_order_table[6] = {31,31,511,2047,2047,8191}; void schedule_SRS(module_id_t module_idP,frame_t frameP,sub_frame_t subframeP) { eNB_MAC_INST *eNB = RC.mac[module_idP]; UE_list_t *UE_list = &eNB->UE_list; nfapi_ul_config_request_body_t *ul_req; int CC_id,UE_id; COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; SoundingRS_UL_ConfigCommon_t *soundingRS_UL_ConfigCommon; struct SoundingRS_UL_ConfigDedicated *soundingRS_UL_ConfigDedicated; uint8_t TSFC; uint16_t deltaTSFC; // bitmap uint8_t srs_SubframeConfig; // table for TSFC (Period) and deltaSFC (offset) const uint16_t deltaTSFCTabType1[15][2] = { {1,1},{1,2},{2,2},{1,5},{2,5},{4,5},{8,5},{3,5},{12,5},{1,10},{2,10},{4,10},{8,10},{351,10},{383,10} }; // Table 5.5.3.3-2 3GPP 36.211 FDD const uint16_t deltaTSFCTabType2[14][2] = { {2,5},{6,5},{10,5},{18,5},{14,5},{22,5},{26,5},{30,5},{70,10},{74,10},{194,10},{326,10},{586,10},{210,10} }; // Table 5.5.3.3-2 3GPP 36.211 TDD uint16_t srsPeriodicity,srsOffset; for (CC_id=0;CC_id<MAX_NUM_CCs;CC_id++) { soundingRS_UL_ConfigCommon = &cc[CC_id].radioResourceConfigCommon->soundingRS_UL_ConfigCommon; // check if SRS is enabled in this frame/subframe if (soundingRS_UL_ConfigCommon) { srs_SubframeConfig = soundingRS_UL_ConfigCommon->choice.setup.srs_SubframeConfig; if (cc[CC_id].tdd_Config == NULL) { // FDD deltaTSFC = deltaTSFCTabType1[srs_SubframeConfig][0]; TSFC = deltaTSFCTabType1[srs_SubframeConfig][1]; } else { // TDD deltaTSFC = deltaTSFCTabType2[srs_SubframeConfig][0]; TSFC = deltaTSFCTabType2[srs_SubframeConfig][1]; } // Sounding reference signal subframes are the subframes satisfying ns/2 mod TSFC (- deltaTSFC uint16_t tmp = (subframeP % TSFC); if((1<<tmp) & deltaTSFC) { // This is an SRS subframe, loop over UEs for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) { if (RC.mac[module_idP]->UE_list.active[UE_id]!=TRUE) continue; ul_req = &RC.mac[module_idP]->UL_req[CC_id].ul_config_request_body; // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet if (mac_eNB_get_rrc_status(module_idP,UE_RNTI(module_idP,UE_id)) < RRC_CONNECTED) continue; AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL, "physicalConfigDedicated is null for UE %d\n",UE_id); if ((soundingRS_UL_ConfigDedicated = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated)!=NULL) { if (soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup) { get_srs_pos(&cc[CC_id], soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex, &srsPeriodicity, &srsOffset); if (((10*frameP+subframeP) % srsPeriodicity) == srsOffset) { // Prorgram SRS ul_req->srs_present = 1; nfapi_ul_config_request_pdu_t* ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; memset((void*)ul_config_pdu,0,sizeof(nfapi_ul_config_request_pdu_t)); ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_SRS_PDU_TYPE; ul_config_pdu->pdu_size = 2+(uint8_t)(2+sizeof(nfapi_ul_config_srs_pdu)); ul_config_pdu->srs_pdu.srs_pdu_rel8.size = (uint8_t)sizeof(nfapi_ul_config_srs_pdu);; ul_config_pdu->srs_pdu.srs_pdu_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; ul_config_pdu->srs_pdu.srs_pdu_rel8.srs_bandwidth = soundingRS_UL_ConfigDedicated->choice.setup.srs_Bandwidth; ul_config_pdu->srs_pdu.srs_pdu_rel8.frequency_domain_position = soundingRS_UL_ConfigDedicated->choice.setup.freqDomainPosition; ul_config_pdu->srs_pdu.srs_pdu_rel8.srs_hopping_bandwidth = soundingRS_UL_ConfigDedicated->choice.setup.srs_HoppingBandwidth;; ul_config_pdu->srs_pdu.srs_pdu_rel8.transmission_comb = soundingRS_UL_ConfigDedicated->choice.setup.transmissionComb; ul_config_pdu->srs_pdu.srs_pdu_rel8.i_srs = soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex; ul_config_pdu->srs_pdu.srs_pdu_rel8.sounding_reference_cyclic_shift = soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift; // ul_config_pdu->srs_pdu.srs_pdu_rel10.antenna_port = ;// // ul_config_pdu->srs_pdu.srs_pdu_rel13.number_of_combs = ;// RC.mac[module_idP]->UL_req[CC_id].sfn_sf = (frameP<<4)+subframeP; ul_req->number_of_pdus++; } // if (((10*frameP+subframeP) % srsPeriodicity) == srsOffset) } // if (soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup) } // if ((soundingRS_UL_ConfigDedicated = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated)!=NULL) } // for (UE_id ... } // if((1<<tmp) & deltaTSFC) }// SRS config } } void schedule_CSI(module_id_t module_idP,frame_t frameP,sub_frame_t subframeP) { eNB_MAC_INST *eNB = RC.mac[module_idP]; UE_list_t *UE_list = &eNB->UE_list; COMMON_channels_t *cc; nfapi_ul_config_request_body_t *ul_req; int CC_id,UE_id; struct CQI_ReportPeriodic *cqi_ReportPeriodic; uint16_t Npd,N_OFFSET_CQI; int H; for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { cc = &eNB->common_channels[CC_id]; for (UE_id=0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { if (UE_list->active[UE_id] != TRUE) continue; ul_req = &RC.mac[module_idP]->UL_req[CC_id].ul_config_request_body; // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet if (mac_eNB_get_rrc_status(module_idP,UE_RNTI(module_idP,UE_id)) < RRC_CONNECTED) continue; AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL, "physicalConfigDedicated is null for UE %d\n",UE_id); if (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig) { if ((cqi_ReportPeriodic = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic)!=NULL && (cqi_ReportPeriodic->present!=CQI_ReportPeriodic_PR_release)) { //Rel8 Periodic CQI/PMI/RI reporting get_csi_params(cc,cqi_ReportPeriodic,&Npd,&N_OFFSET_CQI,&H); if ((((frameP*10)+subframeP)%Npd) == N_OFFSET_CQI) { // CQI opportunity UE_list->UE_sched_ctrl[UE_id].feedback_cnt[CC_id]=(((frameP*10)+subframeP)/Npd)%H; // Program CQI nfapi_ul_config_request_pdu_t* ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; memset((void*)ul_config_pdu,0,sizeof(nfapi_ul_config_request_pdu_t)); ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE; ul_config_pdu->pdu_size = 2+(uint8_t)(2+sizeof(nfapi_ul_config_uci_cqi_pdu)); ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.pucch_index = cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex; ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.dl_cqi_pmi_size = get_rel8_dl_cqi_pmi_size(&UE_list->UE_sched_ctrl[UE_id], CC_id, cc, get_tmode(module_idP,CC_id,UE_id), cqi_ReportPeriodic); ul_req->number_of_pdus++; #if defined(Rel10) || defined(Rel14) // PUT rel10-13 UCI options here #endif } else if ((cqi_ReportPeriodic->choice.setup.ri_ConfigIndex) && ((((frameP*10)+subframeP)%((H*Npd)<<(*cqi_ReportPeriodic->choice.setup.ri_ConfigIndex/161)))== N_OFFSET_CQI + (*cqi_ReportPeriodic->choice.setup.ri_ConfigIndex%161))) { // RI opportunity // Program RI nfapi_ul_config_request_pdu_t* ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; memset((void*)ul_config_pdu,0,sizeof(nfapi_ul_config_request_pdu_t)); ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE; ul_config_pdu->pdu_size = 2+(uint8_t)(2+sizeof(nfapi_ul_config_uci_cqi_pdu)); ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.pucch_index = cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex; ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.dl_cqi_pmi_size = (cc->p_eNB==2)?1:2; RC.mac[module_idP]->UL_req[CC_id].sfn_sf = (frameP<<4)+subframeP; ul_req->number_of_pdus++; } } // if ((cqi_ReportPeriodic = cqi_ReportConfig->cqi_ReportPeriodic)!=NULL) { } // if (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig) } // for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { } // for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { } void schedule_SR(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) { eNB_MAC_INST *eNB = RC.mac[module_idP]; UE_list_t *UE_list = &eNB->UE_list; nfapi_ul_config_request_body_t *ul_req; int CC_id; int UE_id; SchedulingRequestConfig_t *SRconfig; int skip_ue; int is_harq; nfapi_ul_config_sr_information sr; int i; for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { RC.mac[module_idP]->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP; for (UE_id = 0; UE_id<NUMBER_OF_UE_MAX; UE_id++) { if (RC.mac[module_idP]->UE_list.active[UE_id]!=TRUE) continue; ul_req = &RC.mac[module_idP]->UL_req[CC_id].ul_config_request_body; AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL, "physicalConfigDedicated is null for UE %d\n",UE_id); // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet if (mac_eNB_get_rrc_status(module_idP,UE_RNTI(module_idP,UE_id)) < RRC_CONNECTED) continue; if ((SRconfig = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig)!=NULL) { if (SRconfig->present == SchedulingRequestConfig_PR_setup) { if (SRconfig->choice.setup.sr_ConfigIndex <= 4) { // 5 ms SR period if ((subframeP%5) != SRconfig->choice.setup.sr_ConfigIndex) continue; } else if (SRconfig->choice.setup.sr_ConfigIndex <= 14) { // 10 ms SR period if (subframeP!=(SRconfig->choice.setup.sr_ConfigIndex-5)) continue; } else if (SRconfig->choice.setup.sr_ConfigIndex <= 34) { // 20 ms SR period if ((10*(frameP&1)+subframeP) != (SRconfig->choice.setup.sr_ConfigIndex-15)) continue; } else if (SRconfig->choice.setup.sr_ConfigIndex <= 74) { // 40 ms SR period if ((10*(frameP&3)+subframeP) != (SRconfig->choice.setup.sr_ConfigIndex-35)) continue; } else if (SRconfig->choice.setup.sr_ConfigIndex <= 154) { // 80 ms SR period if ((10*(frameP&7)+subframeP) != (SRconfig->choice.setup.sr_ConfigIndex-75)) continue; } } // SRconfig->present == SchedulingRequestConfig_PR_setup) } // SRconfig = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig)!=NULL) // if we get here there is some PUCCH1 reception to schedule for SR skip_ue=0; is_harq = 0; // check that there is no existing UL grant for ULSCH which overrides the SR for (i = 0; i < ul_req->number_of_pdus; i++) { if (((ul_req->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE)|| (ul_req->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE)|| (ul_req->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE)|| (ul_req->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE))&& (ul_req->ul_config_pdu_list[i].ulsch_pdu.ulsch_pdu_rel8.rnti == UE_list->UE_template[CC_id][UE_id].rnti)) { skip_ue=1; break; } /* if there is already an HARQ pdu, convert to SR_HARQ */ else if ((ul_req->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE)&& (ul_req->ul_config_pdu_list[i].uci_harq_pdu.ue_information.ue_information_rel8.rnti == UE_list->UE_template[CC_id][UE_id].rnti)) { is_harq = 1; break; } } // drop the allocation because ULSCH with handle it with BSR if (skip_ue==1) continue; LOG_D(MAC,"Frame %d, Subframe %d : Scheduling SR for UE %d/%x\n",frameP,subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].rnti); // check Rel10 or Rel8 SR #if defined(Rel10) || defined(Rel14) if ((UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2) && (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020)&& (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020)) { sr.sr_information_rel10.number_of_pucch_resources = 1; sr.sr_information_rel10.pucch_index_p1 = *UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020->sr_PUCCH_ResourceIndexP1_r10; } else #endif { sr.sr_information_rel8.pucch_index = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig->choice.setup.sr_PUCCH_ResourceIndex; } /* if there is already an HARQ pdu, convert to SR_HARQ */ if (is_harq) { nfapi_ul_config_harq_information h = ul_req->ul_config_pdu_list[i].uci_harq_pdu.harq_information; ul_req->ul_config_pdu_list[i].pdu_type = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE; ul_req->ul_config_pdu_list[i].uci_sr_harq_pdu.sr_information = sr; ul_req->ul_config_pdu_list[i].uci_sr_harq_pdu.harq_information = h; } else { ul_req->ul_config_pdu_list[ul_req->number_of_pdus].pdu_type = NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE; ul_req->ul_config_pdu_list[ul_req->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; ul_req->ul_config_pdu_list[ul_req->number_of_pdus].uci_sr_pdu.sr_information = sr; ul_req->number_of_pdus++; } /* if (is_harq) */ } // for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) } // for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) } void check_ul_failure(module_id_t module_idP,int CC_id,int UE_id, frame_t frameP, sub_frame_t subframeP) { UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; nfapi_dl_config_request_t *DL_req = &RC.mac[module_idP]->DL_req[0]; uint16_t rnti = UE_RNTI(module_idP,UE_id); COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; // check uplink failure if ((UE_list->UE_sched_ctrl[UE_id].ul_failure_timer>0)&& (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync==0)) { LOG_I(MAC,"UE %d rnti %x: UL Failure timer %d \n",UE_id,rnti,UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); if (UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent==0) { UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent=1; // add a format 1A dci for this UE to request an RA procedure (only one UE per subframe) nfapi_dl_config_request_pdu_t* dl_config_pdu = &DL_req[CC_id].dl_config_request_body.dl_config_pdu_list[DL_req[CC_id].dl_config_request_body.number_pdu]; memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu)); dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP,CC_id),UE_list->UE_sched_ctrl[UE_id].dl_cqi[CC_id],format1A); dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power AssertFatal((cc[CC_id].mib->message.dl_Bandwidth >=0) && (cc[CC_id].mib->message.dl_Bandwidth<6), "illegal dl_Bandwidth %d\n",(int)cc[CC_id].mib->message.dl_Bandwidth); dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = pdcch_order_table[cc[CC_id].mib->message.dl_Bandwidth]; DL_req[CC_id].dl_config_request_body.number_dci++; DL_req[CC_id].dl_config_request_body.number_pdu++; LOG_I(MAC,"UE %d rnti %x: sending PDCCH order for RAPROC (failure timer %d), resource_block_coding %d \n",UE_id,rnti,UE_list->UE_sched_ctrl[UE_id].ul_failure_timer,dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding); } else { // ra_pdcch_sent==1 LOG_I(MAC,"UE %d rnti %x: sent PDCCH order for RAPROC waiting (failure timer %d) \n",UE_id,rnti,UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); if ((UE_list->UE_sched_ctrl[UE_id].ul_failure_timer % 40) == 0) UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent=0; // resend every 4 frames } UE_list->UE_sched_ctrl[UE_id].ul_failure_timer++; // check threshold if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer > 200) { // inform RRC of failure and clear timer LOG_I(MAC,"UE %d rnti %x: UL Failure after repeated PDCCH orders: Triggering RRC \n",UE_id,rnti); mac_eNB_rrc_ul_failure(module_idP,CC_id,frameP,subframeP,rnti); UE_list->UE_sched_ctrl[UE_id].ul_failure_timer=0; UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync=1; } } // ul_failure_timer>0 } void clear_nfapi_information(eNB_MAC_INST *eNB,int CC_idP,frame_t frameP,sub_frame_t subframeP) { nfapi_dl_config_request_t *DL_req = &eNB->DL_req[0]; nfapi_ul_config_request_t *UL_req = &eNB->UL_req[0]; nfapi_hi_dci0_request_t *HI_DCI0_req = &eNB->HI_DCI0_req[0]; nfapi_tx_request_t *TX_req = &eNB->TX_req[0]; eNB->pdu_index[CC_idP] = 0; DL_req[CC_idP].dl_config_request_body.number_pdcch_ofdm_symbols = 1; DL_req[CC_idP].dl_config_request_body.number_dci = 0; DL_req[CC_idP].dl_config_request_body.number_pdu = 0; DL_req[CC_idP].dl_config_request_body.number_pdsch_rnti = 0; DL_req[CC_idP].dl_config_request_body.transmission_power_pcfich = 6000; HI_DCI0_req[CC_idP].hi_dci0_request_body.sfnsf = subframeP + (frameP<<4); HI_DCI0_req[CC_idP].hi_dci0_request_body.number_of_dci = 0; UL_req[CC_idP].ul_config_request_body.number_of_pdus = 0; UL_req[CC_idP].ul_config_request_body.rach_prach_frequency_resources = 0; // ignored, handled by PHY for now UL_req[CC_idP].ul_config_request_body.srs_present = 0; // ignored, handled by PHY for now TX_req[CC_idP].tx_request_body.number_of_pdus = 0; } void copy_ulreq(module_id_t module_idP,frame_t frameP, sub_frame_t subframeP) { int CC_id; eNB_MAC_INST *eNB; nfapi_ul_config_request_body_t *ul_req_tmp; nfapi_ul_config_request_body_t *ul_req; eNB = RC.mac[module_idP]; for (CC_id=0;CC_id<MAX_NUM_CCs;CC_id++) { ul_req_tmp = &eNB->UL_req_tmp[CC_id][subframeP].ul_config_request_body; ul_req = &eNB->UL_req[CC_id].ul_config_request_body; eNB->UL_req[CC_id].sfn_sf = (frameP<<4) + subframeP; ul_req->number_of_pdus = ul_req_tmp->number_of_pdus; ul_req_tmp->number_of_pdus = 0; memcpy((void*)ul_req->ul_config_pdu_list, (void*)ul_req_tmp->ul_config_pdu_list, ul_req->number_of_pdus*sizeof(nfapi_ul_config_request_pdu_t)); } } void eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) { int mbsfn_status[MAX_NUM_CCs]; protocol_ctxt_t ctxt; int CC_id,i; //,next_i; UE_list_t *UE_list=&RC.mac[module_idP]->UE_list; rnti_t rnti; COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; #if defined(FLEXRAN_AGENT_SB_IF) Protocol__FlexranMessage *msg; #endif start_meas(&RC.mac[module_idP]->eNB_scheduler); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_IN); for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { mbsfn_status[CC_id]=0; // clear vrb_maps memset(cc[CC_id].vrb_map,0,100); memset(cc[CC_id].vrb_map_UL,0,100); #if defined(Rel10) || defined(Rel14) cc[CC_id].mcch_active =0; #endif RC.mac[module_idP]->frame = frameP; RC.mac[module_idP]->subframe = subframeP; clear_nfapi_information(RC.mac[module_idP],CC_id,frameP,subframeP); } // refresh UE list based on UEs dropped by PHY in previous subframe for (i = 0; i < NUMBER_OF_UE_MAX; i++) { if (UE_list->active[i] != TRUE) continue; rnti = UE_RNTI(module_idP, i); CC_id = UE_PCCID(module_idP, i); if ((frameP==0)&&(subframeP==0)) { LOG_I(MAC,"UE rnti %x : %s, PHR %d dB DL CQI %d PUSCH SNR %d PUCCH SNR %d\n", rnti, UE_list->UE_sched_ctrl[i].ul_out_of_sync==0 ? "in synch" : "out of sync", UE_list->UE_template[CC_id][i].phr_info, UE_list->UE_sched_ctrl[i].dl_cqi[CC_id], (UE_list->UE_sched_ctrl[i].pusch_snr[CC_id]-128)/2, (UE_list->UE_sched_ctrl[i].pucch1_snr[CC_id]-128)/2); } RC.eNB[module_idP][CC_id]->pusch_stats_bsr[i][(frameP*10)+subframeP]=-63; if (i==UE_list->head) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR,RC.eNB[module_idP][CC_id]->pusch_stats_bsr[i][(frameP*10)+subframeP]); // increment this, it is cleared when we receive an sdu RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ul_inactivity_timer++; RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].cqi_req_timer++; LOG_D(MAC,"UE %d/%x : ul_inactivity %d, cqi_req %d\n",i,rnti, RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ul_inactivity_timer, RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].cqi_req_timer); check_ul_failure(module_idP,CC_id,i,frameP,subframeP); } PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frameP, subframeP,module_idP); pdcp_run(&ctxt); rrc_rx_tx(&ctxt, 0, // eNB index, unused in eNB CC_id); #if defined(Rel10) || defined(Rel14) for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { if (cc[CC_id].MBMS_flag >0) { start_meas(&RC.mac[module_idP]->schedule_mch); mbsfn_status[CC_id] = schedule_MBMS(module_idP,CC_id,frameP,subframeP); stop_meas(&RC.mac[module_idP]->schedule_mch); } } #endif // This schedules MIB if ((subframeP==0) && (frameP&3) == 0) schedule_mib(module_idP,frameP,subframeP); if (phy_test==0) { // This schedules SI for legacy LTE and eMTC starting in subframeP schedule_SI(module_idP,frameP,subframeP); // This schedules Random-Access for legacy LTE and eMTC starting in subframeP schedule_RA(module_idP,frameP,subframeP); // copy previously scheduled UL resources (ULSCH + HARQ) copy_ulreq(module_idP,frameP,subframeP); // This schedules SRS in subframeP schedule_SRS(module_idP,frameP,subframeP); // This schedules ULSCH in subframeP (dci0) schedule_ulsch(module_idP,frameP,subframeP); // This schedules UCI_SR in subframeP schedule_SR(module_idP,frameP,subframeP); // This schedules UCI_CSI in subframeP schedule_CSI(module_idP, frameP, subframeP); // This schedules DLSCH in subframeP schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); } else { schedule_ue_spec_phy_test(module_idP,frameP,subframeP,mbsfn_status); } // Allocate CCEs for good after scheduling is done for (CC_id=0;CC_id<MAX_NUM_CCs;CC_id++) allocate_CCEs(module_idP,CC_id,subframeP,0); stop_meas(&RC.mac[module_idP]->eNB_scheduler); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_OUT); }