MSG4 scheduling based on k0-k1 [Issue-ID: ODUHIGH-388]
[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 ueIdx = 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, ueIdx);
229       GET_CRNTI(crnti,ueIdx);
230       ueCb = &cell->ueCb[ueIdx-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 = 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->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 = 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          /* Free the dl ded msg info allocated in macSchDlRlcBoInfo */
294          SCH_FREE(dlMsgAlloc, sizeof(DlMsgAlloc));
295          dlSchedInfo->dlMsgAlloc = NULLP;
296          return ROK;
297       }
298
299       /*[Step3]: Calculate Best FREE BLOCK with MAX PRB count*/
300       maxFreePRB = searchLargestFreeBlockDL(cell, dlSchedInfo->schSlotValue.dlMsgTime, &startPrb);
301
302       /*[Step4]: Estimation of PRB and BO which can be allocated to each LC in
303        * the list based on RRM policy*/
304
305       /*Either this UE contains no reservedPRB pool fir dedicated S-NSSAI or 
306        * Num of Free PRB available is not enough to reserve Dedicated PRBs*/
307       if(maxFreePRB != 0)
308       {
309          if((ueCb->dlLcPrbEst.dedLcInfo == NULLP) 
310                || ((maxFreePRB <  ueCb->dlLcPrbEst.dedLcInfo->rsvdDedicatedPRB)))
311          { 
312             ueCb->dlLcPrbEst.sharedNumPrb = maxFreePRB;
313             DU_LOG("\nWARNING  --> SCH : Only Default Slice is scheduled, sharedPRB Count:%d",\
314                   ueCb->dlLcPrbEst.sharedNumPrb);
315
316             /*PRB Alloc for Default LCs*/
317             prbAllocUsingRRMPolicy(&(ueCb->dlLcPrbEst.defLcList), FALSE, mcsIdx, pdschSymbols,\
318                   &(ueCb->dlLcPrbEst.sharedNumPrb), NULLP, &isTxPayloadLenAdded);
319          }
320          else
321          {
322             ueCb->dlLcPrbEst.sharedNumPrb = maxFreePRB - ueCb->dlLcPrbEst.dedLcInfo->rsvdDedicatedPRB;
323
324             /*PRB Alloc for Dedicated LCs*/
325             prbAllocUsingRRMPolicy(&(ueCb->dlLcPrbEst.dedLcInfo->dedLcList), TRUE, mcsIdx, pdschSymbols,\
326                   &(ueCb->dlLcPrbEst.sharedNumPrb), &(ueCb->dlLcPrbEst.dedLcInfo->rsvdDedicatedPRB), &isTxPayloadLenAdded);
327
328             /*PRB Alloc for Default LCs*/
329             prbAllocUsingRRMPolicy(&(ueCb->dlLcPrbEst.defLcList), FALSE, mcsIdx, pdschSymbols, \
330                   &(ueCb->dlLcPrbEst.sharedNumPrb), &(ueCb->dlLcPrbEst.dedLcInfo->rsvdDedicatedPRB), &isTxPayloadLenAdded);
331          }
332       }
333
334       /*[Step5]:Traverse each LCID in LcList to calculate the exact Scheduled Bytes
335        * using allocated BO per LC and Update dlMsgAlloc(BO report for MAC*/ 
336       if(ueCb->dlLcPrbEst.dedLcInfo != NULLP)
337          updateGrantSizeForBoRpt(&(ueCb->dlLcPrbEst.dedLcInfo->dedLcList), dlMsgAlloc, &(accumalatedSize));
338
339       updateGrantSizeForBoRpt(&(ueCb->dlLcPrbEst.defLcList), dlMsgAlloc, &(accumalatedSize));
340
341       /*Below case will hit if NO LC(s) are allocated due to resource crunch*/
342       if (!accumalatedSize)
343       {
344          if(maxFreePRB == 0)
345          {
346             DU_LOG("\nERROR  --> SCH : NO FREE PRB!!");
347          }
348          else
349          {
350             /*Schedule the LC for next slot*/
351             DU_LOG("\nDEBUG  -->  SCH : No LC has been scheduled");
352          }
353          /*Not Freeing dlMsgAlloc as ZERO BO REPORT to be sent to RLC so that
354           * Allocation can be done in next slot*/
355          return ROK;
356       }
357       
358       /*[Step6]: pdcch and pdsch data is filled */
359       if((schDlRsrcAllocDlMsg(cell, dlSchedInfo->schSlotValue.dlMsgTime, \
360                   crnti, accumalatedSize, dlMsgAlloc, startPrb)) != ROK)
361       {
362          DU_LOG("\nERROR  --> SCH : Scheduling of DL dedicated message failed");
363          /* Free the dl ded msg info allocated in macSchDlRlcBoInfo */
364          SCH_FREE(dlMsgAlloc, sizeof(DlMsgAlloc));
365          dlSchedInfo->dlMsgAlloc = NULLP;
366          return RFAILED;
367       }
368       
369       dlMsgAlloc->pduPres = BOTH;
370
371       /* TODO : Update the scheduling byte report for multiple LC based on QCI
372        * and Priority */
373       /* As of now, the total number of bytes scheduled for a slot is divided
374        * equally amongst all LC with pending data. This is avoid starving of any
375        * LC 
376        * */
377 #if 0
378       accumalatedSize = accumalatedSize/dlMsgAlloc->numLc;
379       for(lcIdx = 0; lcIdx < dlMsgAlloc->numLc; lcIdx ++)
380          dlMsgAlloc->lcSchInfo[lcIdx].schBytes = accumalatedSize;
381 #endif
382       /* PUCCH resource */
383       /* TODO : Correct values of K1 will be used from K0K1 table */ 
384       if(cell->ueCb[ueIdx].ueCfg.spCellCfg.servCellCfg.initUlBwp.pucchCfgPres)
385       {
386          schPucchCfg = &(cell->ueCb[ueIdx].ueCfg.spCellCfg.servCellCfg.initUlBwp.pucchCfg);
387          if(schPucchCfg->dlDataToUlAck)
388          {
389             for(dlToUlAckIdx = 0; dlToUlAckIdx < schPucchCfg->dlDataToUlAck->dlDataToUlAckListCount; dlToUlAckIdx++)
390             {
391                //For now considering only the first value in the list
392                k1 = schPucchCfg->dlDataToUlAck->dlDataToUlAckList[dlToUlAckIdx];
393                break;
394             }
395          }
396       }
397       ADD_DELTA_TO_TIME(dlSchedInfo->schSlotValue.dlMsgTime, pucchTime, k1);
398       schAllocPucchResource(cell, pucchTime, crnti);
399
400       /* after allocation is done, unset the bo bit for that ue */
401       UNSET_ONE_BIT(ueIdx, cell->boIndBitMap);
402    }
403
404    return ROK;
405 }
406
407 /*******************************************************************
408  *
409  * @brief Handles slot indication at SCH 
410  *
411  * @details
412  *
413  *    Function : schProcessSlotInd
414  *
415  *    Functionality:
416  *     Handles TTI indication received from PHY
417  *
418  * @params[in] 
419  * @return ROK     - success
420  *         RFAILED - failure
421  *
422  * ****************************************************************/
423 uint8_t schProcessSlotInd(SlotTimingInfo *slotInd, Inst schInst)
424 {
425    uint8_t  ueIdx, lcgIdx, ret = ROK;
426    uint16_t slot;
427    DlSchedInfo dlSchedInfo;
428    DlBrdcstAlloc *dlBrdcstAlloc = NULLP;
429    DlMsgAlloc *dlMsgAlloc = NULLP;
430    SchCellCb  *cell = NULLP;
431
432    memset(&dlSchedInfo,0,sizeof(DlSchedInfo));
433    dlSchedInfo.dlMsgAlloc = NULLP;
434    schCalcSlotValues(*slotInd, &dlSchedInfo.schSlotValue);
435    dlBrdcstAlloc = &dlSchedInfo.brdcstAlloc;
436    dlBrdcstAlloc->ssbTrans = NO_TRANSMISSION;
437    dlBrdcstAlloc->sib1Trans = NO_TRANSMISSION;
438
439    cell = schCb[schInst].cells[schInst];
440    if(cell == NULLP)
441    {
442       DU_LOG("\nERROR  -->  SCH : Cell Does not exist");
443       return RFAILED;
444    }
445    memcpy(&cell->slotInfo, slotInd, sizeof(SlotTimingInfo));
446    dlBrdcstAlloc->ssbIdxSupported = SSB_IDX_SUPPORTED;
447
448    dlSchedInfo.cellId = cell->cellId;
449    slot = dlSchedInfo.schSlotValue.broadcastTime.slot;
450
451    /* Check for SSB occassion */
452    dlBrdcstAlloc->ssbTrans = schCheckSsbOcc(cell, dlSchedInfo.schSlotValue.broadcastTime); 
453    if(dlBrdcstAlloc->ssbTrans)
454    {
455       if(schBroadcastSsbAlloc(cell, dlSchedInfo.schSlotValue.broadcastTime, dlBrdcstAlloc) != ROK)
456       {
457          DU_LOG("\nERROR  -->  SCH : schBroadcastSsbAlloc failed");
458          dlBrdcstAlloc->ssbTrans = NO_TRANSMISSION;
459       }
460       else 
461       {
462          dlSchedInfo.isBroadcastPres = true;
463          if((dlBrdcstAlloc->ssbTrans == NEW_TRANSMISSION) && (!cell->firstSsbTransmitted))
464             cell->firstSsbTransmitted = true;
465       }
466    }
467
468    /* Check for SIB1 occassion */
469    dlBrdcstAlloc->sib1Trans = schCheckSib1Occ(cell, dlSchedInfo.schSlotValue.broadcastTime);
470    if(dlBrdcstAlloc->sib1Trans)
471    {
472       if(schBroadcastSib1Alloc(cell, dlSchedInfo.schSlotValue.broadcastTime, dlBrdcstAlloc) != ROK)
473       {
474          DU_LOG("\nERROR  -->  SCH : schBroadcastSib1Alloc failed");
475          dlBrdcstAlloc->sib1Trans = NO_TRANSMISSION;
476       }
477       else 
478       {
479          dlSchedInfo.isBroadcastPres = true;
480          if((dlBrdcstAlloc->sib1Trans == NEW_TRANSMISSION) && (!cell->firstSib1Transmitted))
481             cell->firstSib1Transmitted = true;
482       }
483    }
484
485    /* Check for Pending RA Requests */
486    schProcessRaReq(*slotInd, cell);
487
488    /* Check for RAR */
489    if(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.rarTime.slot]->rarAlloc != NULLP)
490    {
491       slot = dlSchedInfo.schSlotValue.rarTime.slot;
492       dlSchedInfo.rarAlloc = cell->schDlSlotInfo[slot]->rarAlloc;
493       cell->schDlSlotInfo[slot]->rarAlloc = NULLP;
494    }
495    
496    schProcessMsg4Req(cell, *slotInd);
497
498    /* Check for MSG4 */
499    if((cell->schDlSlotInfo[dlSchedInfo.schSlotValue.dlMsgTime.slot]->dlMsgAlloc != NULLP) &&
500       (cell->schDlSlotInfo[dlSchedInfo.schSlotValue.dlMsgTime.slot]->dlMsgAlloc->dlMsgInfo.isMsg4Pdu))
501    {
502       slot = dlSchedInfo.schSlotValue.dlMsgTime.slot;
503       dlSchedInfo.dlMsgAlloc = cell->schDlSlotInfo[slot]->dlMsgAlloc;
504       cell->schDlSlotInfo[slot]->dlMsgAlloc = NULLP;
505    }
506
507    /* Check if UL grant must be sent in this slot for a SR/BSR that had been received */
508    for(ueIdx=0; ueIdx<cell->numActvUe; ueIdx++)
509    {
510       uint32_t totDataReq = 0; /* in bytes */
511       DciInfo  *dciInfo = NULLP;
512       SchUeCb *ueCb = NULLP;
513    
514       ueCb = &cell->ueCb[ueIdx];
515       /* check for SR */
516       if(ueCb->srRcvd)
517       {
518          totDataReq = UL_GRANT_SIZE; /*fixing so that all control msgs can be handled in SR */
519          ueCb->srRcvd = false;
520       }
521       /* check for BSR */
522       for(lcgIdx=0; lcgIdx<MAX_NUM_LOGICAL_CHANNEL_GROUPS; lcgIdx++)
523       {
524         totDataReq+= ueCb->bsrInfo[lcgIdx].dataVol;
525         ueCb->bsrInfo[lcgIdx].dataVol = 0;
526       }
527       if(totDataReq > 0) /* UL grant must be provided for this UE in this slot */
528       {
529          SchPuschInfo schPuschInfo;
530          memset(&schPuschInfo, 0, sizeof(SchPuschInfo));
531
532          SCH_ALLOC(dciInfo, sizeof(DciInfo));
533          if(!dciInfo)
534          {
535             DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for dciInfo alloc");
536             return RFAILED;
537          }
538          memset(dciInfo,0,sizeof(DciInfo));
539
540          /* update the SFN and SLOT */
541          memcpy(&dlSchedInfo.schSlotValue.ulDciTime, slotInd, sizeof(SlotTimingInfo));
542
543          /* Update PUSCH allocation */
544          schFillPuschAlloc(ueCb, dlSchedInfo.schSlotValue.ulDciTime, totDataReq, &schPuschInfo);
545
546          /* Fill DCI for UL grant */
547          schFillUlDci(ueCb, schPuschInfo, dciInfo);
548          memcpy(&dciInfo->slotIndInfo, &dlSchedInfo.schSlotValue.ulDciTime, sizeof(SlotTimingInfo));
549          dlSchedInfo.ulGrant = dciInfo;
550       }
551    }
552
553    /* Check for pending BO grant for LC */
554    if((cell->schDlSlotInfo[dlSchedInfo.schSlotValue.dlMsgTime.slot]->dlMsgAlloc != NULLP) &&
555       (!cell->schDlSlotInfo[dlSchedInfo.schSlotValue.dlMsgTime.slot]->dlMsgAlloc->dlMsgInfo.isMsg4Pdu))
556    {
557       if((schFillBoGrantDlSchedInfo(cell, &dlSchedInfo, dlMsgAlloc)) != ROK)
558       {
559          DU_LOG("\nERROR  -->  SCH : DL MSG scheduling failed");
560          SCH_FREE(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.dlMsgTime.slot]->dlMsgAlloc, sizeof(DlMsgAlloc));
561          return RFAILED;
562       }
563
564       /* Free the dl ded msg info allocated in macSchDlRlcBoInfo */
565       SCH_FREE(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.dlMsgTime.slot]->dlMsgAlloc, sizeof(DlMsgAlloc));
566    }
567
568    /* Send msg to MAC */
569    ret = sendDlAllocToMac(&dlSchedInfo, schInst);
570    if(ret != ROK)
571    {
572       DU_LOG("\nERROR  -->  SCH : Sending DL Broadcast allocation from SCH to MAC failed");
573       return (ret);
574    }
575
576    schInitDlSlot(cell->schDlSlotInfo[slot]);
577    schUlResAlloc(cell, schInst);
578
579    return ret;
580 }
581
582 /**********************************************************************
583   End of file
584  **********************************************************************/
585
586