The problem is that when using those RBs with MCS 28 we may exceed the code rate 0.93 and according to 36.213 7.1.7 the UE may skip decoding PDSCH entirely in this case. This is a hack. The real solution is to check that the code rate is below 0.93 for each scheduling decision and, I don't know, reduce the MCS if the code rate is above, so that in the end it is below. That means that we need a proper resource grid for the configuration of the eNB and this is not an easy thing (at least from my point of view) given all the possible configurations for the eNB, so I prefer not to do it rather than do something incorrect, thus this hack. The problem of this hack is that we won't use all the available RBs for scheduling, potentially reducing the maximum throughput achievable. To be fixed properly at some time, by someone who understands fully the resource grid and all the possible combinations (fdd/tdd, number of antennas, whatever else).
1080 lines
53 KiB
C
1080 lines
53 KiB
C
/*
|
|
* 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.1 (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 "targets/RT/USER/lte-softmodem.h"
|
|
#include "LAYER2/MAC/mac.h"
|
|
#include "LAYER2/MAC/mac_extern.h"
|
|
|
|
#include "LAYER2/MAC/mac_proto.h"
|
|
#include "common/utils/LOG/log.h"
|
|
#include "nfapi/oai_integration/vendor_ext.h"
|
|
#include "common/utils/LOG/vcd_signal_dumper.h"
|
|
#include "UTIL/OPT/opt.h"
|
|
#include "OCG.h"
|
|
#include "OCG_extern.h"
|
|
|
|
#include "RRC/LTE/rrc_extern.h"
|
|
#include "RRC/NR/nr_rrc_extern.h"
|
|
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
|
|
|
|
//#include "LAYER2/MAC/pre_processor.c"
|
|
#include "pdcp.h"
|
|
|
|
//Agent-related headers
|
|
#include "flexran_agent_extern.h"
|
|
#include "flexran_agent_mac.h"
|
|
|
|
/* for fair round robin SCHED */
|
|
#include "eNB_scheduler_fairRR.h"
|
|
|
|
#include "intertask_interface.h"
|
|
|
|
#include "assertions.h"
|
|
|
|
#define ENABLE_MAC_PAYLOAD_DEBUG
|
|
#define DEBUG_eNB_SCHEDULER 1
|
|
|
|
extern RAN_CONTEXT_t RC;
|
|
|
|
|
|
uint16_t pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 };
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/*
|
|
* Schedule periodic SRS
|
|
*/
|
|
void schedule_SRS(module_id_t module_idP,
|
|
frame_t frameP,
|
|
sub_frame_t subframeP)
|
|
//-----------------------------------------------------------------------------
|
|
{
|
|
int CC_id = 0;
|
|
int UE_id = -1;
|
|
uint8_t TSFC = 0;
|
|
uint8_t srs_SubframeConfig = 0;
|
|
uint16_t srsPeriodicity = 0;
|
|
uint16_t srsOffset = 0;
|
|
uint16_t deltaTSFC = 0; // bitmap
|
|
// 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
|
|
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
|
UE_info_t *UE_info = &eNB->UE_info;
|
|
nfapi_ul_config_request_body_t *ul_req = NULL;
|
|
UE_sched_ctrl_t *UE_scheduling_control = NULL;
|
|
COMMON_channels_t *cc = eNB->common_channels;
|
|
LTE_SoundingRS_UL_ConfigCommon_t *soundingRS_UL_ConfigCommon = NULL;
|
|
struct LTE_SoundingRS_UL_ConfigDedicated *soundingRS_UL_ConfigDedicated = NULL;
|
|
|
|
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 < MAX_MOBILES_PER_ENB; UE_id++) {
|
|
if (!UE_info->active[UE_id]) {
|
|
continue;
|
|
}
|
|
|
|
/* 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(UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated == NULL) {
|
|
LOG_E(MAC,"physicalConfigDedicated is null for UE %d\n",UE_id);
|
|
printf("physicalConfigDedicated is null for UE %d\n",UE_id);
|
|
return;
|
|
}
|
|
|
|
/* CDRX condition on Active Time and SRS type-0 report (36.321 5.7) */
|
|
UE_scheduling_control = &(UE_info->UE_sched_ctrl[UE_id]);
|
|
|
|
/* Test if Active Time not running since 6+ subframes */
|
|
if (UE_scheduling_control->cdrx_configured == TRUE && UE_scheduling_control->in_active_time == FALSE) {
|
|
/*
|
|
* TODO: 6+ subframes condition not checked here
|
|
*/
|
|
continue;
|
|
}
|
|
|
|
ul_req = &(eNB->UL_req[CC_id].ul_config_request_body);
|
|
|
|
if ((soundingRS_UL_ConfigDedicated = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated) != NULL) {
|
|
if (soundingRS_UL_ConfigDedicated->present == LTE_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) {
|
|
// Program 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.tl.tag = NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL8_TAG;
|
|
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_info->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;
|
|
eNB->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP;
|
|
eNB->UL_req[CC_id].header.message_id = NFAPI_UL_CONFIG_REQUEST;
|
|
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_info->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated)!=NULL)
|
|
} // end for loop on UE_id
|
|
} // if((1<<tmp) & deltaTSFC)
|
|
} // SRS config not NULL
|
|
} // end for loop on CC_id
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/*
|
|
* Schedule the CSI (CQI/PMI/RI/PTI/CRI) periodic reception
|
|
*/
|
|
void schedule_CSI(module_id_t module_idP,
|
|
frame_t frameP,
|
|
sub_frame_t subframeP)
|
|
//-----------------------------------------------------------------------------
|
|
{
|
|
int CC_id = 0;
|
|
int UE_id = 0;
|
|
int H = 0;
|
|
uint16_t Npd = 0;
|
|
uint16_t N_OFFSET_CQI = 0;
|
|
struct LTE_CQI_ReportPeriodic *cqi_ReportPeriodic = NULL;
|
|
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
|
UE_info_t *UE_info = &eNB->UE_info;
|
|
COMMON_channels_t *cc = NULL;
|
|
nfapi_ul_config_request_body_t *ul_req = NULL;
|
|
UE_sched_ctrl_t *UE_scheduling_control = NULL;
|
|
|
|
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
|
|
cc = &eNB->common_channels[CC_id];
|
|
|
|
for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) {
|
|
if (UE_info->active[UE_id] == FALSE) {
|
|
continue;
|
|
}
|
|
|
|
/* Drop the allocation if the UE hasn't sent RRCConnectionSetupComplete yet */
|
|
if (mac_eNB_get_rrc_status(module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) {
|
|
continue;
|
|
}
|
|
|
|
AssertFatal(UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL,
|
|
"physicalConfigDedicated is null for UE %d\n",
|
|
UE_id);
|
|
/*
|
|
* CDRX condition on Active Time and CSI report on PUCCH (36.321 5.7).
|
|
* Here we consider classic periodic reports on PUCCH without PUSCH simultaneous transmission condition.
|
|
* TODO: add the handling or test on simultaneous PUCCH/PUSCH transmission
|
|
*/
|
|
UE_scheduling_control = &(UE_info->UE_sched_ctrl[UE_id]);
|
|
|
|
if (UE_scheduling_control->cdrx_configured == TRUE) {
|
|
/* Test if CQI masking activated */
|
|
if (UE_scheduling_control->cqi_mask_boolean == TRUE) {
|
|
// CQI masking => test if onDurationTime not running since 6+ subframe
|
|
if (UE_scheduling_control->on_duration_timer == 0) {
|
|
/*
|
|
* TODO: 6+ subframes condition not checked here
|
|
*/
|
|
continue;
|
|
}
|
|
} else { // No CQI masking => test if Active Time not running since 6+ subframe
|
|
if (UE_scheduling_control->in_active_time == FALSE) {
|
|
/*
|
|
* TODO: 6+ subframes condition not checked here
|
|
*/
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
ul_req = &(eNB->UL_req[CC_id].ul_config_request_body);
|
|
|
|
if (UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL) {
|
|
cqi_ReportPeriodic = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic;
|
|
|
|
if (cqi_ReportPeriodic != NULL) {
|
|
/* Rel8 Periodic CSI (CQI/PMI/RI) reporting */
|
|
if (cqi_ReportPeriodic->present != LTE_CQI_ReportPeriodic_PR_release) {
|
|
get_csi_params(cc, cqi_ReportPeriodic, &Npd, &N_OFFSET_CQI, &H);
|
|
|
|
if ((((frameP * 10) + subframeP) % Npd) == N_OFFSET_CQI) { // CQI periodic opportunity
|
|
UE_scheduling_control->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.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG;
|
|
ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_info->UE_template[CC_id][UE_id].rnti;
|
|
ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG;
|
|
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_info->UE_sched_ctrl[UE_id], CC_id, cc, get_tmode(module_idP, CC_id, UE_id),
|
|
cqi_ReportPeriodic);
|
|
ul_req->number_of_pdus++;
|
|
ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG;
|
|
// PUT rel10-13 UCI options here
|
|
} else if (cqi_ReportPeriodic->choice.setup.ri_ConfigIndex != NULL) {
|
|
if ((((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.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG;
|
|
ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_info->UE_template[CC_id][UE_id].rnti;
|
|
ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG;
|
|
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++;
|
|
ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG;
|
|
}
|
|
}
|
|
} // if CSI Periodic is not release state
|
|
} // if (cqi_ReportPeriodic != NULL)
|
|
} // if cqi_ReportConfig != NULL
|
|
} // for (UE_id=UE_info->head; UE_id>=0; UE_id=UE_info->next[UE_id]) {
|
|
} // for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/*
|
|
* Schedule a possible Scheduling Request reception
|
|
*/
|
|
void
|
|
schedule_SR (module_id_t module_idP,
|
|
frame_t frameP,
|
|
sub_frame_t subframeP)
|
|
//-----------------------------------------------------------------------------
|
|
{
|
|
int skip_ue = 0;
|
|
int is_harq = 0;
|
|
int pdu_list_index = 0;
|
|
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
|
UE_info_t *UE_info = &eNB->UE_info;
|
|
nfapi_ul_config_request_t *ul_req = NULL;
|
|
nfapi_ul_config_request_body_t *ul_req_body = NULL;
|
|
LTE_SchedulingRequestConfig_t *SRconfig = NULL;
|
|
nfapi_ul_config_sr_information sr;
|
|
|
|
for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
|
|
eNB->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP;
|
|
|
|
for (int UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) {
|
|
if (!UE_info->active[UE_id]) {
|
|
continue;
|
|
}
|
|
|
|
if (UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated == NULL) continue;
|
|
|
|
if ((SRconfig = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig) != NULL) {
|
|
if (SRconfig->present == LTE_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;
|
|
} else if (SRconfig->choice.setup.sr_ConfigIndex <= 156) { // 2ms SR period
|
|
if ((subframeP % 2) != (SRconfig->choice.setup.sr_ConfigIndex - 155)) continue;
|
|
}
|
|
} // SRconfig->present == SchedulingRequestConfig_PR_setup)
|
|
} // SRconfig = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig)!=NULL)
|
|
|
|
/* If we get here there is some PUCCH1 reception to schedule for SR */
|
|
ul_req = &(eNB->UL_req[CC_id]);
|
|
ul_req_body = &(ul_req->ul_config_request_body);
|
|
skip_ue = 0;
|
|
is_harq = 0;
|
|
pdu_list_index = 0;
|
|
|
|
/* Check that there is no existing UL grant for ULSCH which overrides the SR */
|
|
for (int i = 0; i < ul_req_body->number_of_pdus; i++) {
|
|
if (((ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE) ||
|
|
(ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE) ||
|
|
(ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE) ||
|
|
(ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE)) &&
|
|
(ul_req_body->ul_config_pdu_list[i].ulsch_pdu.ulsch_pdu_rel8.rnti == UE_info->UE_template[CC_id][UE_id].rnti)) {
|
|
skip_ue = 1;
|
|
pdu_list_index = i;
|
|
break;
|
|
}
|
|
/* If there is already an HARQ pdu, convert to SR_HARQ */
|
|
else if ((ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE) &&
|
|
(ul_req_body->ul_config_pdu_list[i].uci_harq_pdu.ue_information.ue_information_rel8.rnti == UE_info->UE_template[CC_id][UE_id].rnti)) {
|
|
is_harq = 1;
|
|
pdu_list_index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Drop the allocation because ULSCH will handle it with BSR */
|
|
if (skip_ue == 1) continue;
|
|
|
|
LOG_D(MAC, "Frame %d, Subframe %d : Scheduling SR for UE %d/%x is_harq:%d \n",
|
|
frameP,
|
|
subframeP,
|
|
UE_id,
|
|
UE_info->UE_template[CC_id][UE_id].rnti,
|
|
is_harq);
|
|
|
|
/* Check Rel10 or Rel8 SR */
|
|
if ((UE_info-> UE_template[CC_id][UE_id].physicalConfigDedicated->ext2) &&
|
|
(UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020) &&
|
|
(UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020)) {
|
|
sr.sr_information_rel10.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL10_TAG;
|
|
sr.sr_information_rel10.number_of_pucch_resources = 1;
|
|
sr.sr_information_rel10.pucch_index_p1 = *UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020->sr_PUCCH_ResourceIndexP1_r10;
|
|
LOG_D(MAC, "REL10 PUCCH INDEX P1:%d \n", sr.sr_information_rel10.pucch_index_p1);
|
|
} else {
|
|
sr.sr_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL8_TAG;
|
|
sr.sr_information_rel8.pucch_index = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig->choice.setup.sr_PUCCH_ResourceIndex;
|
|
LOG_D(MAC, "REL8 PUCCH INDEX:%d\n", sr.sr_information_rel8.pucch_index);
|
|
}
|
|
|
|
/* If there is already an HARQ pdu, convert to SR_HARQ */
|
|
if (is_harq) {
|
|
nfapi_ul_config_harq_information harq = ul_req_body->ul_config_pdu_list[pdu_list_index].uci_harq_pdu.harq_information;
|
|
ul_req_body->ul_config_pdu_list[pdu_list_index].pdu_type = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE;
|
|
ul_req_body->ul_config_pdu_list[pdu_list_index].uci_sr_harq_pdu.sr_information = sr;
|
|
ul_req_body->ul_config_pdu_list[pdu_list_index].uci_sr_harq_pdu.harq_information = harq;
|
|
} else {
|
|
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].pdu_type = NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE;
|
|
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG;
|
|
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.rnti = UE_info->UE_template[CC_id][UE_id].rnti;
|
|
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel11.tl.tag = 0;
|
|
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel13.tl.tag = 0;
|
|
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.sr_information = sr;
|
|
ul_req_body->number_of_pdus++;
|
|
} // if (is_harq)
|
|
|
|
ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG;
|
|
} // for (int UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; 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_info_t *UE_info = &RC.mac[module_idP]->UE_info;
|
|
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_info->UE_sched_ctrl[UE_id].ul_failure_timer > 0) &&
|
|
(UE_info->UE_sched_ctrl[UE_id].ul_out_of_sync == 0)) {
|
|
if (UE_info->UE_sched_ctrl[UE_id].ul_failure_timer == 1)
|
|
LOG_I(MAC, "UE %d rnti %x: UL Failure timer %d \n", UE_id, rnti,
|
|
UE_info->UE_sched_ctrl[UE_id].ul_failure_timer);
|
|
|
|
if (UE_info->UE_sched_ctrl[UE_id].ra_pdcch_order_sent == 0) {
|
|
UE_info->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.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG;
|
|
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_info->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++;
|
|
DL_req[CC_id].dl_config_request_body.tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG;
|
|
DL_req[CC_id].sfn_sf = frameP<<4 | subframeP;
|
|
LOG_D(MAC,
|
|
"UE %d rnti %x: sending PDCCH order for RAPROC (failure timer %d), resource_block_coding %d \n",
|
|
UE_id, rnti,
|
|
UE_info->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_D(MAC,
|
|
"UE %d rnti %x: sent PDCCH order for RAPROC waiting (failure timer %d) \n",
|
|
UE_id, rnti,
|
|
UE_info->UE_sched_ctrl[UE_id].ul_failure_timer);
|
|
|
|
if ((UE_info->UE_sched_ctrl[UE_id].ul_failure_timer % 80) == 0) UE_info->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 0; // resend every 8 frames
|
|
}
|
|
|
|
UE_info->UE_sched_ctrl[UE_id].ul_failure_timer++;
|
|
|
|
// check threshold
|
|
if (UE_info->UE_sched_ctrl[UE_id].ul_failure_timer > 4000) {
|
|
// note: probably ul_failure_timer should be less than UE radio link failure time(see T310/N310/N311)
|
|
if (NODE_IS_DU(RC.rrc[module_idP]->node_type)) {
|
|
MessageDef *m = itti_alloc_new_message(TASK_MAC_ENB, 0, F1AP_UE_CONTEXT_RELEASE_REQ);
|
|
F1AP_UE_CONTEXT_RELEASE_REQ(m).rnti = rnti;
|
|
F1AP_UE_CONTEXT_RELEASE_REQ(m).cause = F1AP_CAUSE_RADIO_NETWORK;
|
|
F1AP_UE_CONTEXT_RELEASE_REQ(m).cause_value = 1; // 1 = F1AP_CauseRadioNetwork_rl_failure
|
|
F1AP_UE_CONTEXT_RELEASE_REQ(m).rrc_container = NULL;
|
|
F1AP_UE_CONTEXT_RELEASE_REQ(m).rrc_container_length = 0;
|
|
itti_send_msg_to_task(TASK_DU_F1, module_idP, m);
|
|
} else {
|
|
// 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_info->UE_sched_ctrl[UE_id].ul_failure_timer = 0;
|
|
UE_info->UE_sched_ctrl[UE_id].ul_out_of_sync = 1;
|
|
}
|
|
} // ul_failure_timer>0
|
|
|
|
UE_info->UE_sched_ctrl[UE_id].uplane_inactivity_timer++;
|
|
|
|
if((U_PLANE_INACTIVITY_VALUE != 0) && (UE_info->UE_sched_ctrl[UE_id].uplane_inactivity_timer > (U_PLANE_INACTIVITY_VALUE * 10))) {
|
|
LOG_D(MAC,"UE %d rnti %x: U-Plane Failure after repeated PDCCH orders: Triggering RRC \n",UE_id,rnti);
|
|
mac_eNB_rrc_uplane_failure(module_idP,CC_id,frameP,subframeP,rnti);
|
|
UE_info->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0;
|
|
}// time > 60s
|
|
}
|
|
|
|
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[CC_idP][subframeP];
|
|
nfapi_tx_request_t *TX_req = &eNB->TX_req[0];
|
|
eNB->pdu_index[CC_idP] = 0;
|
|
|
|
if (NFAPI_MODE == NFAPI_MODE_PNF || NFAPI_MODE == NFAPI_MONOLITHIC) { // monolithic or PNF
|
|
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;
|
|
DL_req[CC_idP].sfn_sf = subframeP + (frameP<<4);
|
|
HI_DCI0_req->hi_dci0_request_body.sfnsf = subframeP + (frameP<<4);
|
|
HI_DCI0_req->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 *mac = RC.mac[module_idP];
|
|
|
|
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
|
|
nfapi_ul_config_request_t *ul_req_tmp = &mac->UL_req_tmp[CC_id][subframeP];
|
|
nfapi_ul_config_request_t *ul_req = &mac->UL_req[CC_id];
|
|
nfapi_ul_config_request_pdu_t *ul_req_pdu = ul_req->ul_config_request_body.ul_config_pdu_list;
|
|
*ul_req = *ul_req_tmp;
|
|
// Restore the pointer
|
|
ul_req->ul_config_request_body.ul_config_pdu_list = ul_req_pdu;
|
|
ul_req->sfn_sf = (frameP<<4) + subframeP;
|
|
ul_req_tmp->ul_config_request_body.number_of_pdus = 0;
|
|
|
|
if (ul_req->ul_config_request_body.number_of_pdus>0) {
|
|
LOG_D(MAC, "%s() active NOW (frameP:%d subframeP:%d) pdus:%d\n", __FUNCTION__, frameP, subframeP, ul_req->ul_config_request_body.number_of_pdus);
|
|
}
|
|
|
|
memcpy((void *)ul_req->ul_config_request_body.ul_config_pdu_list,
|
|
(void *)ul_req_tmp->ul_config_request_body.ul_config_pdu_list,
|
|
ul_req->ul_config_request_body.number_of_pdus*sizeof(nfapi_ul_config_request_pdu_t));
|
|
}
|
|
}
|
|
|
|
extern int16_t find_dlsch(uint16_t rnti, PHY_VARS_eNB *eNB,find_type_t type);
|
|
extern int16_t find_ulsch(uint16_t rnti, PHY_VARS_eNB *eNB,find_type_t type);
|
|
extern void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch);
|
|
extern void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch);
|
|
|
|
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;
|
|
rnti_t rnti = 0;
|
|
int CC_id = 0;
|
|
int UE_id = -1;
|
|
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
|
UE_info_t *UE_info = &(eNB->UE_info);
|
|
COMMON_channels_t *cc = eNB->common_channels;
|
|
UE_sched_ctrl_t *UE_scheduling_control = NULL;
|
|
start_meas(&(eNB->eNB_scheduler));
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, VCD_FUNCTION_IN);
|
|
eNB->frame = frameP;
|
|
eNB->subframe = subframeP;
|
|
|
|
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);
|
|
cc[CC_id].mcch_active = 0;
|
|
clear_nfapi_information(RC.mac[module_idP], CC_id, frameP, subframeP);
|
|
|
|
/* hack: skip BCH RBs in subframe 0 for DL scheduling,
|
|
* because with high MCS we may exceed code rate 0.93
|
|
* when using those RBs (36.213 7.1.7 says the UE may
|
|
* skip decoding if the code rate is higher than 0.93)
|
|
* TODO: remove this hack, deal with physical bits properly
|
|
* i.e. reduce MCS in the scheduler if code rate > 0.93
|
|
*/
|
|
if (subframeP == 0) {
|
|
int i;
|
|
int bw = cc[CC_id].mib->message.dl_Bandwidth;
|
|
/* start and count defined for RBs: 6, 15, 25, 50, 75, 100 */
|
|
int start[6] = { 0, 4, 9, 22, 34, 47 };
|
|
int count[6] = { 6, 7, 7, 6, 7, 6 };
|
|
for (i = 0; i < count[bw]; i++)
|
|
cc[CC_id].vrb_map[start[bw] + i] = 1;
|
|
}
|
|
}
|
|
|
|
/* Refresh UE list based on UEs dropped by PHY in previous subframe */
|
|
for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) {
|
|
if (UE_info->active[UE_id]) {
|
|
rnti = UE_RNTI(module_idP, UE_id);
|
|
CC_id = UE_PCCID(module_idP, UE_id);
|
|
UE_scheduling_control = &(UE_info->UE_sched_ctrl[UE_id]);
|
|
|
|
/* to be merged with MAC_stats.log generation. probably redundant
|
|
if (((frameP & 127) == 0) && (subframeP == 0)) {
|
|
double total_bler;
|
|
if(UE_scheduling_control->pusch_rx_num[CC_id] == 0 && UE_scheduling_control->pusch_rx_error_num[CC_id] == 0) {
|
|
total_bler = 0;
|
|
}
|
|
else {
|
|
total_bler = (double)UE_scheduling_control->pusch_rx_error_num[CC_id] / (double)(UE_scheduling_control->pusch_rx_error_num[CC_id] + UE_scheduling_control->pusch_rx_num[CC_id]) * 100;
|
|
}
|
|
LOG_I(MAC,"UE %x : %s, PHR %d DLCQI %d PUSCH %d PUCCH %d RLC disc %d UL-stat rcv %lu err %lu bler %lf mcsoff %d bsr %u sched %u tbs %lu cnt %u , DL-stat tbs %lu cnt %u rb %u buf %u 1st %u ret %u ri %d\n",
|
|
rnti,
|
|
UE_scheduling_control->ul_out_of_sync == 0 ? "in synch" : "out of sync",
|
|
UE_info->UE_template[CC_id][UE_id].phr_info,
|
|
UE_scheduling_control->dl_cqi[CC_id],
|
|
UE_scheduling_control->pusch_snr_avg[CC_id],
|
|
UE_scheduling_control->pucch1_snr[CC_id],
|
|
UE_scheduling_control->rlc_out_of_resources_cnt,
|
|
UE_scheduling_control->pusch_rx_num[CC_id],
|
|
UE_scheduling_control->pusch_rx_error_num[CC_id],
|
|
total_bler,
|
|
UE_scheduling_control->mcs_offset[CC_id],
|
|
UE_info->UE_template[CC_id][UE_id].estimated_ul_buffer,
|
|
UE_info->UE_template[CC_id][UE_id].scheduled_ul_bytes,
|
|
UE_info->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes_rx,
|
|
UE_info->eNB_UE_stats[CC_id][UE_id].total_num_pdus_rx,
|
|
UE_info->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes,
|
|
UE_info->eNB_UE_stats[CC_id][UE_id].total_num_pdus,
|
|
UE_info->eNB_UE_stats[CC_id][UE_id].total_rbs_used,
|
|
#if defined(PRE_SCD_THREAD)
|
|
UE_info->UE_template[CC_id][UE_id].dl_buffer_total,
|
|
#else
|
|
0,
|
|
#endif
|
|
UE_scheduling_control->first_cnt[CC_id],
|
|
UE_scheduling_control->ret_cnt[CC_id],
|
|
UE_scheduling_control->aperiodic_ri_received[CC_id]
|
|
);
|
|
}
|
|
*/
|
|
RC.eNB[module_idP][CC_id]->pusch_stats_bsr[UE_id][(frameP * 10) + subframeP] = -63;
|
|
|
|
if (UE_id == UE_info->list.head) {
|
|
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR, RC.eNB[module_idP][CC_id]->pusch_stats_bsr[UE_id][(frameP * 10) + subframeP]);
|
|
}
|
|
|
|
/* Set and increment CDRX related timers */
|
|
if (UE_scheduling_control->cdrx_configured == TRUE) {
|
|
boolean_t harq_active_time_condition = FALSE;
|
|
UE_TEMPLATE *UE_template = NULL;
|
|
unsigned long active_time_condition = 0; // variable used only for tracing purpose
|
|
|
|
/* (UL and DL) HARQ RTT timers and DRX retransmission timers */
|
|
for (int harq_process_id = 0; harq_process_id < 8; harq_process_id++) {
|
|
/* DL asynchronous HARQ process */
|
|
if (UE_scheduling_control->drx_retransmission_timer[harq_process_id] > 0) {
|
|
UE_scheduling_control->drx_retransmission_timer[harq_process_id]++;
|
|
|
|
if (UE_scheduling_control->drx_retransmission_timer[harq_process_id] > UE_scheduling_control->drx_retransmission_timer_thres[harq_process_id]) {
|
|
UE_scheduling_control->drx_retransmission_timer[harq_process_id] = 0;
|
|
}
|
|
}
|
|
|
|
if (UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] > 0) {
|
|
UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id]++;
|
|
|
|
if (UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] > 8) {
|
|
/* Note: here drx_retransmission_timer is restarted instead of started in the specification */
|
|
UE_scheduling_control->drx_retransmission_timer[harq_process_id] = 1; // started when HARQ RTT timer expires
|
|
UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] = 0;
|
|
}
|
|
}
|
|
|
|
/* UL asynchronous HARQ process: only UL HARQ RTT timer is implemented (hence not implemented) */
|
|
if (UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] > 0) {
|
|
UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id]++;
|
|
|
|
if (UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] > 4) {
|
|
/*
|
|
* TODO: implement the handling of UL asynchronous HARQ
|
|
* drx_ULRetransmissionTimer should be (re)started here
|
|
*/
|
|
UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] = 0;
|
|
}
|
|
}
|
|
|
|
/* UL synchronous HARQ process */
|
|
if (UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id] > 0) {
|
|
UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id]++;
|
|
|
|
if (UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id] > 5) {
|
|
harq_active_time_condition = TRUE;
|
|
UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id] = 0;
|
|
active_time_condition = 5; // for tracing purpose
|
|
}
|
|
}
|
|
}
|
|
|
|
/* On duration timer */
|
|
if (UE_scheduling_control->on_duration_timer > 0) {
|
|
UE_scheduling_control->on_duration_timer++;
|
|
|
|
if (UE_scheduling_control->on_duration_timer > UE_scheduling_control->on_duration_timer_thres) {
|
|
UE_scheduling_control->on_duration_timer = 0;
|
|
}
|
|
}
|
|
|
|
/* DRX inactivity timer */
|
|
if (UE_scheduling_control->drx_inactivity_timer > 0) {
|
|
UE_scheduling_control->drx_inactivity_timer++;
|
|
|
|
if (UE_scheduling_control->drx_inactivity_timer > (UE_scheduling_control->drx_inactivity_timer_thres + 1)) {
|
|
/* Note: the +1 on the threshold is due to information in table C-1 of 36.321 */
|
|
UE_scheduling_control->drx_inactivity_timer = 0;
|
|
|
|
/* When timer expires switch into short or long DRX cycle */
|
|
if (UE_scheduling_control->drx_shortCycle_timer_thres > 0) {
|
|
UE_scheduling_control->in_short_drx_cycle = TRUE;
|
|
UE_scheduling_control->drx_shortCycle_timer = 0;
|
|
UE_scheduling_control->in_long_drx_cycle = FALSE;
|
|
} else {
|
|
UE_scheduling_control->in_long_drx_cycle = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Short DRX Cycle */
|
|
if (UE_scheduling_control->in_short_drx_cycle == TRUE) {
|
|
UE_scheduling_control->drx_shortCycle_timer++;
|
|
|
|
/* When the Short DRX cycles are over, switch to long DRX cycle */
|
|
if (UE_scheduling_control->drx_shortCycle_timer > UE_scheduling_control->drx_shortCycle_timer_thres) {
|
|
UE_scheduling_control->drx_shortCycle_timer = 0;
|
|
UE_scheduling_control->in_short_drx_cycle = FALSE;
|
|
UE_scheduling_control->in_long_drx_cycle = TRUE;
|
|
UE_scheduling_control->drx_longCycle_timer = 0;
|
|
}
|
|
} else {
|
|
UE_scheduling_control->drx_shortCycle_timer = 0;
|
|
}
|
|
|
|
/* Long DRX Cycle */
|
|
if (UE_scheduling_control->in_long_drx_cycle == TRUE) {
|
|
UE_scheduling_control->drx_longCycle_timer++;
|
|
|
|
if (UE_scheduling_control->drx_longCycle_timer > UE_scheduling_control->drx_longCycle_timer_thres) {
|
|
UE_scheduling_control->drx_longCycle_timer = 1;
|
|
}
|
|
} else {
|
|
UE_scheduling_control->drx_longCycle_timer = 0;
|
|
}
|
|
|
|
/* Check for error cases */
|
|
if ((UE_scheduling_control->in_short_drx_cycle == TRUE) && (UE_scheduling_control->in_long_drx_cycle == TRUE)) {
|
|
LOG_E(MAC, "Error in C-DRX: UE id %d is in both short and long DRX cycle. Should not happen. Back it to long cycle only\n", UE_id);
|
|
UE_scheduling_control->in_short_drx_cycle = FALSE;
|
|
}
|
|
|
|
/* Condition to start On Duration Timer */
|
|
if (UE_scheduling_control->in_short_drx_cycle == TRUE && UE_scheduling_control->on_duration_timer == 0) {
|
|
if (((frameP * 10) + subframeP) % (UE_scheduling_control->short_drx_cycle_duration) ==
|
|
(UE_scheduling_control->drx_start_offset) % (UE_scheduling_control->short_drx_cycle_duration)) {
|
|
UE_scheduling_control->on_duration_timer = 1;
|
|
}
|
|
} else if (UE_scheduling_control->in_long_drx_cycle == TRUE && UE_scheduling_control->on_duration_timer == 0) {
|
|
if (((frameP * 10) + subframeP) % (UE_scheduling_control->drx_longCycle_timer_thres) ==
|
|
(UE_scheduling_control->drx_start_offset)) {
|
|
UE_scheduling_control->on_duration_timer = 1;
|
|
}
|
|
}
|
|
|
|
/* Update Active Time status of UE
|
|
* Based on 36.321 5.7 the differents conditions for the UE to be in Acttive Should be check ONLY
|
|
* here for the current subframe. The variable 'UE_scheduling_control->in_active_time' should be updated
|
|
* ONLY here. The variable can then be used for testing the actual state of the UE for scheduling purpose.
|
|
*/
|
|
UE_template = &(UE_info->UE_template[CC_id][UE_id]);
|
|
|
|
/* (a)synchronous HARQ processes handling for Active Time */
|
|
for (int harq_process_id = 0; harq_process_id < 8; harq_process_id++) {
|
|
if (UE_scheduling_control->drx_retransmission_timer[harq_process_id] > 0) {
|
|
harq_active_time_condition = TRUE;
|
|
active_time_condition = 2; // for tracing purpose
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Active time conditions */
|
|
if (UE_scheduling_control->on_duration_timer > 0 ||
|
|
UE_scheduling_control->drx_inactivity_timer > 1 ||
|
|
harq_active_time_condition ||
|
|
UE_template->ul_SR > 0) {
|
|
UE_scheduling_control->in_active_time = TRUE;
|
|
} else {
|
|
UE_scheduling_control->in_active_time = FALSE;
|
|
}
|
|
|
|
/* BEGIN VCD */
|
|
if (UE_id == 0) {
|
|
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_ON_DURATION_TIMER, (unsigned long) UE_scheduling_control->on_duration_timer);
|
|
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_INACTIVITY, (unsigned long) UE_scheduling_control->drx_inactivity_timer);
|
|
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_SHORT_CYCLE, (unsigned long) UE_scheduling_control->drx_shortCycle_timer);
|
|
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_LONG_CYCLE, (unsigned long) UE_scheduling_control->drx_longCycle_timer);
|
|
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_RETRANSMISSION_HARQ0, (unsigned long) UE_scheduling_control->drx_retransmission_timer[0]);
|
|
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_ACTIVE_TIME, (unsigned long) UE_scheduling_control->in_active_time);
|
|
|
|
/* For tracing purpose */
|
|
if (UE_template->ul_SR > 0) {
|
|
active_time_condition = 1;
|
|
} else if ((UE_scheduling_control->on_duration_timer > 0) && (active_time_condition == 0)) {
|
|
active_time_condition = 3;
|
|
} else if ((UE_scheduling_control->drx_inactivity_timer > 1) && (active_time_condition == 0)) {
|
|
active_time_condition = 4;
|
|
}
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_ACTIVE_TIME_CONDITION, (unsigned long) active_time_condition);
|
|
}
|
|
|
|
/* END VCD */
|
|
|
|
/* DCI0 ongoing timer */
|
|
if (UE_scheduling_control->dci0_ongoing_timer > 0) {
|
|
if (UE_scheduling_control->dci0_ongoing_timer > 7) {
|
|
UE_scheduling_control->dci0_ongoing_timer = 0;
|
|
} else {
|
|
UE_scheduling_control->dci0_ongoing_timer++;
|
|
}
|
|
}
|
|
} else { // else: CDRX not configured
|
|
/* Note: (UL) HARQ RTT timers processing is done here and can be used by other features than CDRX */
|
|
/* HARQ RTT timers */
|
|
for (int harq_process_id = 0; harq_process_id < 8; harq_process_id++) {
|
|
if (UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] > 0) {
|
|
UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id]++;
|
|
|
|
if (UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] > 8) {
|
|
UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] = 0;
|
|
}
|
|
}
|
|
|
|
if (UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] > 0) {
|
|
UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id]++;
|
|
|
|
if (UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] > 4) {
|
|
UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] = 0;
|
|
}
|
|
}
|
|
} // end loop harq process
|
|
} // end else CDRX not configured
|
|
|
|
/* Increment these timers, they are cleared when we receive an sdu */
|
|
UE_scheduling_control->ul_inactivity_timer++;
|
|
UE_scheduling_control->cqi_req_timer++;
|
|
LOG_D(MAC, "UE %d/%x : ul_inactivity %d, cqi_req %d\n",
|
|
UE_id,
|
|
rnti,
|
|
UE_scheduling_control->ul_inactivity_timer,
|
|
UE_scheduling_control->cqi_req_timer);
|
|
check_ul_failure(module_idP, CC_id, UE_id, frameP, subframeP);
|
|
|
|
if (UE_scheduling_control->ue_reestablishment_reject_timer > 0) {
|
|
UE_scheduling_control->ue_reestablishment_reject_timer++;
|
|
|
|
if (UE_scheduling_control->ue_reestablishment_reject_timer >= UE_scheduling_control->ue_reestablishment_reject_timer_thres) {
|
|
UE_scheduling_control->ue_reestablishment_reject_timer = 0;
|
|
|
|
/* Clear reestablish_rnti_map */
|
|
if (UE_scheduling_control->ue_reestablishment_reject_timer_thres > 20) {
|
|
for (int ue_id_l = 0; ue_id_l < MAX_MOBILES_PER_ENB; ue_id_l++) {
|
|
if (reestablish_rnti_map[ue_id_l][0] == rnti) {
|
|
/* Clear currentC-RNTI from map */
|
|
reestablish_rnti_map[ue_id_l][0] = 0;
|
|
reestablish_rnti_map[ue_id_l][1] = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, rnti, 0, 0,module_idP);
|
|
rrc_rlc_remove_ue(&ctxt);
|
|
pdcp_remove_UE(&ctxt);
|
|
}
|
|
|
|
/* Note: This should not be done in the MAC! */
|
|
/*
|
|
for (int ii=0; ii<MAX_MOBILES_PER_ENB; ii++) {
|
|
LTE_eNB_ULSCH_t *ulsch = RC.eNB[module_idP][CC_id]->ulsch[ii];
|
|
|
|
if((ulsch != NULL) && (ulsch->rnti == rnti)) {
|
|
void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch);
|
|
LOG_I(MAC, "clean_eNb_ulsch UE %x \n", rnti);
|
|
clean_eNb_ulsch(ulsch);
|
|
}
|
|
}
|
|
|
|
for (int ii=0; ii<MAX_MOBILES_PER_ENB; ii++) {
|
|
LTE_eNB_DLSCH_t *dlsch = RC.eNB[module_idP][CC_id]->dlsch[ii][0];
|
|
|
|
if((dlsch != NULL) && (dlsch->rnti == rnti)) {
|
|
void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch);
|
|
LOG_I(MAC, "clean_eNb_dlsch UE %x \n", rnti);
|
|
clean_eNb_dlsch(dlsch);
|
|
}
|
|
}
|
|
*/
|
|
|
|
int id;
|
|
|
|
// clean ULSCH entries for rnti
|
|
id = find_ulsch(rnti,RC.eNB[module_idP][CC_id],SEARCH_EXIST);
|
|
if (id>=0) clean_eNb_ulsch(RC.eNB[module_idP][CC_id]->ulsch[id]);
|
|
|
|
// clean DLSCH entries for rnti
|
|
id = find_dlsch(rnti,RC.eNB[module_idP][CC_id],SEARCH_EXIST);
|
|
if (id>=0) clean_eNb_dlsch(RC.eNB[module_idP][CC_id]->dlsch[id][0]);
|
|
|
|
for (int j = 0; j < 10; j++) {
|
|
nfapi_ul_config_request_body_t *ul_req_tmp = NULL;
|
|
ul_req_tmp = &(eNB->UL_req_tmp[CC_id][j].ul_config_request_body);
|
|
|
|
if (ul_req_tmp) {
|
|
int pdu_number = ul_req_tmp->number_of_pdus;
|
|
|
|
for (int pdu_index = pdu_number-1; pdu_index >= 0; pdu_index--) {
|
|
if (ul_req_tmp->ul_config_pdu_list[pdu_index].ulsch_pdu.ulsch_pdu_rel8.rnti == rnti) {
|
|
LOG_I(MAC, "remove UE %x from ul_config_pdu_list %d/%d\n",
|
|
rnti,
|
|
pdu_index,
|
|
pdu_number);
|
|
|
|
if (pdu_index < pdu_number -1) {
|
|
memcpy(&ul_req_tmp->ul_config_pdu_list[pdu_index],
|
|
&ul_req_tmp->ul_config_pdu_list[pdu_index+1],
|
|
(pdu_number-1-pdu_index) * sizeof(nfapi_ul_config_request_pdu_t));
|
|
}
|
|
|
|
ul_req_tmp->number_of_pdus--;
|
|
}
|
|
} // end for pdu_index
|
|
} // end if (ul_req_tmp)
|
|
} // end for j
|
|
|
|
rrc_mac_remove_ue(module_idP,rnti);
|
|
} // end if (UE_scheduling_control->ue_reestablishment_reject_timer >= UE_scheduling_control->ue_reestablishment_reject_timer_thres)
|
|
} // end if (UE_scheduling_control->ue_reestablishment_reject_timer > 0)
|
|
} // end if UE active
|
|
} // end for loop on UE_id
|
|
|
|
#if (!defined(PRE_SCD_THREAD))
|
|
if (!NODE_IS_DU(RC.rrc[module_idP]->node_type)) {
|
|
void rlc_tick(int, int);
|
|
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frameP, subframeP, module_idP);
|
|
rlc_tick(frameP, subframeP);
|
|
pdcp_run(&ctxt);
|
|
pdcp_mbms_run(&ctxt);
|
|
rrc_rx_tx(&ctxt, CC_id);
|
|
}
|
|
#endif
|
|
|
|
int do_fembms_si=0;
|
|
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);
|
|
int(*schedule_mch)(module_id_t module_idP, uint8_t CC_id, frame_t frameP, sub_frame_t subframe) = NULL;
|
|
schedule_mch = schedule_MBMS_NFAPI;
|
|
if(schedule_mch){
|
|
mbsfn_status[CC_id] = schedule_mch(module_idP, CC_id, frameP, subframeP);
|
|
}
|
|
stop_meas(&RC.mac[module_idP]->schedule_mch);
|
|
}
|
|
if (cc[CC_id].FeMBMS_flag > 0) {
|
|
do_fembms_si = 1;
|
|
}
|
|
|
|
}
|
|
|
|
static int debug_flag = 0;
|
|
void (*schedule_ulsch_p)(module_id_t module_idP, frame_t frameP, sub_frame_t subframe) = NULL;
|
|
void (*schedule_ue_spec_p)(module_id_t module_idP, frame_t frameP, sub_frame_t subframe, int *mbsfn_flag) = NULL;
|
|
|
|
if (eNB->scheduler_mode == SCHED_MODE_DEFAULT) {
|
|
schedule_ulsch_p = schedule_ulsch;
|
|
schedule_ue_spec_p = schedule_dlsch;
|
|
} else if (eNB->scheduler_mode == SCHED_MODE_FAIR_RR) {
|
|
memset(dlsch_ue_select, 0, sizeof(dlsch_ue_select));
|
|
schedule_ulsch_p = schedule_ulsch_fairRR;
|
|
schedule_ue_spec_p = schedule_ue_spec_fairRR;
|
|
}
|
|
|
|
if(debug_flag == 0) {
|
|
LOG_E(MAC,"SCHED_MODE = %d\n", eNB->scheduler_mode);
|
|
debug_flag = 1;
|
|
}
|
|
|
|
/* This schedules MIB */
|
|
if(!do_fembms_si/*get_softmodem_params()->fembms*/){
|
|
if ((subframeP == 0) && (frameP & 3) == 0)
|
|
schedule_mib(module_idP, frameP, subframeP);
|
|
}else{
|
|
if ((subframeP == 0) && (frameP & 15) == 0 ){
|
|
schedule_fembms_mib(module_idP, frameP, subframeP);
|
|
//schedule_SI_MBMS(module_idP, frameP, subframeP);
|
|
}
|
|
}
|
|
|
|
if (get_softmodem_params()->phy_test == 0) {
|
|
/* This schedules SI for legacy LTE and eMTC starting in subframeP */
|
|
if(!do_fembms_si/*get_softmodem_params()->fembms*/)
|
|
schedule_SI(module_idP, frameP, subframeP);
|
|
else
|
|
schedule_SI_MBMS(module_idP, frameP, subframeP);
|
|
/* This schedules Paging in subframeP */
|
|
schedule_PCH(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) */
|
|
if (schedule_ulsch_p != NULL) {
|
|
schedule_ulsch_p(module_idP, frameP, subframeP);
|
|
} else {
|
|
LOG_E(MAC," %s %d: schedule_ulsch_p is NULL, function not called\n",
|
|
__FILE__,
|
|
__LINE__);
|
|
}
|
|
|
|
/* 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 for BR UE*/
|
|
schedule_ue_spec_br(module_idP, frameP, subframeP);
|
|
|
|
/* This schedules DLSCH in subframeP */
|
|
if (schedule_ue_spec_p != NULL) {
|
|
schedule_ue_spec_p(module_idP, frameP, subframeP, mbsfn_status);
|
|
} else {
|
|
LOG_E(MAC," %s %d: schedule_ue_spec_p is NULL, function not called\n",
|
|
__FILE__,
|
|
__LINE__);
|
|
}
|
|
} else {
|
|
schedule_ulsch_phy_test(module_idP,frameP,subframeP);
|
|
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++) {
|
|
if (cc[CC_id].tdd_Config == NULL || !(is_UL_sf(&cc[CC_id],subframeP))) {
|
|
int rc = allocate_CCEs(module_idP, CC_id, frameP, subframeP, 2);
|
|
if (rc < 0)
|
|
LOG_E(MAC, "%s() %4d.%d ERROR ALLOCATING CCEs\n", __func__, frameP, subframeP);
|
|
}
|
|
}
|
|
|
|
if (flexran_agent_get_mac_xface(module_idP) && subframeP == 9) {
|
|
flexran_agent_slice_update(module_idP);
|
|
}
|
|
if (flexran_agent_get_mac_xface(module_idP))
|
|
flexran_agent_get_mac_xface(module_idP)->flexran_agent_notify_tick(module_idP);
|
|
|
|
stop_meas(&(eNB->eNB_scheduler));
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, VCD_FUNCTION_OUT);
|
|
}
|