gNB_scheduler.c 12.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * 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 gNB_scheduler.c
 * \brief gNB scheduler top level function operates on per subframe basis
WEI-TAI CHEN's avatar
WEI-TAI CHEN committed
24 25 26
 * \author  Navid Nikaein and Raymond Knopp, WEI-TAI CHEN
 * \date 2010 - 2014, 2018
 * \email: navid.nikaein@eurecom.fr, kroempa@gmail.com
27
 * \version 0.5
WEI-TAI CHEN's avatar
WEI-TAI CHEN committed
28
 * \company Eurecom, NTUST
29 30 31 32 33 34
 * @ingroup _mac

 */

#include "assertions.h"

35 36
#include "NR_MAC_COMMON/nr_mac_extern.h"
#include "NR_MAC_gNB/mac_proto.h"
37

Raymond Knopp's avatar
Raymond Knopp committed
38
#include "common/utils/LOG/log.h"
39
#include "common/utils/nr/nr_common.h"
Raymond Knopp's avatar
Raymond Knopp committed
40
#include "common/utils/LOG/vcd_signal_dumper.h"
41 42
#include "UTIL/OPT/opt.h"

43
#include "openair2/X2AP/x2ap_eNB.h"
44

45
#include "nr_pdcp/nr_pdcp_oai_api.h"
46 47 48

#include "intertask_interface.h"

49
#include "executables/softmodem-common.h"
Mahesh's avatar
Mahesh committed
50
#include "nfapi/oai_integration/vendor_ext.h"
51
#include "executables/nr-softmodem.h"
52

53 54 55
#include <errno.h>
#include <string.h>

laurent's avatar
laurent committed
56
const uint8_t nr_rv_round_map[4] = {0, 2, 3, 1};
57

58
void clear_nr_nfapi_information(gNB_MAC_INST *gNB,
59 60
                                int CC_idP,
                                frame_t frameP,
61 62 63 64
                                sub_frame_t slotP,
                                nfapi_nr_dl_tti_request_t *DL_req,
                                nfapi_nr_tx_data_request_t *TX_req,
                                nfapi_nr_ul_dci_request_t *UL_dci_req)
francescomani's avatar
francescomani committed
65
{
66
  /* called below and in simulators, so we assume a lock but don't require it */
67

68
  NR_ServingCellConfigCommon_t *scc = gNB->common_channels->ServingCellConfigCommon;
69
  const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
70

71
  UL_tti_req_ahead_initialization(gNB, scc, num_slots, CC_idP, frameP, slotP, *scc->ssbSubcarrierSpacing);
72

73
  nfapi_nr_dl_tti_pdcch_pdu_rel15_t **pdcch = (nfapi_nr_dl_tti_pdcch_pdu_rel15_t **)gNB->pdcch_pdu_idx[CC_idP];
74 75

  gNB->pdu_index[CC_idP] = 0;
76

77 78
  DL_req[CC_idP].SFN = frameP;
  DL_req[CC_idP].Slot = slotP;
Mahesh's avatar
Mahesh committed
79
  DL_req[CC_idP].dl_tti_request_body.nPDUs             = 0;
80
  DL_req[CC_idP].dl_tti_request_body.nGroup = 0;
81
  memset(pdcch, 0, sizeof(*pdcch) * MAX_NUM_CORESET);
Mahesh's avatar
Mahesh committed
82

83 84 85
  UL_dci_req[CC_idP].SFN = frameP;
  UL_dci_req[CC_idP].Slot = slotP;
  UL_dci_req[CC_idP].numPdus = 0;
Mahesh's avatar
Mahesh committed
86 87

  /* advance last round's future UL_tti_req to be ahead of current frame/slot */
88 89 90 91 92
  const int size = gNB->UL_tti_req_ahead_size;
  const int prev_slot = frameP * num_slots + slotP + size - 1;
  nfapi_nr_ul_tti_request_t *future_ul_tti_req = &gNB->UL_tti_req_ahead[CC_idP][prev_slot % size];
  future_ul_tti_req->SFN = (prev_slot / num_slots) % 1024;
  LOG_D(NR_MAC, "%d.%d UL_tti_req_ahead SFN.slot = %d.%d for index %d \n", frameP, slotP, future_ul_tti_req->SFN, future_ul_tti_req->Slot, prev_slot % size);
Mahesh's avatar
Mahesh committed
93
  /* future_ul_tti_req->Slot is fixed! */
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
  for (int i = 0; i < future_ul_tti_req->n_pdus; i++) {
    switch(future_ul_tti_req->pdus_list[i].pdu_type){
      case NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE:
        if(future_ul_tti_req->pdus_list[i].prach_pdu.beamforming.prgs_list){
          for (int j = 0; j < future_ul_tti_req->pdus_list[i].prach_pdu.beamforming.num_prgs; ++j) {
            if(future_ul_tti_req->pdus_list[i].prach_pdu.beamforming.prgs_list[j].dig_bf_interface_list){
              free(future_ul_tti_req->pdus_list[i].prach_pdu.beamforming.prgs_list[j].dig_bf_interface_list);
            }
          }
          free(future_ul_tti_req->pdus_list[i].prach_pdu.beamforming.prgs_list);
        }
        break;
      case NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE:
        if(future_ul_tti_req->pdus_list[i].pusch_pdu.beamforming.prgs_list){
          for (int j = 0; j < future_ul_tti_req->pdus_list[i].pusch_pdu.beamforming.num_prgs; ++j) {
            if(future_ul_tti_req->pdus_list[i].pusch_pdu.beamforming.prgs_list[j].dig_bf_interface_list){
              free(future_ul_tti_req->pdus_list[i].pusch_pdu.beamforming.prgs_list[j].dig_bf_interface_list);
            }
          }
          free(future_ul_tti_req->pdus_list[i].pusch_pdu.beamforming.prgs_list);
        }
        break;
      case NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE:
        if(future_ul_tti_req->pdus_list[i].pucch_pdu.beamforming.prgs_list){
          for (int j = 0; j < future_ul_tti_req->pdus_list[i].pucch_pdu.beamforming.num_prgs; ++j) {
            if(future_ul_tti_req->pdus_list[i].pucch_pdu.beamforming.prgs_list[j].dig_bf_interface_list){
              free(future_ul_tti_req->pdus_list[i].pucch_pdu.beamforming.prgs_list[j].dig_bf_interface_list);
            }
          }
          free(future_ul_tti_req->pdus_list[i].pucch_pdu.beamforming.prgs_list);
        }
        break;
      case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE:
        if(future_ul_tti_req->pdus_list[i].srs_pdu.beamforming.prgs_list){
          for (int j = 0; j < future_ul_tti_req->pdus_list[i].srs_pdu.beamforming.num_prgs; ++j) {
            if(future_ul_tti_req->pdus_list[i].srs_pdu.beamforming.prgs_list[j].dig_bf_interface_list){
              free(future_ul_tti_req->pdus_list[i].srs_pdu.beamforming.prgs_list[j].dig_bf_interface_list);
            }
          }
          free(future_ul_tti_req->pdus_list[i].srs_pdu.beamforming.prgs_list);
        }
      default:
        break;
    }
    future_ul_tti_req->pdus_list[i].pdu_type = 0;
    future_ul_tti_req->pdus_list[i].pdu_size = 0;
  }
Mahesh's avatar
Mahesh committed
141 142 143 144 145
  future_ul_tti_req->n_pdus = 0;
  future_ul_tti_req->n_ulsch = 0;
  future_ul_tti_req->n_ulcch = 0;
  future_ul_tti_req->n_group = 0;

146
  TX_req[CC_idP].Number_of_PDUs = 0;
147
}
148

149
bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot) {
150
  return (bitmap >> (slot % 64)) & 0x01;
151 152
}

153 154
/* the structure nfapi_nr_ul_tti_request_t is very big, let's copy only what is necessary */
static void copy_ul_tti_req(nfapi_nr_ul_tti_request_t *to, nfapi_nr_ul_tti_request_t *from)
155
{
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
  int i;

  to->header = from->header;
  to->SFN = from->SFN;
  to->Slot = from->Slot;
  to->n_pdus = from->n_pdus;
  to->rach_present = from->rach_present;
  to->n_ulsch = from->n_ulsch;
  to->n_ulcch = from->n_ulcch;
  to->n_group = from->n_group;

  for (i = 0; i < from->n_pdus; i++) {
    to->pdus_list[i].pdu_type = from->pdus_list[i].pdu_type;
    to->pdus_list[i].pdu_size = from->pdus_list[i].pdu_size;

    switch (from->pdus_list[i].pdu_type) {
      case NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE:
        to->pdus_list[i].prach_pdu = from->pdus_list[i].prach_pdu;
        break;
      case NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE:
        to->pdus_list[i].pusch_pdu = from->pdus_list[i].pusch_pdu;
        break;
      case NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE:
        to->pdus_list[i].pucch_pdu = from->pdus_list[i].pucch_pdu;
        break;
      case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE:
        to->pdus_list[i].srs_pdu = from->pdus_list[i].srs_pdu;
        break;
    }
  }
Mahesh's avatar
Mahesh committed
186

187 188 189 190 191 192
  for (i = 0; i < from->n_group; i++)
    to->groups_list[i] = from->groups_list[i];
}

void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, sub_frame_t slot, NR_Sched_Rsp_t *sched_info)
{
193
  protocol_ctxt_t ctxt = {0};
194
  PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frame, slot,module_idP);
195

196 197
  gNB_MAC_INST *gNB = RC.nrmac[module_idP];
  NR_COMMON_channels_t *cc = gNB->common_channels;
198
  NR_ServingCellConfigCommon_t        *scc     = cc->ServingCellConfigCommon;
199

200 201
  NR_SCHED_LOCK(&gNB->sched_lock);

202
  if (slot==0 && (*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]>=257)) {
203
    //FR2
Robert Schmidt's avatar
Robert Schmidt committed
204
    const NR_TDD_UL_DL_Pattern_t *tdd = &scc->tdd_UL_DL_ConfigurationCommon->pattern1;
205 206 207
    AssertFatal(tdd,"Dynamic TDD not handled yet\n");
    const int nb_periods_per_frame = get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity);
    // re-initialization of tdd_beam_association at beginning of frame
208 209
    for (int i=0; i<nb_periods_per_frame; i++)
      gNB->tdd_beam_association[i] = -1;
210 211
  }

Robert Schmidt's avatar
Robert Schmidt committed
212 213 214
  gNB->frame = frame;
  gNB->slot = slot;

215
  start_meas(&gNB->eNB_scheduler);
Rakesh's avatar
Rakesh committed
216
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_IN);
217

218
  /* send tick to RLC, PDCP, and X2AP every ms */
219 220
  if ((slot & ((1 << *scc->ssbSubcarrierSpacing) - 1)) == 0) {
    void nr_rlc_tick(int frame, int subframe);
221
    void nr_pdcp_tick(int frame, int subframe);
222
    nr_rlc_tick(frame, slot >> *scc->ssbSubcarrierSpacing);
223
    nr_pdcp_tick(frame, slot >> *scc->ssbSubcarrierSpacing);
224
    if (is_x2ap_enabled())
225
      x2ap_trigger();
226
  }
227

228
  for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
229
    //mbsfn_status[CC_id] = 0;
Mahesh's avatar
Mahesh committed
230

231
    // clear vrb_maps
232
    memset(cc[CC_id].vrb_map, 0, sizeof(uint16_t) * MAX_BWP_SIZE);
Robert Schmidt's avatar
Robert Schmidt committed
233
    // clear last scheduled slot's content (only)!
234
    const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
235 236
    const int size = gNB->vrb_map_UL_size;
    const int prev_slot = frame * num_slots + slot + size - 1;
Robert Schmidt's avatar
Robert Schmidt committed
237
    uint16_t *vrb_map_UL = cc[CC_id].vrb_map_UL;
238 239
    memcpy(&vrb_map_UL[prev_slot % size * MAX_BWP_SIZE], &gNB->ulprbbl, sizeof(uint16_t) * MAX_BWP_SIZE);

240
    clear_nr_nfapi_information(gNB, CC_id, frame, slot, &sched_info->DL_req, &sched_info->TX_req, &sched_info->UL_dci_req);
241
  }
242

243
  if ((slot == 0) && (frame & 127) == 0) {
244
    char stats_output[32656] = {0};
245
    dump_mac_stats(gNB, stats_output, sizeof(stats_output), true);
246
    LOG_I(NR_MAC, "Frame.Slot %d.%d\n%s\n", frame, slot, stats_output);
247
  }
248

249 250
  nr_mac_update_timers(module_idP, frame, slot);

251
  // This schedules MIB
252
  schedule_nr_mib(module_idP, frame, slot, &sched_info->DL_req);
253

254
  // This schedules SIB1
255
  if (get_softmodem_params()->sa == 1)
256
    schedule_nr_sib1(module_idP, frame, slot, &sched_info->DL_req, &sched_info->TX_req);
257

258
  // This schedule PRACH if we are not in phy_test mode
259 260 261 262 263 264 265
  if (get_softmodem_params()->phy_test == 0) {
    /* we need to make sure that resources for PRACH are free. To avoid that
       e.g. PUSCH has already been scheduled, make sure we schedule before
       anything else: below, we simply assume an advance one frame (minus one
       slot, because otherwise we would allocate the current slot in
       UL_tti_req_ahead), but be aware that, e.g., K2 is allowed to be larger
       (schedule_nr_prach will assert if resources are not free). */
266 267 268
    const sub_frame_t n_slots_ahead = nr_slots_per_frame[*scc->ssbSubcarrierSpacing] - 1;
    const frame_t f = (frame + (slot + n_slots_ahead) / nr_slots_per_frame[*scc->ssbSubcarrierSpacing]) % 1024;
    const sub_frame_t s = (slot + n_slots_ahead) % nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
269 270
    schedule_nr_prach(module_idP, f, s);
  }
271

272
  // Schedule CSI-RS transmission
273
  nr_csirs_scheduling(module_idP, frame, slot, nr_slots_per_frame[*scc->ssbSubcarrierSpacing], &sched_info->DL_req);
274

275 276
  // Schedule CSI measurement reporting
  nr_csi_meas_reporting(module_idP, frame, slot);
277

278
  nr_schedule_srs(module_idP, frame, slot);
279

280
  // This schedule RA procedure if not in phy_test mode
francescomani's avatar
francescomani committed
281
  // Otherwise consider 5G already connected
282
  if (get_softmodem_params()->phy_test == 0) {
283
    nr_schedule_RA(module_idP, frame, slot, &sched_info->UL_dci_req, &sched_info->DL_req, &sched_info->TX_req);
284
  }
285

286
  // This schedules the DCI for Uplink and subsequently PUSCH
287
  nr_schedule_ulsch(module_idP, frame, slot, &sched_info->UL_dci_req);
288

289
  // This schedules the DCI for Downlink and PDSCH
290
  start_meas(&gNB->schedule_dlsch);
291
  nr_schedule_ue_spec(module_idP, frame, slot, &sched_info->DL_req, &sched_info->TX_req);
292
  stop_meas(&gNB->schedule_dlsch);
293

294
  nr_sr_reporting(gNB, frame, slot);
295

296
  nr_schedule_pucch(gNB, frame, slot);
297

298 299 300 301 302 303 304
  /* TODO: we copy from gNB->UL_tti_req_ahead[0][current_index], ie. CC_id == 0,
   * is more than 1 CC supported?
   */
  AssertFatal(MAX_NUM_CCs == 1, "only 1 CC supported\n");
  const int current_index = ul_buffer_index(frame, slot, *scc->ssbSubcarrierSpacing, gNB->UL_tti_req_ahead_size);
  copy_ul_tti_req(&sched_info->UL_tti_req, &gNB->UL_tti_req_ahead[0][current_index]);

305
  stop_meas(&gNB->eNB_scheduler);
306
  NR_SCHED_UNLOCK(&gNB->sched_lock);
Rakesh's avatar
Rakesh committed
307
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_OUT);
Raymond Knopp's avatar
Raymond Knopp committed
308
}