Files
openairinterface5g/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c
T
Cedric Roux 7757b9e7e7 import NFAPI work from David Price from Cisco (non-working commit, do not use it)
It has been chosen to not include the full history of commits
from David. He included a binary version of wireshark, probably
a modified one that understands NFAPI. Wireshark is released under
the GPL license, we cannot include it in the repository. We could
have done a next commit to remove this binary. But then it would
still be present in the history of commits, which may not be allowed.
And it would take space on disk. We could edit the history to remove
wireshark entirely. But this operation is too complicated.

There was also a pcap capture file, which has nothing to do in
the history of commits and would take space on disk. There again,
it's too difficult to edit the history to remove it.

There was a file .gitignore that was also removed.

The original history can be found on David's repository:
https://gitlab.eurecom.fr/daveprice/openairinterface5g/
The branch is: nfapi-ru-rau-split.

A copy of that branch has been included in the internal OAI
repository, for those who have access to it.
The branch is the same. The last commit ID is
9106438239e0bc626ff1fa1d97d911caadd0fbb9.

You can compare the current commit with the commit 9106...
to see what differs.

The current commit has to be considered non-working.
The commit following the current commit will fix problems with
the work in the current commit.

If you use git bisect, don't spend time analyzing the current
commit.
2018-01-15 11:32:30 +01:00

1773 lines
55 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_dlsch.c
* \brief procedures related to eNB for the DLSCH transport channel
* \author Navid Nikaein and Raymond Knopp
* \date 2010 - 2014
* \email: navid.nikaein@eurecom.fr
* \version 1.0
* @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/proto.h"
#include "LAYER2/MAC/extern.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"
#include "SIMULATION/TOOLS/defs.h" // for taus
#if defined(ENABLE_ITTI)
#include "intertask_interface.h"
#endif
#include "T.h"
#define ENABLE_MAC_PAYLOAD_DEBUG
//#define DEBUG_eNB_SCHEDULER 1
extern RAN_CONTEXT_t RC;
extern uint8_t nfapi_mode;
//------------------------------------------------------------------------------
void
add_ue_dlsch_info(module_id_t module_idP,
int CC_id,
int UE_id, sub_frame_t subframeP, UE_DLSCH_STATUS status)
//------------------------------------------------------------------------------
{
//LOG_D(MAC, "%s(module_idP:%d, CC_id:%d, UE_id:%d, subframeP:%d, status:%d) serving_num:%d rnti:%x\n", __FUNCTION__, module_idP, CC_id, UE_id, subframeP, status, eNB_dlsch_info[module_idP][CC_id][UE_id].serving_num, UE_RNTI(module_idP,UE_id));
eNB_dlsch_info[module_idP][CC_id][UE_id].rnti =
UE_RNTI(module_idP, UE_id);
// eNB_dlsch_info[module_idP][CC_id][ue_mod_idP].weight = weight;
eNB_dlsch_info[module_idP][CC_id][UE_id].subframe = subframeP;
eNB_dlsch_info[module_idP][CC_id][UE_id].status = status;
eNB_dlsch_info[module_idP][CC_id][UE_id].serving_num++;
}
//------------------------------------------------------------------------------
int
schedule_next_dlue(module_id_t module_idP, int CC_id,
sub_frame_t subframeP)
//------------------------------------------------------------------------------
{
int next_ue;
UE_list_t *UE_list = &RC.mac[module_idP]->UE_list;
for (next_ue = UE_list->head; next_ue >= 0;
next_ue = UE_list->next[next_ue]) {
if (eNB_dlsch_info[module_idP][CC_id][next_ue].status ==
S_DL_WAITING) {
return next_ue;
}
}
for (next_ue = UE_list->head; next_ue >= 0;
next_ue = UE_list->next[next_ue]) {
if (eNB_dlsch_info[module_idP][CC_id][next_ue].status ==
S_DL_BUFFERED) {
eNB_dlsch_info[module_idP][CC_id][next_ue].status =
S_DL_WAITING;
}
}
return (-1); //next_ue;
}
//------------------------------------------------------------------------------
unsigned char
generate_dlsch_header(unsigned char *mac_header,
unsigned char num_sdus,
unsigned short *sdu_lengths,
unsigned char *sdu_lcids,
unsigned char drx_cmd,
unsigned short timing_advance_cmd,
unsigned char *ue_cont_res_id,
unsigned char short_padding,
unsigned short post_padding)
//------------------------------------------------------------------------------
{
SCH_SUBHEADER_FIXED *mac_header_ptr =
(SCH_SUBHEADER_FIXED *) mac_header;
uint8_t first_element = 0, last_size = 0, i;
uint8_t mac_header_control_elements[16], *ce_ptr;
ce_ptr = &mac_header_control_elements[0];
// compute header components
if ((short_padding == 1) || (short_padding == 2)) {
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = SHORT_PADDING;
first_element = 1;
last_size = 1;
}
if (short_padding == 2) {
mac_header_ptr->E = 1;
mac_header_ptr++;
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = SHORT_PADDING;
last_size = 1;
}
if (drx_cmd != 255) {
if (first_element > 0) {
mac_header_ptr->E = 1;
mac_header_ptr++;
} else {
first_element = 1;
}
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = DRX_CMD;
last_size = 1;
}
if (timing_advance_cmd != 31) {
if (first_element > 0) {
mac_header_ptr->E = 1;
mac_header_ptr++;
} else {
first_element = 1;
}
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = TIMING_ADV_CMD;
last_size = 1;
// msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr);
((TIMING_ADVANCE_CMD *) ce_ptr)->R = 0;
AssertFatal(timing_advance_cmd < 64,
"timing_advance_cmd %d > 63\n", timing_advance_cmd);
((TIMING_ADVANCE_CMD *) ce_ptr)->TA = timing_advance_cmd; //(timing_advance_cmd+31)&0x3f;
LOG_D(MAC, "timing advance =%d (%d)\n", timing_advance_cmd,
((TIMING_ADVANCE_CMD *) ce_ptr)->TA);
ce_ptr += sizeof(TIMING_ADVANCE_CMD);
//msg("offset %d\n",ce_ptr-mac_header_control_elements);
}
if (ue_cont_res_id) {
if (first_element > 0) {
mac_header_ptr->E = 1;
/*
printf("[eNB][MAC] last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID);
*/
mac_header_ptr++;
} else {
first_element = 1;
}
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = UE_CONT_RES;
last_size = 1;
LOG_T(MAC,
"[eNB ][RAPROC] Generate contention resolution msg: %x.%x.%x.%x.%x.%x\n",
ue_cont_res_id[0], ue_cont_res_id[1], ue_cont_res_id[2],
ue_cont_res_id[3], ue_cont_res_id[4], ue_cont_res_id[5]);
memcpy(ce_ptr, ue_cont_res_id, 6);
ce_ptr += 6;
// msg("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements);
}
//msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr);
for (i = 0; i < num_sdus; i++) {
LOG_T(MAC, "[eNB] Generate DLSCH header num sdu %d len sdu %d\n",
num_sdus, sdu_lengths[i]);
if (first_element > 0) {
mac_header_ptr->E = 1;
/*msg("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID);
*/
mac_header_ptr += last_size;
//msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr);
} else {
first_element = 1;
}
if (sdu_lengths[i] < 128) {
((SCH_SUBHEADER_SHORT *) mac_header_ptr)->R = 0;
((SCH_SUBHEADER_SHORT *) mac_header_ptr)->E = 0;
((SCH_SUBHEADER_SHORT *) mac_header_ptr)->F = 0;
((SCH_SUBHEADER_SHORT *) mac_header_ptr)->LCID = sdu_lcids[i];
((SCH_SUBHEADER_SHORT *) mac_header_ptr)->L =
(unsigned char) sdu_lengths[i];
last_size = 2;
} else {
((SCH_SUBHEADER_LONG *) mac_header_ptr)->R = 0;
((SCH_SUBHEADER_LONG *) mac_header_ptr)->E = 0;
((SCH_SUBHEADER_LONG *) mac_header_ptr)->F = 1;
((SCH_SUBHEADER_LONG *) mac_header_ptr)->LCID = sdu_lcids[i];
((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_MSB =
((unsigned short) sdu_lengths[i] >> 8) & 0x7f;
((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_LSB =
(unsigned short) sdu_lengths[i] & 0xff;
((SCH_SUBHEADER_LONG *) mac_header_ptr)->padding = 0x00;
last_size = 3;
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,
"[eNB] generate long sdu, size %x (MSB %x, LSB %x)\n",
sdu_lengths[i],
((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_MSB,
((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_LSB);
#endif
}
}
/*
printf("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr);
printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID);
if (((SCH_SUBHEADER_FIXED*)mac_header_ptr)->LCID < UE_CONT_RES) {
if (((SCH_SUBHEADER_SHORT*)mac_header_ptr)->F == 0)
printf("F = 0, sdu len (L field) %d\n",(((SCH_SUBHEADER_SHORT*)mac_header_ptr)->L));
else
printf("F = 1, sdu len (L field) %d\n",(((SCH_SUBHEADER_LONG*)mac_header_ptr)->L));
}
*/
if (post_padding > 0) { // we have lots of padding at the end of the packet
mac_header_ptr->E = 1;
mac_header_ptr += last_size;
// add a padding element
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = SHORT_PADDING;
mac_header_ptr++;
} else { // no end of packet padding
// last SDU subhead is of fixed type (sdu length implicitly to be computed at UE)
mac_header_ptr++;
}
//msg("After subheaders %d\n",(uint8_t*)mac_header_ptr - mac_header);
if ((ce_ptr - mac_header_control_elements) > 0) {
// printf("Copying %d bytes for control elements\n",ce_ptr-mac_header_control_elements);
memcpy((void *) mac_header_ptr, mac_header_control_elements,
ce_ptr - mac_header_control_elements);
mac_header_ptr +=
(unsigned char) (ce_ptr - mac_header_control_elements);
}
//msg("After CEs %d\n",(uint8_t*)mac_header_ptr - mac_header);
return ((unsigned char *) mac_header_ptr - mac_header);
}
//------------------------------------------------------------------------------
void
set_ul_DAI(int module_idP, int UE_idP, int CC_idP, int frameP,
int subframeP)
//------------------------------------------------------------------------------
{
eNB_MAC_INST *eNB = RC.mac[module_idP];
UE_list_t *UE_list = &eNB->UE_list;
unsigned char DAI;
COMMON_channels_t *cc = &eNB->common_channels[CC_idP];
if (cc->tdd_Config != NULL) { //TDD
DAI = (UE_list->UE_template[CC_idP][UE_idP].DAI - 1) & 3;
LOG_D(MAC,
"[eNB %d] CC_id %d Frame %d, subframe %d: DAI %d for UE %d\n",
module_idP, CC_idP, frameP, subframeP, DAI, UE_idP);
// Save DAI for Format 0 DCI
switch (cc->tdd_Config->subframeAssignment) {
case 0:
// if ((subframeP==0)||(subframeP==1)||(subframeP==5)||(subframeP==6))
break;
case 1:
switch (subframeP) {
case 1:
UE_list->UE_template[CC_idP][UE_idP].DAI_ul[7] = DAI;
break;
case 4:
UE_list->UE_template[CC_idP][UE_idP].DAI_ul[8] = DAI;
break;
case 6:
UE_list->UE_template[CC_idP][UE_idP].DAI_ul[2] = DAI;
break;
case 9:
UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI;
break;
}
case 2:
// if ((subframeP==3)||(subframeP==8))
// UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI;
break;
case 3:
//if ((subframeP==6)||(subframeP==8)||(subframeP==0)) {
// LOG_D(MAC,"schedule_ue_spec: setting UL DAI to %d for subframeP %d => %d\n",DAI,subframeP, ((subframeP+8)%10)>>1);
// UE_list->UE_template[CC_idP][UE_idP].DAI_ul[((subframeP+8)%10)>>1] = DAI;
//}
switch (subframeP) {
case 5:
case 6:
case 1:
UE_list->UE_template[CC_idP][UE_idP].DAI_ul[2] = DAI;
break;
case 7:
case 8:
UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI;
break;
case 9:
case 0:
UE_list->UE_template[CC_idP][UE_idP].DAI_ul[4] = DAI;
break;
default:
break;
}
break;
case 4:
// if ((subframeP==8)||(subframeP==9))
// UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI;
break;
case 5:
// if (subframeP==8)
// UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI;
break;
case 6:
// if ((subframeP==1)||(subframeP==4)||(subframeP==6)||(subframeP==9))
// UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI;
break;
default:
break;
}
}
}
// changes to pre-processor for eMTC
//------------------------------------------------------------------------------
void
schedule_ue_spec(module_id_t module_idP,
frame_t frameP, sub_frame_t subframeP, int *mbsfn_flag)
//------------------------------------------------------------------------------
{
uint8_t CC_id;
int UE_id;
unsigned char aggregation;
mac_rlc_status_resp_t rlc_status;
unsigned char header_len_dcch = 0, header_len_dcch_tmp = 0;
unsigned char header_len_dtch = 0, header_len_dtch_tmp =
0, header_len_dtch_last = 0;
unsigned char ta_len = 0;
unsigned char sdu_lcids[NB_RB_MAX], lcid, offset, num_sdus = 0;
uint16_t nb_rb, nb_rb_temp, nb_available_rb;
uint16_t TBS, j, sdu_lengths[NB_RB_MAX], rnti, padding =
0, post_padding = 0;
unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES];
unsigned char round = 0;
unsigned char harq_pid = 0;
eNB_UE_STATS *eNB_UE_stats = NULL;
uint16_t sdu_length_total = 0;
eNB_MAC_INST *eNB = RC.mac[module_idP];
COMMON_channels_t *cc = eNB->common_channels;
UE_list_t *UE_list = &eNB->UE_list;
int continue_flag = 0;
int32_t normalized_rx_power, target_rx_power;
int32_t tpc = 1;
static int32_t tpc_accumulated = 0;
UE_sched_ctrl *ue_sched_ctl;
int mcs;
int i;
int min_rb_unit[MAX_NUM_CCs];
int N_RB_DL[MAX_NUM_CCs];
int total_nb_available_rb[MAX_NUM_CCs];
int N_RBG[MAX_NUM_CCs];
nfapi_dl_config_request_body_t *dl_req;
nfapi_dl_config_request_pdu_t *dl_config_pdu;
int tdd_sfa;
int ta_update;
#if 0
if (UE_list->head == -1) {
return;
}
#endif
start_meas(&eNB->schedule_dlsch);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_IN);
// for TDD: check that we have to act here, otherwise return
if (cc[0].tdd_Config) {
tdd_sfa = cc[0].tdd_Config->subframeAssignment;
switch (subframeP) {
case 0:
// always continue
break;
case 1:
return;
break;
case 2:
return;
break;
case 3:
if ((tdd_sfa != 2) && (tdd_sfa != 5))
return;
break;
case 4:
if ((tdd_sfa != 1) && (tdd_sfa != 2) && (tdd_sfa != 4)
&& (tdd_sfa != 5))
return;
break;
case 5:
break;
case 6:
case 7:
if ((tdd_sfa != 1) && (tdd_sfa != 2) && (tdd_sfa != 4)
&& (tdd_sfa != 5))
return;
break;
case 8:
if ((tdd_sfa != 2) && (tdd_sfa != 3) && (tdd_sfa != 4)
&& (tdd_sfa != 5))
return;
break;
case 9:
if ((tdd_sfa != 1) && (tdd_sfa != 3) && (tdd_sfa != 4)
&& (tdd_sfa != 6))
return;
break;
}
}
//weight = get_ue_weight(module_idP,UE_id);
aggregation = 2;
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
N_RB_DL[CC_id] = to_prb(cc[CC_id].mib->message.dl_Bandwidth);
min_rb_unit[CC_id] = get_min_rb_unit(module_idP, CC_id);
// get number of PRBs less those used by common channels
total_nb_available_rb[CC_id] = N_RB_DL[CC_id];
for (i = 0; i < N_RB_DL[CC_id]; i++)
if (cc[CC_id].vrb_map[i] != 0)
total_nb_available_rb[CC_id]--;
N_RBG[CC_id] = to_rbg(cc[CC_id].mib->message.dl_Bandwidth);
// store the global enb stats:
eNB->eNB_stats[CC_id].num_dlactive_UEs = UE_list->num_UEs;
eNB->eNB_stats[CC_id].available_prbs =
total_nb_available_rb[CC_id];
eNB->eNB_stats[CC_id].total_available_prbs +=
total_nb_available_rb[CC_id];
eNB->eNB_stats[CC_id].dlsch_bytes_tx = 0;
eNB->eNB_stats[CC_id].dlsch_pdus_tx = 0;
}
/// CALLING Pre_Processor for downlink scheduling (Returns estimation of RBs required by each UE and the allocation on sub-band)
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_IN);
start_meas(&eNB->schedule_dlsch_preprocessor);
dlsch_scheduler_pre_processor(module_idP,
frameP, subframeP, N_RBG, mbsfn_flag);
stop_meas(&eNB->schedule_dlsch_preprocessor);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_OUT);
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
//LOG_D(MAC, "doing schedule_ue_spec for CC_id %d\n", CC_id);
dl_req = &eNB->DL_req[CC_id].dl_config_request_body;
if (mbsfn_flag[CC_id] > 0)
continue;
for (UE_id = UE_list->head; UE_id >= 0;
UE_id = UE_list->next[UE_id]) {
continue_flag = 0; // reset the flag to allow allocation for the remaining UEs
rnti = UE_RNTI(module_idP, UE_id);
eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id];
ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
if (rnti == NOT_A_RNTI) {
LOG_D(MAC, "Cannot find rnti for UE_id %d (num_UEs %d)\n",
UE_id, UE_list->num_UEs);
continue_flag = 1;
}
if (eNB_UE_stats == NULL) {
LOG_D(MAC, "[eNB] Cannot find eNB_UE_stats\n");
continue_flag = 1;
}
if (continue_flag != 1) {
switch (get_tmode(module_idP, CC_id, UE_id)) {
case 1:
case 2:
case 7:
aggregation =
get_aggregation(get_bw_index(module_idP, CC_id),
ue_sched_ctl->dl_cqi[CC_id],
format1);
break;
case 3:
aggregation =
get_aggregation(get_bw_index(module_idP, CC_id),
ue_sched_ctl->dl_cqi[CC_id],
format2A);
break;
default:
LOG_W(MAC, "Unsupported transmission mode %d\n",
get_tmode(module_idP, CC_id, UE_id));
aggregation = 2;
}
}
/* if (continue_flag != 1 */
if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated
CCE_allocation_infeasible(module_idP, CC_id, 1, subframeP,
aggregation, rnti)) {
LOG_D(MAC,
"[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n",
module_idP, frameP, UE_id, CC_id);
continue_flag = 1; //to next user (there might be rbs availiable for other UEs in TM5
}
if (cc[CC_id].tdd_Config != NULL) { //TDD
set_ue_dai(subframeP,
UE_id,
CC_id,
cc[CC_id].tdd_Config->subframeAssignment,
UE_list);
// update UL DAI after DLSCH scheduling
set_ul_DAI(module_idP, UE_id, CC_id, frameP, subframeP);
}
if (continue_flag == 1) {
add_ue_dlsch_info(module_idP,
CC_id, UE_id, subframeP, S_DL_NONE);
continue;
}
#warning RK->CR This old API call has to be revisited for FAPI, or logic must be changed
#if 0
/* add "fake" DCI to have CCE_allocation_infeasible work properly for next allocations */
/* if we don't add it, next allocations may succeed but overall allocations may fail */
/* will be removed at the end of this function */
add_ue_spec_dci(&eNB->common_channels[CC_id].DCI_pdu, &(char[]) {
0}, rnti, 1, aggregation, 1, format1, 0);
#endif
nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id];
if (cc->tdd_Config)
harq_pid = ((frameP * 10) + subframeP) % 10;
else
harq_pid = ((frameP * 10) + subframeP) & 7;
round = ue_sched_ctl->round[CC_id][harq_pid];
UE_list->eNB_UE_stats[CC_id][UE_id].crnti = rnti;
UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status =
mac_eNB_get_rrc_status(module_idP, rnti);
UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid;
UE_list->eNB_UE_stats[CC_id][UE_id].harq_round = round;
if (UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status <
RRC_CONNECTED)
continue;
sdu_length_total = 0;
num_sdus = 0;
/*
DevCheck(((eNB_UE_stats->dl_cqi < MIN_CQI_VALUE) || (eNB_UE_stats->dl_cqi > MAX_CQI_VALUE)),
eNB_UE_stats->dl_cqi, MIN_CQI_VALUE, MAX_CQI_VALUE);
*/
if (nfapi_mode) {
eNB_UE_stats->dlsch_mcs1 = 10;//cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]];
}
else {
eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]];
}
eNB_UE_stats->dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1; //cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs);
// store stats
//UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi= eNB_UE_stats->dl_cqi;
// initializing the rb allocation indicator for each UE
for (j = 0; j < N_RBG[CC_id]; j++) {
UE_list->
UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]
= 0;
}
LOG_I(MAC,
"[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n",
module_idP, frameP, UE_id, CC_id, rnti, harq_pid, round,
nb_available_rb, ue_sched_ctl->dl_cqi[CC_id],
eNB_UE_stats->dlsch_mcs1,
UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status);
/* process retransmission */
if (round != 8) {
// get freq_allocation
nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid];
TBS =
get_TBS_DL(UE_list->
UE_template[CC_id][UE_id].oldmcs1[harq_pid],
nb_rb);
if (nb_rb <= nb_available_rb) {
if (cc[CC_id].tdd_Config != NULL) {
UE_list->UE_template[CC_id][UE_id].DAI++;
update_ul_dci(module_idP, CC_id, rnti,
UE_list->UE_template[CC_id][UE_id].
DAI);
LOG_D(MAC,
"DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n",
CC_id, subframeP, UE_id,
UE_list->UE_template[CC_id][UE_id].DAI);
}
if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) {
for (j = 0; j < N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band
UE_list->UE_template[CC_id][UE_id].
rballoc_subband[harq_pid][j] =
ue_sched_ctl->rballoc_sub_UE[CC_id][j];
}
} else {
nb_rb_temp = nb_rb;
j = 0;
while ((nb_rb_temp > 0) && (j < N_RBG[CC_id])) {
if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] ==
1) {
if (UE_list->
UE_template[CC_id]
[UE_id].rballoc_subband[harq_pid][j])
printf
("WARN: rballoc_subband not free for retrans?\n");
UE_list->
UE_template[CC_id]
[UE_id].rballoc_subband[harq_pid][j] =
ue_sched_ctl->rballoc_sub_UE[CC_id][j];
if ((j == N_RBG[CC_id] - 1) &&
((N_RB_DL[CC_id] == 25) ||
(N_RB_DL[CC_id] == 50))) {
nb_rb_temp =
nb_rb_temp - min_rb_unit[CC_id] +
1;
} else {
nb_rb_temp =
nb_rb_temp - min_rb_unit[CC_id];
}
}
j = j + 1;
}
}
nb_available_rb -= nb_rb;
/*
eNB->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb;
eNB->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id];
for(j=0; j<N_RBG[CC_id]; j++) {
eNB->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j];
}
*/
switch (get_tmode(module_idP, CC_id, UE_id)) {
case 1:
case 2:
case 7:
default:
LOG_I(MAC,"retransmission DL_REQ: rnti:%x\n",rnti);
dl_config_pdu =
&dl_req->dl_config_pdu_list[dl_req->
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_1;
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.aggregation_level =
get_aggregation(get_bw_index
(module_idP, CC_id),
ue_sched_ctl->dl_cqi[CC_id],
format1);
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
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.
harq_process = harq_pid;
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // dont adjust power when retransmitting
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.new_data_indicator_1 =
UE_list->UE_template[CC_id][UE_id].
oldNDI[harq_pid];
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 =
UE_list->UE_template[CC_id][UE_id].
oldmcs1[harq_pid];
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.redundancy_version_1 =
round & 3;
if (cc[CC_id].tdd_Config != NULL) { //TDD
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.downlink_assignment_index =
(UE_list->UE_template[CC_id][UE_id].DAI -
1) & 3;
LOG_D(MAC,
"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d, mcs %d\n",
module_idP, CC_id, harq_pid, round,
(UE_list->UE_template[CC_id][UE_id].DAI -
1),
UE_list->
UE_template[CC_id][UE_id].oldmcs1
[harq_pid]);
} else {
LOG_D(MAC,
"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, mcs %d\n",
module_idP, CC_id, harq_pid, round,
UE_list->
UE_template[CC_id][UE_id].oldmcs1
[harq_pid]);
}
if (!CCE_allocation_infeasible
(module_idP, CC_id, 1, subframeP,
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.aggregation_level, rnti)) {
dl_req->number_dci++;
dl_req->number_pdu++;
dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG;
eNB->DL_req[CC_id].sfn_sf = frameP<<4 | subframeP;
eNB->DL_req[CC_id].header.message_id = NFAPI_DL_CONFIG_REQUEST;
fill_nfapi_dlsch_config(eNB, dl_req, TBS, -1
/* retransmission, no pdu_index */
, rnti, 0, // type 0 allocation from 7.1.6 in 36.213
0, // virtual_resource_block_assignment_flag, unused here
0, // resource_block_coding, to be filled in later
getQm(UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]), round & 3, // redundancy version
1, // transport blocks
0, // transport block to codeword swap flag
cc[CC_id].p_eNB == 1 ? 0 : 1, // transmission_scheme
1, // number of layers
1, // number of subbands
// uint8_t codebook_index,
4, // UE category capacity
UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated->p_a, 0, // delta_power_offset for TM5
0, // ngap
0, // nprb
cc[CC_id].p_eNB == 1 ? 1 : 2, // transmission mode
0, //number of PRBs treated as one subband, not used here
0 // number of beamforming vectors, not used here
);
LOG_D(MAC,
"Filled NFAPI configuration for DCI/DLSCH %d, retransmission round %d\n",
eNB->pdu_index[CC_id], round);
program_dlsch_acknak(module_idP, CC_id, UE_id,
frameP, subframeP,
dl_config_pdu->
dci_dl_pdu.dci_dl_pdu_rel8.
cce_idx);
// No TX request for retransmission (check if null request for FAPI)
} else {
LOG_W(MAC,
"Frame %d, Subframe %d: Dropping DLSCH allocation for UE %d\%x, infeasible CCE allocation\n",
frameP, subframeP, UE_id, rnti);
}
}
add_ue_dlsch_info(module_idP,
CC_id, UE_id, subframeP,
S_DL_SCHEDULED);
//eNB_UE_stats->dlsch_trials[round]++;
UE_list->eNB_UE_stats[CC_id][UE_id].
num_retransmission += 1;
UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx =
nb_rb;
UE_list->eNB_UE_stats[CC_id][UE_id].
total_rbs_used_retx += nb_rb;
UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 =
eNB_UE_stats->dlsch_mcs1;
UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 =
eNB_UE_stats->dlsch_mcs1;
} else {
LOG_D(MAC,
"[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n",
module_idP, frameP, CC_id, UE_id);
}
} else { /* This is a potentially new SDU opportunity */
rlc_status.bytes_in_buffer = 0;
// Now check RLC information to compute number of required RBs
// get maximum TBS size for RLC request
TBS =
get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb);
// check first for RLC data on DCCH
// add the length for all the control elements (timing adv, drx, etc) : header + payload
if (ue_sched_ctl->ta_timer == 0) {
ta_update = ue_sched_ctl->ta_update;
/* if we send TA then set timer to not send it for a while */
if (ta_update != 31)
ue_sched_ctl->ta_timer = 20;
/* reset ta_update */
ue_sched_ctl->ta_update = 31;
} else {
ta_update = 31;
}
ta_len = (ta_update != 31) ? 2 : 0;
header_len_dcch = 2; // 2 bytes DCCH SDU subheader
if (TBS - ta_len - header_len_dcch > 0) {
rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, (TBS - ta_len - header_len_dcch)); // transport block set size
sdu_lengths[0] = 0;
if (rlc_status.bytes_in_buffer > 0) { // There is DCCH to transmit
LOG_D(MAC,
"[eNB %d] Frame %d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
module_idP, frameP, CC_id,
TBS - header_len_dcch);
sdu_lengths[0] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, TBS, //not used
(char *)
&dlsch_buffer
[0]);
T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP),
T_INT(CC_id), T_INT(rnti), T_INT(frameP),
T_INT(subframeP), T_INT(harq_pid), T_INT(DCCH),
T_INT(sdu_lengths[0]));
LOG_D(MAC,
"[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n",
module_idP, CC_id, sdu_lengths[0]);
sdu_length_total = sdu_lengths[0];
sdu_lcids[0] = DCCH;
UE_list->eNB_UE_stats[CC_id][UE_id].
num_pdu_tx[DCCH] += 1;
UE_list->
eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH]
+= sdu_lengths[0];
num_sdus = 1;
#ifdef DEBUG_eNB_SCHEDULER
LOG_T(MAC,
"[eNB %d][DCCH] CC_id %d Got %d bytes :",
module_idP, CC_id, sdu_lengths[0]);
for (j = 0; j < sdu_lengths[0]; j++) {
LOG_T(MAC, "%x ", dlsch_buffer[j]);
}
LOG_T(MAC, "\n");
#endif
} else {
header_len_dcch = 0;
sdu_length_total = 0;
}
}
// check for DCCH1 and update header information (assume 2 byte sub-header)
if (TBS - ta_len - header_len_dcch - sdu_length_total > 0) {
rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, (TBS - ta_len - header_len_dcch - sdu_length_total)); // transport block set size less allocations for timing advance and
// DCCH SDU
sdu_lengths[num_sdus] = 0;
if (rlc_status.bytes_in_buffer > 0) {
LOG_D(MAC,
"[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
module_idP, frameP, CC_id,
TBS - header_len_dcch - sdu_length_total);
sdu_lengths[num_sdus] += mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, TBS, //not used
(char *)
&dlsch_buffer
[sdu_length_total]);
T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP),
T_INT(CC_id), T_INT(rnti), T_INT(frameP),
T_INT(subframeP), T_INT(harq_pid),
T_INT(DCCH + 1), T_INT(sdu_lengths[num_sdus]));
sdu_lcids[num_sdus] = DCCH1;
sdu_length_total += sdu_lengths[num_sdus];
header_len_dcch += 2;
UE_list->eNB_UE_stats[CC_id][UE_id].
num_pdu_tx[DCCH1] += 1;
UE_list->
eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH1]
+= sdu_lengths[num_sdus];
num_sdus++;
#ifdef DEBUG_eNB_SCHEDULER
LOG_T(MAC,
"[eNB %d][DCCH1] CC_id %d Got %d bytes :",
module_idP, CC_id, sdu_lengths[num_sdus]);
for (j = 0; j < sdu_lengths[num_sdus]; j++) {
LOG_T(MAC, "%x ", dlsch_buffer[j]);
}
LOG_T(MAC, "\n");
#endif
}
}
// assume the max dtch header size, and adjust it later
header_len_dtch = 0;
header_len_dtch_last = 0; // the header length of the last mac sdu
// lcid has to be sorted before the actual allocation (similar struct as ue_list).
for (lcid = NB_RB_MAX - 1; lcid >= DTCH; lcid--) {
// TBD: check if the lcid is active
header_len_dtch += 3;
header_len_dtch_last = 3;
LOG_D(MAC,
"[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n",
module_idP, frameP, lcid, TBS,
TBS - ta_len - header_len_dcch -
sdu_length_total - header_len_dtch);
if (TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch > 0) { // NN: > 2 ?
rlc_status = mac_rlc_status_ind(module_idP,
rnti,
module_idP,
frameP,
subframeP,
ENB_FLAG_YES,
MBMS_FLAG_NO,
lcid,
TBS - ta_len -
header_len_dcch -
sdu_length_total -
header_len_dtch);
if (rlc_status.bytes_in_buffer > 0) {
LOG_D(MAC,
"[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d)\n",
module_idP, frameP,
TBS - header_len_dcch -
sdu_length_total - header_len_dtch, lcid,
header_len_dtch);
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, TBS, //not used
(char
*)
&dlsch_buffer
[sdu_length_total]);
T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP),
T_INT(CC_id), T_INT(rnti), T_INT(frameP),
T_INT(subframeP), T_INT(harq_pid),
T_INT(lcid), T_INT(sdu_lengths[num_sdus]));
LOG_D(MAC,
"[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n",
module_idP, sdu_lengths[num_sdus], lcid);
sdu_lcids[num_sdus] = lcid;
sdu_length_total += sdu_lengths[num_sdus];
UE_list->
eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid]
+= 1;
UE_list->
eNB_UE_stats[CC_id][UE_id].num_bytes_tx
[lcid] += sdu_lengths[num_sdus];
if (sdu_lengths[num_sdus] < 128) {
header_len_dtch--;
header_len_dtch_last--;
}
num_sdus++;
} // no data for this LCID
else {
header_len_dtch -= 3;
}
} // no TBS left
else {
header_len_dtch -= 3;
break;
}
}
if (header_len_dtch == 0)
header_len_dtch_last = 0;
// there is at least one SDU
// if (num_sdus > 0 ){
if ((sdu_length_total + header_len_dcch +
header_len_dtch) > 0) {
// Now compute number of required RBs for total sdu length
// Assume RAH format 2
// adjust header lengths
header_len_dcch_tmp = header_len_dcch;
header_len_dtch_tmp = header_len_dtch;
if (header_len_dtch == 0) {
header_len_dcch = (header_len_dcch > 0) ? 1 : 0; //header_len_dcch; // remove length field
} else {
header_len_dtch_last -= 1; // now use it to find how many bytes has to be removed for the last MAC SDU
header_len_dtch = (header_len_dtch > 0) ? header_len_dtch - header_len_dtch_last : header_len_dtch; // remove length field for the last SDU
}
mcs = eNB_UE_stats->dlsch_mcs1;
if (mcs == 0) {
nb_rb = 4; // don't let the TBS get too small
} else {
nb_rb = min_rb_unit[CC_id];
}
TBS = get_TBS_DL(mcs, nb_rb);
while (TBS <
(sdu_length_total + header_len_dcch +
header_len_dtch + ta_len)) {
nb_rb += min_rb_unit[CC_id]; //
if (nb_rb > nb_available_rb) { // if we've gone beyond the maximum number of RBs
// (can happen if N_RB_DL is odd)
TBS =
get_TBS_DL(eNB_UE_stats->dlsch_mcs1,
nb_available_rb);
nb_rb = nb_available_rb;
break;
}
TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_rb);
}
if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) {
for (j = 0; j < N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band
UE_list->UE_template[CC_id][UE_id].
rballoc_subband[harq_pid][j] =
ue_sched_ctl->rballoc_sub_UE[CC_id][j];
}
} else {
nb_rb_temp = nb_rb;
j = 0;
while ((nb_rb_temp > 0) && (j < N_RBG[CC_id])) {
if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] ==
1) {
UE_list->
UE_template[CC_id]
[UE_id].rballoc_subband[harq_pid][j] =
ue_sched_ctl->rballoc_sub_UE[CC_id][j];
if ((j == N_RBG[CC_id] - 1) &&
((N_RB_DL[CC_id] == 25) ||
(N_RB_DL[CC_id] == 50))) {
nb_rb_temp =
nb_rb_temp - min_rb_unit[CC_id] +
1;
} else {
nb_rb_temp =
nb_rb_temp - min_rb_unit[CC_id];
}
}
j = j + 1;
}
}
// decrease mcs until TBS falls below required length
while ((TBS >
(sdu_length_total + header_len_dcch +
header_len_dtch + ta_len)) && (mcs > 0)) {
mcs--;
TBS = get_TBS_DL(mcs, nb_rb);
}
// if we have decreased too much or we don't have enough RBs, increase MCS
while ((TBS <
(sdu_length_total + header_len_dcch +
header_len_dtch + ta_len))
&& (((ue_sched_ctl->dl_pow_off[CC_id] > 0)
&& (mcs < 28))
|| ((ue_sched_ctl->dl_pow_off[CC_id] == 0)
&& (mcs <= 15)))) {
mcs++;
TBS = get_TBS_DL(mcs, nb_rb);
}
LOG_D(MAC,
"dlsch_mcs before and after the rate matching = (%d, %d)\n",
eNB_UE_stats->dlsch_mcs1, mcs);
#ifdef DEBUG_eNB_SCHEDULER
LOG_D(MAC,
"[eNB %d] CC_id %d Generated DLSCH header (mcs %d, TBS %d, nb_rb %d)\n",
module_idP, CC_id, mcs, TBS, nb_rb);
// msg("[MAC][eNB ] Reminder of DLSCH with random data %d %d %d %d \n",
// TBS, sdu_length_total, offset, TBS-sdu_length_total-offset);
#endif
if ((TBS - header_len_dcch - header_len_dtch -
sdu_length_total - ta_len) <= 2) {
padding =
(TBS - header_len_dcch - header_len_dtch -
sdu_length_total - ta_len);
post_padding = 0;
} else {
padding = 0;
// adjust the header len
if (header_len_dtch == 0) {
header_len_dcch = header_len_dcch_tmp;
} else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2)))
header_len_dtch = header_len_dtch_tmp;
}
post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len; // 1 is for the postpadding header
}
offset = generate_dlsch_header((unsigned char *) UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], num_sdus, //num_sdus
sdu_lengths, //
sdu_lcids, 255, // no drx
ta_update, // timing advance
NULL, // contention res id
padding, post_padding);
//#ifdef DEBUG_eNB_SCHEDULER
if (1 || ta_update != 31) {
LOG_I(MAC,
"[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_dcch %d, header_dtch %d\n",
module_idP, frameP, UE_id, CC_id,
sdu_length_total, num_sdus, sdu_lengths[0],
sdu_lcids[0], offset, ta_update, padding,
post_padding, mcs, TBS, nb_rb,
header_len_dcch, header_len_dtch);
}
//#endif
#ifdef DEBUG_eNB_SCHEDULER
LOG_T(MAC, "[eNB %d] First 16 bytes of DLSCH : \n");
for (i = 0; i < 16; i++) {
LOG_T(MAC, "%x.", dlsch_buffer[i]);
}
LOG_T(MAC, "\n");
#endif
// cycle through SDUs and place in dlsch_buffer
memcpy(&UE_list->
DLSCH_pdu[CC_id][0][UE_id].payload[0][offset],
dlsch_buffer, sdu_length_total);
// memcpy(RC.mac[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]);
// fill remainder of DLSCH with random data
for (j = 0; j < (TBS - sdu_length_total - offset); j++) {
UE_list->DLSCH_pdu[CC_id][0][UE_id].
payload[0][offset + sdu_length_total + j] =
(char) (taus() & 0xff);
}
if (opt_enabled == 1) {
trace_pdu(1, (uint8_t *)
UE_list->DLSCH_pdu[CC_id][0][UE_id].
payload[0], TBS, module_idP, 3,
UE_RNTI(module_idP, UE_id), eNB->frame,
eNB->subframe, 0, 0);
LOG_D(OPT,
"[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n",
module_idP, CC_id, frameP,
UE_RNTI(module_idP, UE_id), TBS);
}
T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP),
T_INT(CC_id), T_INT(rnti), T_INT(frameP),
T_INT(subframeP), T_INT(harq_pid),
T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id].
payload[0], TBS));
UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] =
nb_rb;
add_ue_dlsch_info(module_idP,
CC_id, UE_id, subframeP,
S_DL_SCHEDULED);
// store stats
eNB->eNB_stats[CC_id].dlsch_bytes_tx +=
sdu_length_total;
eNB->eNB_stats[CC_id].dlsch_pdus_tx += 1;
UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb;
UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used +=
nb_rb;
UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 =
eNB_UE_stats->dlsch_mcs1;
UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = mcs;
UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS;
UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes =
TBS - sdu_length_total;
UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes +=
sdu_length_total;
UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes +=
TBS;
UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus +=
1;
if (cc[CC_id].tdd_Config != NULL) { // TDD
UE_list->UE_template[CC_id][UE_id].DAI++;
update_ul_dci(module_idP, CC_id, rnti,
UE_list->UE_template[CC_id][UE_id].
DAI);
}
// do PUCCH power control
// this is the normalized RX power
eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id];
/* TODO: fix how we deal with power, unit is not dBm, it's special from nfapi */
normalized_rx_power = ue_sched_ctl->pucch1_snr[CC_id];
target_rx_power = 208;
// this assumes accumulated tpc
// make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out
int32_t framex10psubframe =
UE_list->UE_template[CC_id][UE_id].
pucch_tpc_tx_frame * 10 +
UE_list->UE_template[CC_id][UE_id].
pucch_tpc_tx_subframe;
if (((framex10psubframe + 10) <= (frameP * 10 + subframeP)) || //normal case
((framex10psubframe > (frameP * 10 + subframeP)) && (((10240 - framex10psubframe + frameP * 10 + subframeP) >= 10)))) //frame wrap-around
if (ue_sched_ctl->pucch1_cqi_update[CC_id] == 1) {
ue_sched_ctl->pucch1_cqi_update[CC_id] = 0;
UE_list->
UE_template[CC_id]
[UE_id].pucch_tpc_tx_frame = frameP;
UE_list->
UE_template[CC_id]
[UE_id].pucch_tpc_tx_subframe = subframeP;
if (normalized_rx_power >
(target_rx_power + 4)) {
tpc = 0; //-1
tpc_accumulated--;
} else if (normalized_rx_power <
(target_rx_power - 4)) {
tpc = 2; //+1
tpc_accumulated++;
} else {
tpc = 1; //0
}
LOG_D(MAC,
"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n",
module_idP, frameP, subframeP, harq_pid,
tpc, tpc_accumulated,
normalized_rx_power, target_rx_power);
} // Po_PUCCH has been updated
else {
tpc = 1; //0
} // time to do TPC update
else {
tpc = 1; //0
}
dl_config_pdu =
&dl_req->dl_config_pdu_list[dl_req->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_1;
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.aggregation_level =
get_aggregation(get_bw_index(module_idP, CC_id),
ue_sched_ctl->dl_cqi[CC_id],
format1);
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.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
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.
harq_process = harq_pid;
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc; // dont adjust power when retransmitting
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.new_data_indicator_1 =
1 -
UE_list->UE_template[CC_id][UE_id].
oldNDI[harq_pid];
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs;
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.redundancy_version_1 = 0;
//deactivate second codeword
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_2 = 0;
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.redundancy_version_2 = 1;
if (cc[CC_id].tdd_Config != NULL) { //TDD
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.downlink_assignment_index =
(UE_list->UE_template[CC_id][UE_id].DAI -
1) & 3;
LOG_D(MAC,
"[eNB %d] Initial transmission CC_id %d : harq_pid %d, dai %d, mcs %d\n",
module_idP, CC_id, harq_pid,
(UE_list->UE_template[CC_id][UE_id].DAI - 1),
mcs);
} else {
LOG_D(MAC,
"[eNB %d] Initial transmission CC_id %d : harq_pid %d, mcs %d\n",
module_idP, CC_id, harq_pid, mcs);
}
LOG_D(MAC, "Checking feasibility pdu %d (new sdu)\n",
dl_req->number_pdu);
if (!CCE_allocation_infeasible
(module_idP, CC_id, 1, subframeP,
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.aggregation_level, rnti)) {
ue_sched_ctl->round[CC_id][harq_pid] = 0;
dl_req->number_dci++;
dl_req->number_pdu++;
dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG;
eNB->DL_req[CC_id].sfn_sf = frameP<<4 | subframeP;
eNB->DL_req[CC_id].header.message_id = NFAPI_DL_CONFIG_REQUEST;
// Toggle NDI for next time
LOG_D(MAC,
"CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n",
CC_id, frameP, subframeP, UE_id, rnti,
harq_pid,
UE_list->
UE_template[CC_id][UE_id].oldNDI[harq_pid]);
UE_list->UE_template[CC_id][UE_id].
oldNDI[harq_pid] =
1 -
UE_list->UE_template[CC_id][UE_id].
oldNDI[harq_pid];
UE_list->UE_template[CC_id][UE_id].
oldmcs1[harq_pid] = mcs;
UE_list->UE_template[CC_id][UE_id].
oldmcs2[harq_pid] = 0;
AssertFatal(UE_list->UE_template[CC_id]
[UE_id].physicalConfigDedicated !=
NULL,
"physicalConfigDedicated is NULL\n");
AssertFatal(UE_list->UE_template[CC_id]
[UE_id].
physicalConfigDedicated->pdsch_ConfigDedicated
!= NULL,
"physicalConfigDedicated->pdsch_ConfigDedicated is NULL\n");
fill_nfapi_dlsch_config(eNB, dl_req, TBS, eNB->pdu_index[CC_id], rnti, 0, // type 0 allocation from 7.1.6 in 36.213
0, // virtual_resource_block_assignment_flag, unused here
0, // resource_block_coding, to be filled in later
getQm(mcs), 0, // redundancy version
1, // transport blocks
0, // transport block to codeword swap flag
cc[CC_id].p_eNB == 1 ? 0 : 1, // transmission_scheme
1, // number of layers
1, // number of subbands
// uint8_t codebook_index,
4, // UE category capacity
UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated->p_a, 0, // delta_power_offset for TM5
0, // ngap
0, // nprb
cc[CC_id].p_eNB == 1 ? 1 : 2, // transmission mode
0, //number of PRBs treated as one subband, not used here
0 // number of beamforming vectors, not used here
);
eNB->TX_req[CC_id].sfn_sf =
fill_nfapi_tx_req(&eNB->
TX_req
[CC_id].tx_request_body,
(frameP * 10) + subframeP,
TBS, eNB->pdu_index[CC_id],
eNB->
UE_list.DLSCH_pdu[CC_id][0][(unsigned char)
UE_id].payload
[0]);
LOG_D(MAC,
"Filled NFAPI configuration for DCI/DLSCH/TXREQ %d, new SDU\n",
eNB->pdu_index[CC_id]);
eNB->pdu_index[CC_id]++;
program_dlsch_acknak(module_idP, CC_id, UE_id,
frameP, subframeP,
dl_config_pdu->
dci_dl_pdu.dci_dl_pdu_rel8.
cce_idx);
} else {
LOG_W(MAC,
"Frame %d, Subframe %d: Dropping DLSCH allocation for UE %d/%x, infeasible CCE allocations\n",
frameP, subframeP, UE_id, rnti);
}
} else { // There is no data from RLC or MAC header, so don't schedule
}
}
if (cc[CC_id].tdd_Config != NULL) { // TDD
set_ul_DAI(module_idP, UE_id, CC_id, frameP, subframeP);
}
} // UE_id loop
} // CC_id loop
fill_DLSCH_dci(module_idP, frameP, subframeP, mbsfn_flag);
stop_meas(&eNB->schedule_dlsch);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_OUT);
}
//------------------------------------------------------------------------------
void
fill_DLSCH_dci(module_id_t module_idP,
frame_t frameP, sub_frame_t subframeP, int *mbsfn_flagP)
//------------------------------------------------------------------------------
{
// loop over all allocated UEs and compute frequency allocations for PDSCH
int UE_id = -1;
uint8_t /* first_rb, */ nb_rb = 3;
rnti_t rnti;
//unsigned char *vrb_map;
uint8_t rballoc_sub[25];
//uint8_t number_of_subbands=13;
//unsigned char round;
unsigned char harq_pid;
int i;
int CC_id;
eNB_MAC_INST *eNB = RC.mac[module_idP];
UE_list_t *UE_list = &eNB->UE_list;
int N_RBG;
int N_RB_DL;
COMMON_channels_t *cc;
start_meas(&eNB->fill_DLSCH_dci);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
(VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI, VCD_FUNCTION_IN);
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
//LOG_D(MAC, "Doing fill DCI for CC_id %d\n", CC_id);
if (mbsfn_flagP[CC_id] > 0)
continue;
cc = &eNB->common_channels[CC_id];
N_RBG = to_rbg(cc->mib->message.dl_Bandwidth);
N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth);
// UE specific DCIs
for (UE_id = UE_list->head; UE_id >= 0;
UE_id = UE_list->next[UE_id]) {
LOG_T(MAC, "CC_id %d, UE_id: %d => status %d\n", CC_id, UE_id,
eNB_dlsch_info[module_idP][CC_id][UE_id].status);
if (eNB_dlsch_info[module_idP][CC_id][UE_id].status ==
S_DL_SCHEDULED) {
// clear scheduling flag
eNB_dlsch_info[module_idP][CC_id][UE_id].status =
S_DL_WAITING;
rnti = UE_RNTI(module_idP, UE_id);
if (cc->tdd_Config)
harq_pid = ((frameP * 10) + subframeP) % 10;
else
harq_pid = ((frameP * 10) + subframeP) & 7;
nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid];
/// Synchronizing rballoc with rballoc_sub
for (i = 0; i < N_RBG; i++) {
rballoc_sub[i] =
UE_list->
UE_template[CC_id][UE_id].rballoc_subband[harq_pid]
[i];
}
nfapi_dl_config_request_t *DL_req =
&RC.mac[module_idP]->DL_req[0];
nfapi_dl_config_request_pdu_t *dl_config_pdu;
for (i = 0;
i < DL_req[CC_id].dl_config_request_body.number_pdu;
i++) {
dl_config_pdu =
&DL_req[CC_id].
dl_config_request_body.dl_config_pdu_list[i];
if ((dl_config_pdu->pdu_type ==
NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)
&& (dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.
rnti == rnti)
&& (dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.dci_format != 1)) {
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.resource_block_coding =
allocate_prbs_sub(nb_rb, N_RB_DL, N_RBG,
rballoc_sub);
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.resource_allocation_type = 0;
} else
if ((dl_config_pdu->pdu_type ==
NFAPI_DL_CONFIG_DLSCH_PDU_TYPE)
&& (dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.
rnti == rnti)
&& (dl_config_pdu->dlsch_pdu.
dlsch_pdu_rel8.resource_allocation_type ==
0)) {
dl_config_pdu->dlsch_pdu.
dlsch_pdu_rel8.resource_block_coding =
allocate_prbs_sub(nb_rb, N_RB_DL, N_RBG,
rballoc_sub);
}
}
}
}
}
stop_meas(&eNB->fill_DLSCH_dci);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
(VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI, VCD_FUNCTION_OUT);
}
//------------------------------------------------------------------------------
unsigned char *get_dlsch_sdu(module_id_t module_idP,
int CC_id, frame_t frameP, rnti_t rntiP,
uint8_t TBindex)
//------------------------------------------------------------------------------
{
int UE_id;
eNB_MAC_INST *eNB = RC.mac[module_idP];
if (rntiP == SI_RNTI) {
LOG_D(MAC, "[eNB %d] CC_id %d Frame %d Get DLSCH sdu for BCCH \n",
module_idP, CC_id, frameP);
return ((unsigned char *) &eNB->common_channels[CC_id].
BCCH_pdu.payload[0]);
}
UE_id = find_UE_id(module_idP, rntiP);
if (UE_id != -1) {
LOG_D(MAC,
"[eNB %d] Frame %d: CC_id %d Get DLSCH sdu for rnti %x => UE_id %d\n",
module_idP, frameP, CC_id, rntiP, UE_id);
return ((unsigned char *) &eNB->
UE_list.DLSCH_pdu[CC_id][TBindex][UE_id].payload[0]);
} else {
LOG_E(MAC,
"[eNB %d] Frame %d: CC_id %d UE with RNTI %x does not exist\n",
module_idP, frameP, CC_id, rntiP);
return NULL;
}
}
//------------------------------------------------------------------------------
void
update_ul_dci(module_id_t module_idP,
uint8_t CC_idP, rnti_t rntiP, uint8_t daiP)
//------------------------------------------------------------------------------
{
nfapi_hi_dci0_request_t *HI_DCI0_req =
&RC.mac[module_idP]->HI_DCI0_req[CC_idP];
nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu =
&HI_DCI0_req->hi_dci0_request_body.hi_dci0_pdu_list[0];
COMMON_channels_t *cc = &RC.mac[module_idP]->common_channels[CC_idP];
int i;
if (cc->tdd_Config != NULL) { // TDD
for (i = 0;
i <
HI_DCI0_req->hi_dci0_request_body.number_of_dci +
HI_DCI0_req->hi_dci0_request_body.number_of_dci; i++) {
if ((hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) &&
(hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti == rntiP))
hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.dl_assignment_index =
(daiP - 1) & 3;
}
}
}
//------------------------------------------------------------------------------
void
set_ue_dai(sub_frame_t subframeP,
int UE_id, uint8_t CC_id, uint8_t tdd_config,
UE_list_t * UE_list)
//------------------------------------------------------------------------------
{
switch (tdd_config) {
case 0:
if ((subframeP == 0) || (subframeP == 1) || (subframeP == 3)
|| (subframeP == 5) || (subframeP == 6) || (subframeP == 8)) {
UE_list->UE_template[CC_id][UE_id].DAI = 0;
}
break;
case 1:
if ((subframeP == 0) || (subframeP == 4) || (subframeP == 5)
|| (subframeP == 9)) {
UE_list->UE_template[CC_id][UE_id].DAI = 0;
}
break;
case 2:
if ((subframeP == 4) || (subframeP == 5)) {
UE_list->UE_template[CC_id][UE_id].DAI = 0;
}
break;
case 3:
if ((subframeP == 5) || (subframeP == 7) || (subframeP == 9)) {
UE_list->UE_template[CC_id][UE_id].DAI = 0;
}
break;
case 4:
if ((subframeP == 0) || (subframeP == 6)) {
UE_list->UE_template[CC_id][UE_id].DAI = 0;
}
break;
case 5:
if (subframeP == 9) {
UE_list->UE_template[CC_id][UE_id].DAI = 0;
}
break;
case 6:
if ((subframeP == 0) || (subframeP == 1) || (subframeP == 5)
|| (subframeP == 6) || (subframeP == 9)) {
UE_list->UE_template[CC_id][UE_id].DAI = 0;
}
break;
default:
UE_list->UE_template[CC_id][UE_id].DAI = 0;
LOG_N(MAC, "unknow TDD config %d\n", tdd_config);
break;
}
}