Multi-UE support upto MSG4 handling [Issue-ID: ODUHIGH-387]
[o-du/l2.git] / src / 5gnrsch / sch_slot_ind.c
1 /*******************************************************************************
2 ################################################################################
3 #   Copyright (c) [2017-2019] [Radisys]                                        #
4 #                                                                              #
5 #   Licensed under the Apache License, Version 2.0 (the "License");            #
6 #   you may not use this file except in compliance with the License.           #
7 #   You may obtain a copy of the License at                                    #
8 #                                                                              #
9 #       http://www.apache.org/licenses/LICENSE-2.0                             #
10 #                                                                              #
11 #   Unless required by applicable law or agreed to in writing, software        #
12 #   distributed under the License is distributed on an "AS IS" BASIS,          #
13 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
14 #   See the License for the specific language governing permissions and        #
15 #   limitations under the License.                                             #
16 ################################################################################
17  *******************************************************************************/
18
19 /************************************************************************
20
21 Name:     5G NR SCH layer
22
23 Type:     C source file
24
25 Desc:     C source code for Entry point fucntions for slot indications
26
27 File:     sch_slot_ind.c
28
29  **********************************************************************/
30
31 /** @file sch_slot_ind.c
32   @brief This module processes slot indications
33  */
34 #include "common_def.h"
35 #include "tfu.h"
36 #include "lrg.h"
37 #include "tfu.x"
38 #include "lrg.x"
39 #include "du_log.h"
40 #include "du_app_mac_inf.h"
41 #include "mac_sch_interface.h"
42 #include "sch.h"
43 #include "sch_utils.h"
44
45 SchMacDlAllocFunc schMacDlAllocOpts[] =
46 {
47    packSchMacDlAlloc,
48    MacProcDlAlloc,
49    packSchMacDlAlloc
50 };
51
52 /*******************************************************************
53  *
54  * @brief Handles sending DL broadcast alloc to MAC 
55  *
56  * @details
57  *
58  *    Function : sendDlAllocToMac
59  *
60  *    Functionality:
61  *     Sends DL Broadcast Resource Allocation to MAC from SCH
62  *
63  * @params[in] 
64  * @return ROK     - success
65  *         RFAILED - failure
66  *
67  * ****************************************************************/
68 uint8_t sendDlAllocToMac(DlSchedInfo *dlSchedInfo, Inst inst)
69 {
70    Pst pst;
71
72    memset(&pst, 0, sizeof(Pst));
73    FILL_PST_SCH_TO_MAC(pst, inst);
74    pst.event = EVENT_DL_SCH_INFO;
75
76    return(*schMacDlAllocOpts[pst.selector])(&pst, dlSchedInfo);
77
78 }
79
80 /*******************************************************************
81  *
82  * @brief Handles slot indication at SCH 
83  *
84  * @details
85  *
86  *    Function : schCalcSlotValues
87  *
88  *    Functionality:
89  *     Handles TTI indication received from PHY
90  *
91  * @params[in] 
92  * @return ROK     - success
93  *         RFAILED - failure
94  *
95  * ****************************************************************/
96 void schCalcSlotValues(SlotTimingInfo slotInd, SchSlotValue *schSlotValue)
97 {
98    /****************************************************************
99     * PHY_DELTA - the physical layer delta                         * 
100     * SCHED_DELTA - scheduler schedules one slot ahead             *
101     * BO_DELTA - this delay is considered for BO response and      *
102     *            RLC buffer packet to received at MAC              *
103     * lower-mac (FAPI filling) will be working on PHY_DELTA        *
104     * brdcast scheduler will working on PHY_DELTA + SCHED_DELTA    *
105     * RAR scheduler will working on PHY_DELTA + SCHED_DELTA        *
106     * msg4 scheduler will working on PHY_DELTA + SCHED_DELTA       *
107     * dedicated DL msg scheduler will working                      *
108     *        on PHY_DELTA + SCHED_DELTA + BO_DELTA                 *
109     ****************************************************************/
110
111    ADD_DELTA_TO_TIME(slotInd, schSlotValue->currentTime, PHY_DELTA_DL);
112    ADD_DELTA_TO_TIME(slotInd, schSlotValue->broadcastTime, PHY_DELTA_DL + SCHED_DELTA);
113    ADD_DELTA_TO_TIME(slotInd, schSlotValue->rarTime, PHY_DELTA_DL + SCHED_DELTA);
114    ADD_DELTA_TO_TIME(slotInd, schSlotValue->dlMsgTime, PHY_DELTA_DL + SCHED_DELTA);
115 }
116
117 /*******************************************************************
118  *
119  * @brief Checks if a slot is to be scheduled for SSB transmission
120  *
121  * @details
122  *
123  *    Function : schCheckSsbOcc 
124  *
125  *    Functionality:
126  *       Checks if a slot is to be scheduled for SSB transmission
127  *
128  * @params[in] SlotTimingInfo slotTime
129  *             SchCellCb *cell 
130  * @return  Pdu transmission 
131  *
132  * ****************************************************************/
133 PduTxOccsaion schCheckSsbOcc(SchCellCb *cell, SlotTimingInfo slotTime)
134 {
135    uint8_t  ssb_rep;
136
137    ssb_rep = cell->cellCfg.ssbSchCfg.ssbPeriod;
138
139    /* Identify SSB ocassion*/
140    if ((slotTime.sfn % SCH_MIB_TRANS == 0) && (slotTime.slot ==0))
141    {
142       return NEW_TRANSMISSION;
143    }
144    else if(cell->firstSsbTransmitted) 
145    {
146       if((ssb_rep == 5) && ((slotTime.slot == 0 || slotTime.slot == 10)))
147          return REPEATITION;
148       else if((slotTime.sfn % (ssb_rep/10) == 0) && slotTime.slot == 0)
149          return REPEATITION;
150    }
151    /* not SSB occassion */
152    return NO_TRANSMISSION;
153 }
154
155 /*******************************************************************
156  *
157  * @brief Checks if a slot is to be scheduled for SIB1 transmission
158  *
159  * @details
160  *
161  *    Function : schCheckSib1Occ
162  *
163  *    Functionality:
164  *       Checks if a slot is to be scheduled for SIB1 transmission
165  *
166  * @params[in] SlotTimingInfo slotTime
167  *             SchCellCb *cell
168  * @return  Pdu transmission
169  *
170  * ****************************************************************/
171 PduTxOccsaion schCheckSib1Occ(SchCellCb *cell, SlotTimingInfo slotTime)
172 {
173    /* Identify SIB1 occasions */
174    if((slotTime.sfn % SCH_SIB1_TRANS == 0) && (slotTime.slot ==0))
175    {
176       return NEW_TRANSMISSION;
177    }
178    else if(cell->firstSib1Transmitted) 
179    {
180       if((slotTime.sfn % (cell->cellCfg.sib1SchCfg.sib1RepetitionPeriod/10) == 0) &&
181             (slotTime.slot == 0))
182       {
183          return REPEATITION;
184       }
185    }
186    /* not SIB1 occassion */
187    return NO_TRANSMISSION;
188 }
189
190 /*******************************************************************
191  *
192  * @brief 
193  *
194  * @details
195  *
196  *    Function : schFillBoGrantDlSchedInfo 
197  *
198  *    Functionality:
199  
200  *
201  * @params[in] 
202  * @return ROK     - success
203  *         RFAILED - failure
204  *
205  * ****************************************************************/
206 uint8_t schFillBoGrantDlSchedInfo(SchCellCb *cell, DlSchedInfo *dlSchedInfo, DlMsgAlloc *dlMsgAlloc)
207 {
208    uint8_t ueId = 0, lcIdx = 0, pdschSymbols = 0, k1 = 0;
209    uint16_t slot = 0,  startPrb = 0, maxFreePRB = 0,dlToUlAckIdx =0;
210    uint16_t crnti = 0, mcsIdx = 0;
211    uint32_t accumalatedSize = 0;
212    SchUeCb *ueCb = NULLP;
213    CmLListCp *lcLL = NULLP;
214    SchPdschConfig pdschCfg;
215    SlotTimingInfo pucchTime;
216    SchPucchCfg *schPucchCfg;
217
218    /* TX_PAYLOAD_HDR_LEN: Overhead which is to be Added once for any UE while estimating Accumulated TB Size
219     * Following flag added to keep the record whether TX_PAYLOAD_HDR_LEN is added to the first Node getting allocated.
220     * If both Dedicated and Default LC lists are present then First LC in Dedicated List will include this overhead
221     * else if only Default list is present then first node in this List will add this overhead len*/
222    bool isTxPayloadLenAdded = FALSE;
223
224    while(cell->boIndBitMap)
225    {
226       slot = dlSchedInfo->schSlotValue.dlMsgTime.slot;
227
228       GET_RIGHT_MOST_SET_BIT(cell->boIndBitMap, ueId);
229       GET_CRNTI(crnti,ueId);
230       ueCb = &cell->ueCb[ueId-1];
231
232       /* allocate PDCCH and PDSCH resources for the ue */
233       SCH_ALLOC(dlMsgAlloc, sizeof(DlMsgAlloc));
234       if(!dlMsgAlloc)
235       {
236          DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for ded DL msg alloc");
237          return RFAILED;
238       }
239       memset(dlMsgAlloc, 0, sizeof(DlMsgAlloc));
240       dlSchedInfo->dlMsgAlloc[ueId-1] = dlMsgAlloc;
241       dlMsgAlloc->crnti = crnti;
242
243       pdschCfg = ueCb->ueCfg.spCellCfg.servCellCfg.initDlBwp.pdschCfg; 
244       mcsIdx = ueCb->ueCfg.dlModInfo.mcsIndex;
245
246       /*TODO: K0Index must be used instead of 0th Index in
247        * pdschCfg.timeDomRsrcAllociList*/
248       pdschSymbols = pdschCfg.timeDomRsrcAllociList[0].symbolLength;
249       /* Dl ded Msg info is copied, this was earlier filled in macSchDlRlcBoInfo */
250       memcpy(&dlMsgAlloc->dlMsgInfo, &cell->schDlSlotInfo[slot]->dlMsgAlloc[ueId-1]->dlMsgInfo, \
251             sizeof(DlMsgInfo));
252
253       /*Re-Initalization per UE*/
254       /* scheduled LC data fill */
255       dlMsgAlloc->numLc = 0;
256       isTxPayloadLenAdded = FALSE; /*Re-initlaize the flag for every UE*/
257       accumalatedSize = 0;
258
259       for(lcIdx = 0; lcIdx < MAX_NUM_LC; lcIdx++)
260       {
261          if(ueCb->dlInfo.dlLcCtxt[lcIdx].bo)
262          {
263             /*Check the LC is Dedicated or default and accordingly LCList will
264              * be used*/
265             if(ueCb->dlInfo.dlLcCtxt[lcIdx].isDedicated)
266             {
267                lcLL = &(ueCb->dlLcPrbEst.dedLcInfo->dedLcList);
268             }
269             else
270             {
271                lcLL = &(ueCb->dlLcPrbEst.defLcList);
272             }
273
274             /*[Step2]: Update the reqPRB and Payloadsize for this LC in the appropriate List*/
275             if(updateLcListReqPRB(lcLL, ueCb->dlInfo.dlLcCtxt[lcIdx].lcId,\
276                      (ueCb->dlInfo.dlLcCtxt[lcIdx].bo + MAC_HDR_SIZE)) != ROK)
277             {
278                DU_LOG("\nERROR  --> SCH : Updation in LC List Failed");
279                /* Free the dl ded msg info allocated in macSchDlRlcBoInfo */
280                SCH_FREE(dlMsgAlloc, sizeof(DlMsgAlloc));
281                dlSchedInfo->dlMsgAlloc[ueId-1] = NULLP;
282                return RFAILED;
283             }
284          }
285          ueCb->dlInfo.dlLcCtxt[lcIdx].bo = 0;
286       }//End of for loop
287
288
289       if ((ueCb->dlLcPrbEst.defLcList.count == 0) && \
290             ((ueCb->dlLcPrbEst.dedLcInfo != NULL) && (ueCb->dlLcPrbEst.dedLcInfo->dedLcList.count == 0)))
291       {
292          DU_LOG("\nDEBUG  -->  SCH : No pending BO for any LC id\n");
293          UNSET_ONE_BIT(ueId, cell->boIndBitMap);
294          /* Free the dl ded msg info allocated in macSchDlRlcBoInfo */
295          SCH_FREE(dlMsgAlloc, sizeof(DlMsgAlloc));
296          dlSchedInfo->dlMsgAlloc[ueId-1] = NULLP;
297          continue;
298       }
299
300       /*[Step3]: Calculate Best FREE BLOCK with MAX PRB count*/
301       maxFreePRB = searchLargestFreeBlockDL(cell, dlSchedInfo->schSlotValue.dlMsgTime, &startPrb);
302
303       /*[Step4]: Estimation of PRB and BO which can be allocated to each LC in
304        * the list based on RRM policy*/
305
306       /*Either this UE contains no reservedPRB pool fir dedicated S-NSSAI or 
307        * Num of Free PRB available is not enough to reserve Dedicated PRBs*/
308       if(maxFreePRB != 0)
309       {
310          if((ueCb->dlLcPrbEst.dedLcInfo == NULLP) 
311                || ((maxFreePRB <  ueCb->dlLcPrbEst.dedLcInfo->rsvdDedicatedPRB)))
312          { 
313             ueCb->dlLcPrbEst.sharedNumPrb = maxFreePRB;
314             DU_LOG("\nWARNING  --> SCH : Only Default Slice is scheduled, sharedPRB Count:%d",\
315                   ueCb->dlLcPrbEst.sharedNumPrb);
316
317             /*PRB Alloc for Default LCs*/
318             prbAllocUsingRRMPolicy(&(ueCb->dlLcPrbEst.defLcList), FALSE, mcsIdx, pdschSymbols,\
319                   &(ueCb->dlLcPrbEst.sharedNumPrb), NULLP, &isTxPayloadLenAdded);
320          }
321          else
322          {
323             ueCb->dlLcPrbEst.sharedNumPrb = maxFreePRB - ueCb->dlLcPrbEst.dedLcInfo->rsvdDedicatedPRB;
324
325             /*PRB Alloc for Dedicated LCs*/
326             prbAllocUsingRRMPolicy(&(ueCb->dlLcPrbEst.dedLcInfo->dedLcList), TRUE, mcsIdx, pdschSymbols,\
327                   &(ueCb->dlLcPrbEst.sharedNumPrb), &(ueCb->dlLcPrbEst.dedLcInfo->rsvdDedicatedPRB), &isTxPayloadLenAdded);
328
329             /*PRB Alloc for Default LCs*/
330             prbAllocUsingRRMPolicy(&(ueCb->dlLcPrbEst.defLcList), FALSE, mcsIdx, pdschSymbols, \
331                   &(ueCb->dlLcPrbEst.sharedNumPrb), &(ueCb->dlLcPrbEst.dedLcInfo->rsvdDedicatedPRB), &isTxPayloadLenAdded);
332          }
333       }
334
335       /*[Step5]:Traverse each LCID in LcList to calculate the exact Scheduled Bytes
336        * using allocated BO per LC and Update dlMsgAlloc(BO report for MAC*/ 
337       if(ueCb->dlLcPrbEst.dedLcInfo != NULLP)
338          updateGrantSizeForBoRpt(&(ueCb->dlLcPrbEst.dedLcInfo->dedLcList), dlMsgAlloc, &(accumalatedSize));
339
340       updateGrantSizeForBoRpt(&(ueCb->dlLcPrbEst.defLcList), dlMsgAlloc, &(accumalatedSize));
341
342       /*Below case will hit if NO LC(s) are allocated due to resource crunch*/
343       if (!accumalatedSize)
344       {
345          if(maxFreePRB == 0)
346          {
347             DU_LOG("\nERROR  --> SCH : NO FREE PRB!!");
348          }
349          else
350          {
351             /*Schedule the LC for next slot*/
352             DU_LOG("\nDEBUG  -->  SCH : No LC has been scheduled");
353          }
354          /*Not Freeing dlMsgAlloc as ZERO BO REPORT to be sent to RLC so that
355           * Allocation can be done in next slot*/
356          return ROK;
357       }
358       
359       /*[Step6]: pdcch and pdsch data is filled */
360       if((schDlRsrcAllocDlMsg(cell, dlSchedInfo->schSlotValue.dlMsgTime, \
361                   crnti, accumalatedSize, dlMsgAlloc, startPrb)) != ROK)
362       {
363          DU_LOG("\nERROR  --> SCH : Scheduling of DL dedicated message failed");
364          /* Free the dl ded msg info allocated in macSchDlRlcBoInfo */
365          SCH_FREE(dlMsgAlloc, sizeof(DlMsgAlloc));
366          dlSchedInfo->dlMsgAlloc[ueId-1] = NULLP;
367          return RFAILED;
368       }
369       
370       dlMsgAlloc->pduPres = BOTH;
371
372       /* TODO : Update the scheduling byte report for multiple LC based on QCI
373        * and Priority */
374       /* As of now, the total number of bytes scheduled for a slot is divided
375        * equally amongst all LC with pending data. This is avoid starving of any
376        * LC 
377        * */
378 #if 0
379       accumalatedSize = accumalatedSize/dlMsgAlloc->numLc;
380       for(lcIdx = 0; lcIdx < dlMsgAlloc->numLc; lcIdx ++)
381          dlMsgAlloc->lcSchInfo[lcIdx].schBytes = accumalatedSize;
382 #endif
383       /* PUCCH resource */
384       /* TODO : Correct values of K1 will be used from K0K1 table */ 
385       if(cell->ueCb[ueId-1].ueCfg.spCellCfg.servCellCfg.initUlBwp.pucchCfgPres)
386       {
387          schPucchCfg = &(cell->ueCb[ueId-1].ueCfg.spCellCfg.servCellCfg.initUlBwp.pucchCfg);
388          if(schPucchCfg->dlDataToUlAck)
389          {
390             for(dlToUlAckIdx = 0; dlToUlAckIdx < schPucchCfg->dlDataToUlAck->dlDataToUlAckListCount; dlToUlAckIdx++)
391             {
392                //For now considering only the first value in the list
393                k1 = schPucchCfg->dlDataToUlAck->dlDataToUlAckList[dlToUlAckIdx];
394                break;
395             }
396          }
397       }
398       ADD_DELTA_TO_TIME(dlSchedInfo->schSlotValue.dlMsgTime, pucchTime, k1);
399       schAllocPucchResource(cell, pucchTime, crnti);
400
401       /* after allocation is done, unset the bo bit for that ue */
402       UNSET_ONE_BIT(ueId, cell->boIndBitMap);
403    }
404
405    return ROK;
406 }
407
408 /*******************************************************************
409  *
410  * @brief Handles slot indication at SCH 
411  *
412  * @details
413  *
414  *    Function : schProcessSlotInd
415  *
416  *    Functionality:
417  *     Handles TTI indication received from PHY
418  *
419  * @params[in] 
420  * @return ROK     - success
421  *         RFAILED - failure
422  *
423  * ****************************************************************/
424 uint8_t schProcessSlotInd(SlotTimingInfo *slotInd, Inst schInst)
425 {
426    uint8_t   ueId, ueIdx, lcgIdx, ret = ROK;
427    uint16_t  slot;
428    bool      isRarPending = false, isRarScheduled = false;
429    bool      isMsg4Pending = false, isMsg4Scheduled = false;
430    CmLList       *pendingUeNode;
431    DlSchedInfo   dlSchedInfo;
432    DlBrdcstAlloc *dlBrdcstAlloc = NULLP;
433    DlMsgAlloc    *dlMsgAlloc = NULLP;
434    SchCellCb     *cell = NULLP;
435
436    memset(&dlSchedInfo, 0, sizeof(DlSchedInfo));
437    schCalcSlotValues(*slotInd, &dlSchedInfo.schSlotValue);
438    dlBrdcstAlloc = &dlSchedInfo.brdcstAlloc;
439    dlBrdcstAlloc->ssbTrans = NO_TRANSMISSION;
440    dlBrdcstAlloc->sib1Trans = NO_TRANSMISSION;
441
442    cell = schCb[schInst].cells[schInst];
443    if(cell == NULLP)
444    {
445       DU_LOG("\nERROR  -->  SCH : Cell Does not exist");
446       return RFAILED;
447    }
448    memcpy(&cell->slotInfo, slotInd, sizeof(SlotTimingInfo));
449    dlBrdcstAlloc->ssbIdxSupported = SSB_IDX_SUPPORTED;
450
451    dlSchedInfo.cellId = cell->cellId;
452    slot = dlSchedInfo.schSlotValue.broadcastTime.slot;
453
454    /* Check for SSB occassion */
455    dlBrdcstAlloc->ssbTrans = schCheckSsbOcc(cell, dlSchedInfo.schSlotValue.broadcastTime); 
456    if(dlBrdcstAlloc->ssbTrans)
457    {
458       if(schBroadcastSsbAlloc(cell, dlSchedInfo.schSlotValue.broadcastTime, dlBrdcstAlloc) != ROK)
459       {
460          DU_LOG("\nERROR  -->  SCH : schBroadcastSsbAlloc failed");
461          dlBrdcstAlloc->ssbTrans = NO_TRANSMISSION;
462       }
463       else 
464       {
465          dlSchedInfo.isBroadcastPres = true;
466          if((dlBrdcstAlloc->ssbTrans == NEW_TRANSMISSION) && (!cell->firstSsbTransmitted))
467             cell->firstSsbTransmitted = true;
468       }
469    }
470
471    /* Check for SIB1 occassion */
472    dlBrdcstAlloc->sib1Trans = schCheckSib1Occ(cell, dlSchedInfo.schSlotValue.broadcastTime);
473    if(dlBrdcstAlloc->sib1Trans)
474    {
475       if(schBroadcastSib1Alloc(cell, dlSchedInfo.schSlotValue.broadcastTime, dlBrdcstAlloc) != ROK)
476       {
477          DU_LOG("\nERROR  -->  SCH : schBroadcastSib1Alloc failed");
478          dlBrdcstAlloc->sib1Trans = NO_TRANSMISSION;
479       }
480       else 
481       {
482          dlSchedInfo.isBroadcastPres = true;
483          if((dlBrdcstAlloc->sib1Trans == NEW_TRANSMISSION) && (!cell->firstSib1Transmitted))
484             cell->firstSib1Transmitted = true;
485       }
486    }
487
488    /* Select first UE in the linked list to be scheduled next */
489    pendingUeNode = cell->ueToBeScheduled.first;
490    if(pendingUeNode)
491    {
492       ueId = *(uint8_t *)(pendingUeNode->node);
493
494       /* If RAR is pending for this UE, schedule PDCCH,PDSCH to send RAR and 
495        * PUSCH to receive MSG3 as per k0-k2 configuration*/
496       if(cell->raReq[ueId-1] != NULLP)
497       {
498          isRarPending = true;
499          isRarScheduled = schProcessRaReq(cell, *slotInd, ueId);
500       }
501
502       /* If MSG4 is pending for this UE, schedule PDCCH,PDSCH to send MSG4 and
503        * PUCCH to receive UL msg as per k0-k1 configuration  */
504       if(cell->raCb[ueId-1].msg4recvd)
505       {
506          isMsg4Pending = true;
507          isMsg4Scheduled = schProcessMsg4Req(cell, *slotInd, ueId);
508       }
509
510       if(isRarPending || isMsg4Pending)
511       {
512          /* If RAR or MSG is successfully scheduled then
513           * remove UE from linked list since no pending msgs for this UE */
514          if(isRarScheduled || isMsg4Scheduled)
515          {
516             SCH_FREE(pendingUeNode->node, sizeof(uint8_t));
517             deleteNodeFromLList(&cell->ueToBeScheduled, pendingUeNode);
518          }
519          /* If RAR/MSG4 is pending but couldnt be scheduled then,
520           * put this UE at the end of linked list to be scheduled later */
521          else 
522          {
523             cmLListAdd2Tail(&cell->ueToBeScheduled, cmLListDelFrm(&cell->ueToBeScheduled, pendingUeNode));
524          }
525       }
526    }
527
528    /* Check if any PDU is scheduled at this slot for any UE */
529    for(ueIdx=0; ueIdx<MAX_NUM_UE; ueIdx++)
530    {
531       /* If RAR PDCCH/PDSCH is scheduled for a UE at this slot, fill RAR specific interface 
532        * structure to send to MAC */
533       if(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.rarTime.slot]->rarAlloc[ueIdx] != NULLP)
534       {
535          slot = dlSchedInfo.schSlotValue.rarTime.slot;
536          dlSchedInfo.rarAlloc[ueIdx] = cell->schDlSlotInfo[slot]->rarAlloc[ueIdx];
537          cell->schDlSlotInfo[slot]->rarAlloc[ueIdx] = NULLP;
538       }
539    
540       /* If MSG4 PDCCH/PDSCH is scheduled for a UE at this slot, fill MSG4
541        * specific interface structure to send to MAC */
542       if((cell->schDlSlotInfo[dlSchedInfo.schSlotValue.dlMsgTime.slot]->dlMsgAlloc[ueIdx] != NULLP) &&
543             (cell->schDlSlotInfo[dlSchedInfo.schSlotValue.dlMsgTime.slot]->dlMsgAlloc[ueIdx]->dlMsgInfo.isMsg4Pdu))
544       {
545          slot = dlSchedInfo.schSlotValue.dlMsgTime.slot;
546          dlSchedInfo.dlMsgAlloc[ueIdx] = cell->schDlSlotInfo[slot]->dlMsgAlloc[ueIdx];
547          cell->schDlSlotInfo[slot]->dlMsgAlloc[ueIdx] = NULLP;
548       }
549
550       /* Check for pending BO grant for LC */
551       if((cell->schDlSlotInfo[dlSchedInfo.schSlotValue.dlMsgTime.slot]->dlMsgAlloc[ueIdx] != NULLP) &&
552             (!cell->schDlSlotInfo[dlSchedInfo.schSlotValue.dlMsgTime.slot]->dlMsgAlloc[ueIdx]->dlMsgInfo.isMsg4Pdu))
553       {
554          if((schFillBoGrantDlSchedInfo(cell, &dlSchedInfo, dlMsgAlloc)) != ROK)
555          {
556             DU_LOG("\nERROR  -->  SCH : DL MSG scheduling failed");
557             SCH_FREE(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.dlMsgTime.slot]->dlMsgAlloc[ueIdx], sizeof(DlMsgAlloc));
558             return RFAILED;
559          }
560
561          /* Free the dl ded msg info allocated in macSchDlRlcBoInfo */
562          SCH_FREE(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.dlMsgTime.slot]->dlMsgAlloc[ueIdx], sizeof(DlMsgAlloc));
563       }
564    }
565
566    /* Check if UL grant must be sent in this slot for a SR/BSR that had been received */
567    for(ueIdx=0; ueIdx<cell->numActvUe; ueIdx++)
568    {
569       uint32_t totDataReq = 0; /* in bytes */
570       DciInfo  *dciInfo = NULLP;
571       SchUeCb *ueCb = NULLP;
572    
573       ueCb = &cell->ueCb[ueIdx];
574       /* check for SR */
575       if(ueCb->srRcvd)
576       {
577          totDataReq = UL_GRANT_SIZE; /*fixing so that all control msgs can be handled in SR */
578          ueCb->srRcvd = false;
579       }
580       /* check for BSR */
581       for(lcgIdx=0; lcgIdx<MAX_NUM_LOGICAL_CHANNEL_GROUPS; lcgIdx++)
582       {
583         totDataReq+= ueCb->bsrInfo[lcgIdx].dataVol;
584         ueCb->bsrInfo[lcgIdx].dataVol = 0;
585       }
586       if(totDataReq > 0) /* UL grant must be provided for this UE in this slot */
587       {
588          SchPuschInfo schPuschInfo;
589          memset(&schPuschInfo, 0, sizeof(SchPuschInfo));
590
591          SCH_ALLOC(dciInfo, sizeof(DciInfo));
592          if(!dciInfo)
593          {
594             DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for dciInfo alloc");
595             return RFAILED;
596          }
597          memset(dciInfo,0,sizeof(DciInfo));
598
599          /* update the SFN and SLOT */
600          memcpy(&dlSchedInfo.schSlotValue.ulDciTime, slotInd, sizeof(SlotTimingInfo));
601
602          /* Update PUSCH allocation */
603          schFillPuschAlloc(ueCb, dlSchedInfo.schSlotValue.ulDciTime, totDataReq, &schPuschInfo);
604
605          /* Fill DCI for UL grant */
606          schFillUlDci(ueCb, schPuschInfo, dciInfo);
607          memcpy(&dciInfo->slotIndInfo, &dlSchedInfo.schSlotValue.ulDciTime, sizeof(SlotTimingInfo));
608          dlSchedInfo.ulGrant = dciInfo;
609       }
610    }
611
612    /* Send msg to MAC */
613    ret = sendDlAllocToMac(&dlSchedInfo, schInst);
614    if(ret != ROK)
615    {
616       DU_LOG("\nERROR  -->  SCH : Sending DL Broadcast allocation from SCH to MAC failed");
617       return (ret);
618    }
619
620    schInitDlSlot(cell->schDlSlotInfo[slot]);
621    schUlResAlloc(cell, schInst);
622
623    return ret;
624 }
625
626 /**********************************************************************
627   End of file
628  **********************************************************************/
629
630