08774854ca6bf3f600d1c98a84638e3ab39bccfa
[o-du/l2.git] / 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 #ifdef NR_DRX 
45 #include "sch_drx.h"
46 #endif
47
48 SchMacDlAllocFunc schMacDlAllocOpts[] =
49 {
50    packSchMacDlAlloc,
51    MacProcDlAlloc,
52    packSchMacDlAlloc
53 };
54
55 SchMacDlPageAllocFunc schMacDlPageAllocOpts[] =
56 {
57    packSchMacDlPageAlloc,
58    MacProcDlPageAlloc,
59    packSchMacDlPageAlloc
60 };
61
62 /*******************************************************************
63  *
64  * @brief Handles sending DL broadcast alloc to MAC 
65  *
66  * @details
67  *
68  *    Function : sendDlAllocToMac
69  *
70  *    Functionality:
71  *     Sends DL Broadcast Resource Allocation to MAC from SCH
72  *
73  * @params[in] 
74  * @return ROK     - success
75  *         RFAILED - failure
76  *
77  * ****************************************************************/
78 uint8_t sendDlAllocToMac(DlSchedInfo *dlSchedInfo, Inst inst)
79 {
80    Pst pst;
81
82    memset(&pst, 0, sizeof(Pst));
83    FILL_PST_SCH_TO_MAC(pst, inst);
84    pst.event = EVENT_DL_SCH_INFO;
85
86    return(*schMacDlAllocOpts[pst.selector])(&pst, dlSchedInfo);
87
88 }
89
90 /*******************************************************************
91  *
92  * @brief Handles sending DL Page alloc to MAC 
93  *
94  * @details
95  *
96  *    Function : sendDlPAgeAllocToMac
97  *
98  *    Functionality:
99  *     Sends DL Page Resource Allocation to MAC from SCH
100  *
101  * @params[in] 
102  * @return ROK     - success
103  *         RFAILED - failure
104  *
105  * ****************************************************************/
106 uint8_t sendDlPageAllocToMac(DlPageAlloc *dlPageAlloc, Inst inst)
107 {
108    Pst pst;
109
110    memset(&pst, 0, sizeof(Pst));
111    FILL_PST_SCH_TO_MAC(pst, inst);
112    pst.event = EVENT_DL_PAGING_ALLOC;
113
114    return(*schMacDlPageAllocOpts[pst.selector])(&pst, dlPageAlloc);
115
116 }
117
118 /*******************************************************************
119  *
120  * @brief Handles slot indication at SCH 
121  *
122  * @details
123  *
124  *    Function : schCalcSlotValues
125  *
126  *    Functionality:
127  *     Handles TTI indication received from PHY
128  *
129  * @params[in] 
130  * @return ROK     - success
131  *         RFAILED - failure
132  *
133  * ****************************************************************/
134 void schCalcSlotValues(SlotTimingInfo slotInd, SchSlotValue *schSlotValue, uint16_t numOfSlots)
135 {
136    /****************************************************************
137     * PHY_DELTA - the physical layer delta                         * 
138     * SCHED_DELTA - scheduler schedules one slot ahead             *
139     * BO_DELTA - this delay is considered for BO response and      *
140     *            RLC buffer packet to received at MAC              *
141     * lower-mac (FAPI filling) will be working on PHY_DELTA        *
142     * brdcast scheduler will working on PHY_DELTA + SCHED_DELTA    *
143     * RAR scheduler will working on PHY_DELTA + SCHED_DELTA        *
144     * msg4 scheduler will working on PHY_DELTA + SCHED_DELTA       *
145     * dedicated DL msg scheduler will working                      *
146     *        on PHY_DELTA + SCHED_DELTA + BO_DELTA                 *
147     ****************************************************************/
148
149    ADD_DELTA_TO_TIME(slotInd, schSlotValue->currentTime, PHY_DELTA_DL, numOfSlots);
150    ADD_DELTA_TO_TIME(slotInd, schSlotValue->broadcastTime, PHY_DELTA_DL + SCHED_DELTA, numOfSlots);
151    ADD_DELTA_TO_TIME(slotInd, schSlotValue->rarTime, PHY_DELTA_DL + SCHED_DELTA, numOfSlots);
152    ADD_DELTA_TO_TIME(slotInd, schSlotValue->dlMsgTime, PHY_DELTA_DL + SCHED_DELTA, numOfSlots);
153    ADD_DELTA_TO_TIME(slotInd, schSlotValue->ulDciTime, PHY_DELTA_DL + SCHED_DELTA, numOfSlots);
154 }
155
156 /*******************************************************************
157  *
158  * @brief Checks if a slot is to be scheduled for SSB transmission
159  *
160  * @details
161  *
162  *    Function : schCheckSsbOcc 
163  *
164  *    Functionality:
165  *       Checks if a slot is to be scheduled for SSB transmission
166  *
167  * @params[in] SlotTimingInfo slotTime
168  *             SchCellCb *cell 
169  * @return  Pdu transmission 
170  *
171  * ****************************************************************/
172 PduTxOccsaion schCheckSsbOcc(SchCellCb *cell, SlotTimingInfo slotTime)
173 {
174    uint8_t  ssb_rep;
175
176    ssb_rep = cell->cellCfg.ssbSchCfg.ssbPeriod;
177
178    /* Identify SSB ocassion*/
179    if ((slotTime.sfn % SCH_MIB_TRANS == 0) && (slotTime.slot ==0))
180    {
181       return NEW_TRANSMISSION;
182    }
183    else if(cell->firstSsbTransmitted) 
184    {
185       if((ssb_rep == 5) && ((slotTime.slot == 0 || slotTime.slot == 10)))
186          return REPEATITION;
187       else if((slotTime.sfn % (ssb_rep/10) == 0) && slotTime.slot == 0)
188          return REPEATITION;
189    }
190    /* not SSB occassion */
191    return NO_TRANSMISSION;
192 }
193
194 /*******************************************************************
195  *
196  * @brief Checks if a slot is to be scheduled for SIB1 transmission
197  *
198  * @details
199  *
200  *    Function : schCheckSib1Occ
201  *
202  *    Functionality:
203  *       Checks if a slot is to be scheduled for SIB1 transmission
204  *
205  * @params[in] SlotTimingInfo slotTime
206  *             SchCellCb *cell
207  * @return  Pdu transmission
208  *
209  * ****************************************************************/
210 PduTxOccsaion schCheckSib1Occ(SchCellCb *cell, SlotTimingInfo slotTime)
211 {
212    /* Identify SIB1 occasions */
213    if((slotTime.sfn % SCH_SIB1_TRANS == 0) && (slotTime.slot ==0))
214    {
215       return NEW_TRANSMISSION;
216    }
217    else if(cell->firstSib1Transmitted) 
218    {
219       if((slotTime.sfn % (cell->cellCfg.sib1SchCfg.sib1RepetitionPeriod/10) == 0) &&
220             (slotTime.slot == 0))
221       {
222          return REPEATITION;
223       }
224    }
225    /* not SIB1 occassion */
226    return NO_TRANSMISSION;
227 }
228
229 /*******************************************************************
230  *
231  * @brief find correct combination of k0-k1 value
232  *
233  * @details
234  *
235  *    Function : findValidK0K1Value
236  *
237  *    Functionality:
238  *       find correct combination of k0-k1 value
239  *
240  * @params[in] SchCellCb *cell, SlotTimingInfo currTime
241  * @params[in] uint8_t ueId, bool dedMsg
242  * @params[in] uint8_t *pdschStartSymbol, uint8_t *pdschSymblLen
243  * @params[in] SlotTimingInfo *pdcchTime, SlotTimingInfo *pdschTime
244  * @params[in] SlotTimingInfo *pucchTime, bool isRetx, SchDlHqProcCb *hqP
245  * @return ROK     - success
246  *         RFAILED - failure
247  *
248  *******************************************************************/
249 bool findValidK0K1Value(SchCellCb *cell, SlotTimingInfo currTime, uint8_t ueId, bool dedMsg,
250                         uint8_t *pdschStartSymbol, uint8_t *pdschSymblLen, SlotTimingInfo *pdcchTime,
251                         SlotTimingInfo *pdschTime, SlotTimingInfo *pucchTime, bool isRetx, SchDlHqProcCb *hqP)
252 {
253    uint8_t numK0 = 0, k0TblIdx = 0, k0Val = 0, k0Index =0 ;
254    uint8_t k1TblIdx = 0, k1Index = 0, k1Val = 0, numK1 = 0;
255    SchUeCb *ueCb = NULLP;
256    SchK0K1TimingInfoTbl *k0K1InfoTbl;
257
258    ADD_DELTA_TO_TIME(currTime, (*pdcchTime), PHY_DELTA_DL + SCHED_DELTA, cell->numSlots);
259 #ifdef NR_TDD
260    if(schGetSlotSymbFrmt(pdcchTime->slot, cell->slotFrmtBitMap) != DL_SLOT)
261    {
262       /* If it is not a DL slot, cannot schedule PDCCH. Return from here. */
263       return false;
264    }
265 #endif
266
267    if(cell->schDlSlotInfo[pdcchTime->slot]->pdcchUe != 0)
268    {
269       return false;
270    }
271
272    if(dedMsg == true)
273    {
274       ueCb = &cell->ueCb[ueId-1];
275       k0K1InfoTbl = &ueCb->ueCfg.spCellCfg.servCellCfg.initDlBwp.k0K1InfoTbl;
276    }
277    else
278    {
279       k0K1InfoTbl = &cell->cellCfg.schInitialDlBwp.k0K1InfoTbl;
280    }
281
282    numK0 = k0K1InfoTbl->k0k1TimingInfo[pdcchTime->slot].numK0;
283    for(k0TblIdx = 0; k0TblIdx < numK0; k0TblIdx++)
284    {
285       k0Index = k0K1InfoTbl->k0k1TimingInfo[pdcchTime->slot].k0Indexes[k0TblIdx].k0Index;
286       if(dedMsg != true)
287       {
288          k0Val = cell->cellCfg.schInitialDlBwp.pdschCommon.timeDomRsrcAllocList[k0Index].k0;
289          *pdschStartSymbol = cell->cellCfg.schInitialDlBwp.pdschCommon.timeDomRsrcAllocList[k0Index].startSymbol;
290          *pdschSymblLen = cell->cellCfg.schInitialDlBwp.pdschCommon.timeDomRsrcAllocList[k0Index].lengthSymbol;
291       }
292       else
293       {
294          if(ueCb->ueCfg.spCellCfg.servCellCfg.initDlBwp.pdschCfg.timeDomRsrcAllociList[k0Index].k0 != NULLP)
295          {
296             k0Val = *(ueCb->ueCfg.spCellCfg.servCellCfg.initDlBwp.pdschCfg.timeDomRsrcAllociList[k0Index].k0);
297             *pdschStartSymbol = ueCb->ueCfg.spCellCfg.servCellCfg.initDlBwp.pdschCfg.timeDomRsrcAllociList[k0Index].startSymbol;
298             *pdschSymblLen = ueCb->ueCfg.spCellCfg.servCellCfg.initDlBwp.pdschCfg.timeDomRsrcAllociList[k0Index].symbolLength;
299          }
300       }
301
302       ADD_DELTA_TO_TIME((*pdcchTime), (*pdschTime), k0Val, cell->numSlots);
303 #ifdef NR_TDD
304       if(schGetSlotSymbFrmt(pdschTime->slot, cell->slotFrmtBitMap) != DL_SLOT)
305       {
306          continue;
307       }
308 #endif
309       if(cell->schDlSlotInfo[pdschTime->slot]->pdschUe != 0)
310       {
311          continue; 
312       }
313
314       numK1 = k0K1InfoTbl->k0k1TimingInfo[pdcchTime->slot].k0Indexes[k0TblIdx].k1TimingInfo.numK1;
315       for(k1TblIdx = 0; k1TblIdx < numK1; k1TblIdx++)
316       {
317          k1Index = k0K1InfoTbl->k0k1TimingInfo[pdcchTime->slot].k0Indexes[k0TblIdx].k1TimingInfo.k1Indexes[k1TblIdx];
318          if(dedMsg != true)
319          {
320             k1Val = defaultUlAckTbl[k1Index];
321          }
322          else
323          {
324             if(ueCb->ueCfg.spCellCfg.servCellCfg.initUlBwp.pucchCfg.dlDataToUlAck)
325             {
326                k1Val = ueCb->ueCfg.spCellCfg.servCellCfg.initUlBwp.pucchCfg.dlDataToUlAck->dlDataToUlAckList[k1Index];
327             }
328          }
329          ADD_DELTA_TO_TIME((*pdschTime),(*pucchTime), k1Val, cell->numSlots);
330 #ifdef NR_TDD
331          if(schGetSlotSymbFrmt(pucchTime->slot, cell->slotFrmtBitMap) == DL_SLOT)
332          {
333             continue;
334          }
335 #endif
336          if(cell->schUlSlotInfo[pucchTime->slot]->pucchUe != 0)
337          {
338             continue; 
339          }
340          return true;
341       }
342    }
343    /*
344     * Number of symbols in case of retransmisson should be same as it was in
345     * original transmisson. Symbol availablity checks need to be added.
346     */
347    return false;
348 }
349
350 /*******************************************************************
351  *
352  * @brief 
353  *
354  * @details
355  *
356  *    Function : schFillBoGrantDlSchedInfo 
357  *
358  *    Functionality:
359  
360  *
361  * @params[in] SchCellCb *cell, SlotTimingInfo currTime, uint8_t ueId
362  * @params[in] bool isRetx, SchDlHqProcCb **hqP
363  * @return ROK     - success
364  *         RFAILED - failure
365  *
366  * ****************************************************************/
367 bool schFillBoGrantDlSchedInfo(SchCellCb *cell, SlotTimingInfo currTime, uint8_t ueId, bool isRetx, SchDlHqProcCb **hqP)
368 {
369    uint8_t lcIdx = 0;
370    uint8_t pdschNumSymbols = 0, pdschStartSymbol = 0;
371    uint16_t startPrb = 0, maxFreePRB = 0;
372    uint16_t crnti = 0, mcsIdx = 0;
373    uint32_t accumalatedSize = 0;
374    SchUeCb *ueCb = NULLP;
375    CmLListCp *lcLL = NULLP;
376    DlMsgAlloc *dciSlotAlloc, *dlMsgAlloc;
377    SlotTimingInfo pdcchTime, pdschTime, pucchTime;
378    uint16_t rsvdDedicatedPRB = 0;
379
380    /* TX_PAYLOAD_HDR_LEN: Overhead which is to be Added once for any UE while estimating Accumulated TB Size
381     * Following flag added to keep the record whether TX_PAYLOAD_HDR_LEN is added to the first Node getting allocated.
382     * If both Dedicated and Default LC lists are present then First LC in Dedicated List will include this overhead
383     * else if only Default list is present then first node in this List will add this overhead len*/
384    bool isTxPayloadLenAdded = FALSE;
385    GET_CRNTI(crnti,ueId);
386    ueCb = &cell->ueCb[ueId-1];
387
388    if (isRetx == FALSE)
389    {
390       if(schDlGetAvlHqProcess(cell, ueCb, hqP) != ROK)
391       {
392          return false;
393       }
394    }
395
396    if(findValidK0K1Value(cell, currTime, ueId, ueCb->ueCfg.spCellCfg.servCellCfg.initDlBwp.k0K1TblPrsnt,\
397             &pdschStartSymbol, &pdschNumSymbols, &pdcchTime, &pdschTime, &pucchTime, isRetx, *hqP) != true )
398    {
399       /* If a valid combination of slots to scheduled PDCCH, PDSCH and PUCCH is
400        * not found, do not perform resource allocation. Return from here. */
401       return false;
402    }
403    
404    /* allocate PDCCH and PDSCH resources for the ue */
405    if(cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] == NULL)
406    {
407
408       SCH_ALLOC(dciSlotAlloc, sizeof(DlMsgAlloc));
409       if(!dciSlotAlloc)
410       {
411          DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for ded DL msg alloc");
412          return false;
413       }
414       cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId -1] = dciSlotAlloc;
415       memset(dciSlotAlloc, 0, sizeof(DlMsgAlloc));
416       dciSlotAlloc->crnti = crnti;
417    }
418    else
419    {
420       dciSlotAlloc = cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId -1];
421    }
422    /* Dl ded Msg info is copied, this was earlier filled in macSchDlRlcBoInfo */
423    fillDlMsgInfo(&dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo].dlMsgInfo, dciSlotAlloc->crnti, isRetx, *hqP);
424    dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo].isRetx = isRetx;
425
426
427    if (isRetx == FALSE)
428    {
429       /*Re-Initalization per UE*/
430       /* scheduled LC data fill */
431       dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo].numLc = 0;
432       isTxPayloadLenAdded = FALSE; /*Re-initlaize the flag for every UE*/
433       accumalatedSize = 0;
434
435       for(lcIdx = 0; lcIdx < MAX_NUM_LC; lcIdx++)
436       {
437          if(ueCb->dlInfo.dlLcCtxt[lcIdx].bo)
438          {
439             /*Check the LC is Dedicated or default and accordingly LCList will
440             * be used*/
441             if(ueCb->dlInfo.dlLcCtxt[lcIdx].isDedicated)
442             {
443                lcLL = &((*hqP)->dlLcPrbEst.dedLcList);
444                rsvdDedicatedPRB = ueCb->dlInfo.dlLcCtxt[lcIdx].rsvdDedicatedPRB;
445             }
446             else
447             {
448                lcLL = &((*hqP)->dlLcPrbEst.defLcList);
449             }
450
451             /*[Step2]: Update the reqPRB and Payloadsize for this LC in the appropriate List*/
452             if(updateLcListReqPRB(lcLL, ueCb->dlInfo.dlLcCtxt[lcIdx].lcId,\
453                      (ueCb->dlInfo.dlLcCtxt[lcIdx].bo + MAC_HDR_SIZE)) != ROK)
454             {
455                DU_LOG("\nERROR  --> SCH : Updation in LC List Failed");
456                /* Free the dl ded msg info allocated in macSchDlRlcBoInfo */
457                if(dciSlotAlloc->numSchedInfo == 0)
458                {
459                   SCH_FREE(dciSlotAlloc, sizeof(DlMsgAlloc));
460                   cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId -1] = NULL;
461                }
462                else
463                   memset(&dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo], 0, sizeof(DlMsgSchInfo));
464                return false;
465             }
466          }
467          ueCb->dlInfo.dlLcCtxt[lcIdx].bo = 0;
468       }//End of for loop
469       if (((*hqP)->dlLcPrbEst.defLcList.count == 0) && ( ((*hqP)->dlLcPrbEst.dedLcList.count == 0)))
470       {
471          DU_LOG("\nDEBUG  -->  SCH : No pending BO for any LC id\n");
472          UNSET_ONE_BIT(ueId, cell->boIndBitMap);
473
474          /* Free the dl ded msg info allocated in macSchDlRlcBoInfo */
475          if(dciSlotAlloc->numSchedInfo == 0)
476          {
477             SCH_FREE(dciSlotAlloc, sizeof(DlMsgAlloc));
478             cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId -1] = NULL;
479          }
480          else
481             memset(&dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo], 0, sizeof(DlMsgSchInfo));
482
483          /*TRUE because this UE has nothing to be scheduled*/
484          return true;
485       }
486    }
487
488    /*[Step3]: Calculate Best FREE BLOCK with MAX PRB count*/
489    maxFreePRB = searchLargestFreeBlock(cell, pdschTime, &startPrb, DIR_DL);
490
491    /*[Step4]: Estimation of PRB and BO which can be allocated to each LC in
492     * the list based on RRM policy*/
493
494    /*Either this UE contains no reservedPRB pool fir dedicated S-NSSAI or 
495     * Num of Free PRB available is not enough to reserve Dedicated PRBs*/
496    if(isRetx == FALSE)
497    {
498       if(maxFreePRB != 0)
499       {
500          mcsIdx = ueCb->ueCfg.dlModInfo.mcsIndex;
501
502          if(((*hqP)->dlLcPrbEst.dedLcList.count == NULLP) 
503                || ((maxFreePRB < rsvdDedicatedPRB)))
504          { 
505             (*hqP)->dlLcPrbEst.sharedNumPrb = maxFreePRB;
506             DU_LOG("\nDEBUG  --> SCH : DL Only Default Slice is scheduled, sharedPRB Count:%d",\
507                   (*hqP)->dlLcPrbEst.sharedNumPrb);
508
509             /*PRB Alloc for Default LCs*/
510             prbAllocUsingRRMPolicy(&((*hqP)->dlLcPrbEst.defLcList), FALSE, mcsIdx, pdschNumSymbols,\
511                   &((*hqP)->dlLcPrbEst.sharedNumPrb), NULLP, &isTxPayloadLenAdded, NULLP);
512          }
513          else
514          {
515             (*hqP)->dlLcPrbEst.sharedNumPrb = maxFreePRB - rsvdDedicatedPRB;
516             /*PRB Alloc for Dedicated LCs*/
517             prbAllocUsingRRMPolicy(&((*hqP)->dlLcPrbEst.dedLcList), TRUE, mcsIdx, pdschNumSymbols,\
518                   &((*hqP)->dlLcPrbEst.sharedNumPrb), &(rsvdDedicatedPRB), &isTxPayloadLenAdded, NULLP);
519
520             /*PRB Alloc for Default LCs*/
521             prbAllocUsingRRMPolicy(&((*hqP)->dlLcPrbEst.defLcList), FALSE, mcsIdx, pdschNumSymbols, \
522                   &((*hqP)->dlLcPrbEst.sharedNumPrb), &(rsvdDedicatedPRB), &isTxPayloadLenAdded, NULLP);
523          }
524       }
525    }
526
527    /*[Step5]:Traverse each LCID in LcList to calculate the exact Scheduled Bytes
528     * using allocated BO per LC and Update dlMsgAlloc(BO report for MAC*/
529    if (isRetx == FALSE)
530    {
531       if((*hqP)->dlLcPrbEst.dedLcList.count != 0)
532          updateGrantSizeForBoRpt(&((*hqP)->dlLcPrbEst.dedLcList), dciSlotAlloc, NULLP, &(accumalatedSize));
533
534       updateGrantSizeForBoRpt(&((*hqP)->dlLcPrbEst.defLcList), dciSlotAlloc, NULLP, &(accumalatedSize));
535    }
536    else
537    {
538       accumalatedSize = (*hqP)->tbInfo[0].tbSzReq;
539    }
540
541    /*Below case will hit if NO LC(s) are allocated due to resource crunch*/
542    if (!accumalatedSize)
543    {
544       if(maxFreePRB == 0)
545       {
546          DU_LOG("\nERROR  --> SCH : NO FREE PRB!!");
547       }
548       else
549       {
550          /*Schedule the LC for next slot*/
551          DU_LOG("\nDEBUG  -->  SCH : No LC has been scheduled");
552       }
553       /* Not Freeing dlMsgAlloc as ZERO BO REPORT to be sent to RLC so that
554        * Allocation can be done in next slot*/
555       return false;
556    }
557
558    /*[Step6]: pdcch and pdsch data is filled */
559    if((schDlRsrcAllocDlMsg(cell, pdschTime, crnti, accumalatedSize, dciSlotAlloc, startPrb, pdschStartSymbol, pdschNumSymbols, isRetx, *hqP)) != ROK)
560    {
561       DU_LOG("\nERROR  --> SCH : Scheduling of DL dedicated message failed");
562
563       /* Free the dl ded msg info allocated in macSchDlRlcBoInfo */
564       if(dciSlotAlloc->numSchedInfo == 0)
565       {
566          SCH_FREE(dciSlotAlloc, sizeof(DlMsgAlloc));
567          cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId -1] = NULL;
568       }
569       else
570       {
571          memset(&dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo], 0, sizeof(DlMsgSchInfo));
572       }
573       return false;
574    }
575
576    /* TODO : Update the scheduling byte report for multiple LC based on QCI
577     * and Priority */
578    /* As of now, the total number of bytes scheduled for a slot is divided
579     * equally amongst all LC with pending data. This is avoid starving of any
580     * LC 
581     * */
582 #if 0
583    accumalatedSize = accumalatedSize/dlMsgAlloc->numLc;
584    for(lcIdx = 0; lcIdx < dlMsgAlloc->numLc; lcIdx ++)
585       dlMsgAlloc->lcSchInfo[lcIdx].schBytes = accumalatedSize;
586 #endif
587    
588    /* Check if both DCI and DL_MSG are sent in the same slot.
589     * If not, allocate memory for DL_MSG PDSCH slot to store PDSCH info */
590
591    if(pdcchTime.slot == pdschTime.slot)
592    {
593       dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo].pduPres = BOTH;
594       dciSlotAlloc->numSchedInfo++;
595    }
596    else
597    {
598       /* Allocate memory to schedule dlMsgAlloc to send DL_Msg, pointer will be checked at schProcessSlotInd() */
599       if(cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1] == NULLP)
600       {
601          SCH_ALLOC(dlMsgAlloc, sizeof(DlMsgAlloc));
602          if(dlMsgAlloc == NULLP)
603          {
604             DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for dlMsgAlloc");
605             if(dciSlotAlloc->numSchedInfo == 0)
606             {
607                SCH_FREE(dciSlotAlloc, sizeof(DlMsgAlloc));
608                cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
609             }
610             else
611                memset(&dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo], 0, sizeof(DlMsgSchInfo));
612             return false;
613          }
614          cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1] = dlMsgAlloc;
615          memset(dlMsgAlloc, 0, sizeof(DlMsgAlloc));
616          dlMsgAlloc->crnti = dciSlotAlloc->crnti;
617       }
618       else
619          dlMsgAlloc = cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1];
620
621       /* Copy all DL_MSG info */
622       memcpy(&dlMsgAlloc->dlMsgSchedInfo[dlMsgAlloc->numSchedInfo], \
623             &dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo], sizeof(DlMsgSchInfo));
624       dlMsgAlloc->dlMsgSchedInfo[dlMsgAlloc->numSchedInfo].dlMsgPdcchCfg.dci.pdschCfg = \
625             &dlMsgAlloc->dlMsgSchedInfo[dlMsgAlloc->numSchedInfo].dlMsgPdschCfg;
626
627       /* Assign correct PDU types in corresponding slots */
628       dlMsgAlloc->dlMsgSchedInfo[dlMsgAlloc->numSchedInfo].pduPres = PDSCH_PDU;
629       dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo].pduPres = PDCCH_PDU;
630       dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo].pdschSlot = pdschTime.slot;
631
632       dciSlotAlloc->numSchedInfo++;
633       dlMsgAlloc->numSchedInfo++;
634    }
635
636    schAllocPucchResource(cell, pucchTime, crnti, ueCb, isRetx, *hqP);
637
638    cell->schDlSlotInfo[pdcchTime.slot]->pdcchUe = ueId;
639    cell->schDlSlotInfo[pdschTime.slot]->pdschUe = ueId;
640    cell->schUlSlotInfo[pucchTime.slot]->pucchUe = ueId;
641
642    /* after allocation is done, unset the bo bit for that ue */
643    UNSET_ONE_BIT(ueId, cell->boIndBitMap);
644    return true;
645 }
646
647 /*******************************************************************
648 *
649 * @brief Process DL Resource allocation for Page
650 *
651 * @details
652 *
653 *    Function : schProcDlPageAlloc
654 *
655 *    Functionality: Process DL Resource allocation for Page
656 *
657 * @params[in] SchCellCb *cell, SlotTimingInfo currTime, Inst schInst
658 *
659 * @return pointer to return Value(ROK, RFAILED)
660 *
661 * ****************************************************************/
662 uint8_t schProcDlPageAlloc(SchCellCb *cell, SlotTimingInfo currTime, Inst schInst)
663 {
664    DlPageAlloc      dlPageAlloc;
665    CmLList          *pageInfoNode = NULLP;
666    SchPageInfo      *pageInfo = NULLP;
667    SlotTimingInfo   pdschTime;
668    uint32_t         tbSize = 0;
669    uint16_t         startPrb = 0, maxFreePRB = 0, nPRB = 0;
670    uint8_t          ret = RFAILED;
671
672    pageInfoNode = schPageInfoSearchFromPageList(currTime, &(cell->pageCb.pageIndInfoRecord[currTime.sfn]));
673
674    if(pageInfoNode == NULLP)
675    {
676       return ROK;
677    }
678    pageInfo = (SchPageInfo *)pageInfoNode->node;
679    
680    while(true)
681    {
682       dlPageAlloc.cellId = currTime.cellId;
683
684       ADD_DELTA_TO_TIME(currTime, dlPageAlloc.dlPageTime, PHY_DELTA_DL + SCHED_DELTA, cell->numSlots);
685       dlPageAlloc.shortMsgInd  = FALSE;
686       pdschTime = dlPageAlloc.dlPageTime;
687
688       /*Calculate Best FREE BLOCK with MAX PRB count*/
689       maxFreePRB = searchLargestFreeBlock(cell, pdschTime, &startPrb, DIR_DL);
690
691       if(maxFreePRB != 0)
692       {
693          tbSize = calculateEstimateTBSize(pageInfo->msgLen, pageInfo->mcs, NUM_PDSCH_SYMBOL, maxFreePRB, &nPRB);
694       }
695       else
696       {
697          DU_LOG("\nERROR  --> SCH: Unable to get any free block for Paging at SFN:%d, SLOT:%d",\
698                pdschTime.sfn, pdschTime.slot);
699          break;
700       }
701       /*Fill PDCCH: PDCCH Cfg is same as SIB1 as Paging will be a broadcast message*/
702       memcpy(&dlPageAlloc.pagePdcchCfg, &cell->cellCfg.sib1SchCfg.sib1PdcchCfg, sizeof(PdcchCfg));
703       dlPageAlloc.pagePdcchCfg.dci.rnti = P_RNTI;
704
705       /*Fill BWP*/
706       memcpy(&dlPageAlloc.bwp, &cell->cellCfg.sib1SchCfg.bwp, sizeof(BwpCfg)); 
707
708       /*Fill PDSCH*/
709       if(schFillPagePdschCfg(cell, &dlPageAlloc.pagePdschCfg, pdschTime, tbSize, pageInfo->mcs, startPrb) != ROK)
710       {
711          DU_LOG("\nERROR  --> SCH: Issue in PDSCH Allocation for Paging at SFN:%d, SLOT:%d",\
712                pdschTime.sfn, pdschTime.slot);
713          break;
714       }
715       dlPageAlloc.pagePdcchCfg.dci.pdschCfg = &dlPageAlloc.pagePdschCfg;
716
717       /*Fill Page PDU information*/
718       dlPageAlloc.dlPagePduLen = pageInfo->msgLen;
719
720       SCH_ALLOC(dlPageAlloc.dlPagePdu, sizeof(dlPageAlloc.dlPagePduLen));
721
722       if(dlPageAlloc.dlPagePdu == NULLP)
723       {
724          DU_LOG("\nERROR  --> SCH: Memory Allocation Failed during Page Resource allocation");
725          break;
726       }
727       memcpy(dlPageAlloc.dlPagePdu, pageInfo->pagePdu, dlPageAlloc.dlPagePduLen);
728
729       /* Send msg to MAC */
730       if(sendDlPageAllocToMac(&dlPageAlloc, schInst) != ROK)
731       {
732          DU_LOG("\nERROR  -->  SCH : Sending DL Paging allocation from SCH to MAC failed");
733          SCH_FREE(dlPageAlloc.dlPagePdu, sizeof(dlPageAlloc.dlPagePduLen));
734          break;
735       }
736       ret = ROK;
737       break;
738    }
739
740    /*Remove the Page Node*/
741    SCH_FREE(pageInfo->pagePdu, pageInfo->msgLen);
742    schDeleteFromPageInfoList(&(cell->pageCb.pageIndInfoRecord[currTime.sfn]), pageInfoNode);
743
744    return(ret);
745
746 }
747
748 /*******************************************************************
749  *
750  * @brief Handles slot indication at SCH 
751  *
752  * @details
753  *
754  *    Function : schProcessSlotInd
755  *
756  *    Functionality:
757  *     Handles TTI indication received from PHY
758  *
759  * @params[in] 
760  * @return ROK     - success
761  *         RFAILED - failure
762  *
763  * ****************************************************************/
764 uint8_t schProcessSlotInd(SlotTimingInfo *slotInd, Inst schInst)
765 {
766    uint8_t   ueId, ueIdx, ret = ROK;
767    uint16_t  slot;
768    bool      isRarPending = false, isRarScheduled = false;
769    bool      isMsg4Pending = false, isMsg4Scheduled = false;
770    bool      isUlGrantPending = false, isUlGrantScheduled = false;
771    bool      isDlMsgPending = false, isDlMsgScheduled = false;
772    CmLList        *pendingUeNode;
773    DlSchedInfo    dlSchedInfo;
774    DlBrdcstAlloc  *dlBrdcstAlloc = NULLP;
775    SchCellCb      *cell = NULLP;
776    CmLList        *node;
777    uint8_t*       ueNode;
778    SchDlHqProcCb  *hqP = NULLP;
779    SchUlHqProcCb *ulHqP = NULLP;
780
781    cell = schCb[schInst].cells[schInst];
782    if(cell == NULLP)
783    {
784       DU_LOG("\nERROR  -->  SCH : Cell Does not exist");
785       return RFAILED;
786    }
787    memset(&dlSchedInfo, 0, sizeof(DlSchedInfo));
788    schCalcSlotValues(*slotInd, &dlSchedInfo.schSlotValue, cell->numSlots);
789    dlBrdcstAlloc = &dlSchedInfo.brdcstAlloc;
790    dlBrdcstAlloc->ssbTrans = NO_TRANSMISSION;
791    dlBrdcstAlloc->sib1Trans = NO_TRANSMISSION;
792
793    memcpy(&cell->slotInfo, slotInd, sizeof(SlotTimingInfo));
794    dlBrdcstAlloc->ssbIdxSupported = SSB_IDX_SUPPORTED;
795
796    dlSchedInfo.cellId = cell->cellId;
797    slot = dlSchedInfo.schSlotValue.broadcastTime.slot;
798
799 #ifdef NR_DRX 
800    schHandleStartDrxTimer(cell);
801 #endif
802    
803    /* Check for SSB occassion */
804    dlBrdcstAlloc->ssbTrans = schCheckSsbOcc(cell, dlSchedInfo.schSlotValue.broadcastTime); 
805    if(dlBrdcstAlloc->ssbTrans)
806    {
807       if(schBroadcastSsbAlloc(cell, dlSchedInfo.schSlotValue.broadcastTime, dlBrdcstAlloc) != ROK)
808       {
809          DU_LOG("\nERROR  -->  SCH : schBroadcastSsbAlloc failed");
810          dlBrdcstAlloc->ssbTrans = NO_TRANSMISSION;
811       }
812       else 
813       {
814          dlSchedInfo.isBroadcastPres = true;
815          if((dlBrdcstAlloc->ssbTrans == NEW_TRANSMISSION) && (!cell->firstSsbTransmitted))
816             cell->firstSsbTransmitted = true;
817       }
818    }
819
820    /* Check for SIB1 occassion */
821    dlBrdcstAlloc->sib1Trans = schCheckSib1Occ(cell, dlSchedInfo.schSlotValue.broadcastTime);
822    if(dlBrdcstAlloc->sib1Trans)
823    {
824       if(schBroadcastSib1Alloc(cell, dlSchedInfo.schSlotValue.broadcastTime, dlBrdcstAlloc) != ROK)
825       {
826          DU_LOG("\nERROR  -->  SCH : schBroadcastSib1Alloc failed");
827          dlBrdcstAlloc->sib1Trans = NO_TRANSMISSION;
828       }
829       else 
830       {
831          dlSchedInfo.isBroadcastPres = true;
832          if((dlBrdcstAlloc->sib1Trans == NEW_TRANSMISSION) && (!cell->firstSib1Transmitted))
833             cell->firstSib1Transmitted = true;
834       }
835    }
836
837    /*Process Paging Msg*/
838    schProcDlPageAlloc(cell, *slotInd, schInst);
839
840    /* Select first UE in the linked list to be scheduled next */
841    pendingUeNode = cell->ueToBeScheduled.first;
842    if(pendingUeNode)
843    {
844       if(pendingUeNode->node)
845       {
846          ueNode = (uint8_t *)pendingUeNode->node;
847          ueId = *(uint8_t *)(pendingUeNode->node);
848          /* If RAR is pending for this UE, schedule PDCCH,PDSCH to send RAR and 
849           * PUSCH to receive MSG3 as per k0-k2 configuration*/
850          if(cell->raReq[ueId-1] != NULLP)
851          {
852             isRarPending = true;
853             isRarScheduled = schProcessRaReq(schInst, cell, *slotInd, ueId);
854          }
855
856          /*MSG3 retransmisson*/
857          if(cell->raCb[ueId-1].retxMsg3HqProc)
858          {            
859             schMsg3RetxSchedulingForUe(&(cell->raCb[ueId-1]));
860          }
861
862          /* If MSG4 is pending for this UE, schedule PDCCH,PDSCH to send MSG4 and
863           * PUCCH to receive UL msg as per k0-k1 configuration  */
864          if (cell->ueCb[ueId-1].retxMsg4HqProc) //should work from dlmap later tbd
865          {
866             /* Retransmission of MSG4 */
867             isMsg4Pending = true;
868             if(schProcessMsg4Req(cell, *slotInd, ueId, TRUE, &cell->ueCb[ueId-1].retxMsg4HqProc) == ROK)
869                isMsg4Scheduled = true;
870          }
871          else
872          {
873             /* First transmission of MSG4 */
874             if(cell->raCb[ueId-1].msg4recvd)
875             {
876                isMsg4Pending = true;
877                if(schProcessMsg4Req(cell, *slotInd, ueId, FALSE, &cell->ueCb[ueId-1].msg4Proc) == ROK)
878                   isMsg4Scheduled = true;
879
880                /* If MSG4 scheduling failed, free the newly assigned HARQ process */
881                if(!isMsg4Scheduled)
882                   schDlReleaseHqProcess(cell->ueCb[ueId-1].msg4Proc);
883             }
884          }
885
886          if(isRarPending || isMsg4Pending)
887          {
888             /* If RAR or MSG is successfully scheduled then
889              * remove UE from linked list since no pending msgs for this UE */
890             if(isRarScheduled || isMsg4Scheduled)
891             {
892                SCH_FREE(pendingUeNode->node, sizeof(uint8_t));
893                deleteNodeFromLList(&cell->ueToBeScheduled, pendingUeNode);
894             }
895             /* If RAR/MSG4 is pending but couldnt be scheduled then,
896              * put this UE at the end of linked list to be scheduled later */
897             else
898             {
899                cmLListAdd2Tail(&cell->ueToBeScheduled, cmLListDelFrm(&cell->ueToBeScheduled, pendingUeNode));
900             }
901          }
902
903 #ifdef NR_DRX 
904          if((cell->ueCb[ueId-1].ueDrxInfoPres == true) && (cell->ueCb[ueId-1].drxUeCb.drxDlUeActiveStatus != true))
905          {
906             if(pendingUeNode->node)
907             {
908                cmLListAdd2Tail(&cell->ueToBeScheduled, cmLListDelFrm(&cell->ueToBeScheduled, pendingUeNode));
909             }
910          }
911          else 
912 #endif
913          {
914             
915             /* DL Data */
916             node = cell->ueCb[ueId-1].dlRetxHqList.first;
917             if(node != NULLP)
918             {
919                /* DL Data ReTransmisson */
920                isDlMsgPending = true;
921                isDlMsgScheduled = schFillBoGrantDlSchedInfo(cell, *slotInd, ueId, TRUE, ((SchDlHqProcCb**) &(node->node)));
922                cmLListDelFrm(&cell->ueCb[ueId-1].dlRetxHqList, node);
923             }
924             else
925             {
926                /* DL Data new transmission */
927                if((cell->boIndBitMap) & (1<<ueId))
928                {
929                   isDlMsgPending = true;               
930                   isDlMsgScheduled = schFillBoGrantDlSchedInfo(cell, *slotInd, ueId, FALSE, &hqP);
931
932                   /* If DL scheduling failed, free the newly assigned HARQ process */
933                   if(!isDlMsgScheduled)
934                      schDlReleaseHqProcess(hqP);
935                }
936             }
937
938             /* Scheduling of UL grant */
939             node = cell->ueCb[ueId-1].ulRetxHqList.first;
940             if(node != NULLP)
941             {
942                /* UL Data ReTransmisson */
943                isUlGrantPending = true;
944                isUlGrantScheduled = schProcessSrOrBsrReq(cell, *slotInd, ueId, TRUE, (SchUlHqProcCb**) &(node->node));
945                cmLListDelFrm(&cell->ueCb[ueId-1].ulRetxHqList, node);
946             }
947             else
948             {
949                /* UL Data new transmission */
950                if(cell->ueCb[ueId-1].srRcvd || cell->ueCb[ueId-1].bsrRcvd)
951                {
952                   isUlGrantPending = true;
953                   isUlGrantScheduled = schProcessSrOrBsrReq(cell, *slotInd, ueId, FALSE, &ulHqP);
954                   if(!isUlGrantScheduled)
955                      schUlReleaseHqProcess(ulHqP, FALSE);
956                }
957             }
958
959             if(!isUlGrantPending && !isDlMsgPending)
960             {
961                /* No action required */  
962             }
963             else if((isUlGrantPending && !isUlGrantScheduled) || (isDlMsgPending && !isDlMsgScheduled))
964             {
965                cmLListAdd2Tail(&cell->ueToBeScheduled, cmLListDelFrm(&cell->ueToBeScheduled, pendingUeNode));
966             }
967             else
968             {
969                SCH_FREE(ueNode, sizeof(uint8_t));
970                deleteNodeFromLList(&cell->ueToBeScheduled, pendingUeNode);
971             }
972          }
973       }
974    }
975
976    /* Check if any PDU is scheduled at this slot for any UE */
977    for(ueIdx=0; ueIdx<MAX_NUM_UE; ueIdx++)
978    {
979       /* If RAR PDCCH/PDSCH is scheduled for a UE at this slot, fill RAR specific interface 
980        * structure to send to MAC */
981       if(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.rarTime.slot]->rarAlloc[ueIdx] != NULLP)
982       {
983          slot = dlSchedInfo.schSlotValue.rarTime.slot;
984          dlSchedInfo.rarAlloc[ueIdx] = cell->schDlSlotInfo[slot]->rarAlloc[ueIdx];
985          cell->schDlSlotInfo[slot]->rarAlloc[ueIdx] = NULLP;
986       }
987
988       /* If DL-Msg PDCCH/PDSCH is scheduled for a UE at this slot, fill 
989        * specific interface structure to send to MAC */
990       if(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.dlMsgTime.slot]->dlMsgAlloc[ueIdx] != NULLP)
991       {
992          slot = dlSchedInfo.schSlotValue.dlMsgTime.slot;
993          dlSchedInfo.dlMsgAlloc[ueIdx] = cell->schDlSlotInfo[slot]->dlMsgAlloc[ueIdx];
994          cell->schDlSlotInfo[slot]->dlMsgAlloc[ueIdx] = NULLP;
995       }
996    }
997
998    if(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.ulDciTime.slot]->ulGrant != NULLP)
999    {
1000       slot = dlSchedInfo.schSlotValue.ulDciTime.slot;
1001       dlSchedInfo.ulGrant = cell->schDlSlotInfo[slot]->ulGrant;
1002       cell->schDlSlotInfo[slot]->ulGrant = NULLP;
1003    }
1004
1005    /* Send msg to MAC */
1006    ret = sendDlAllocToMac(&dlSchedInfo, schInst);
1007    if(ret != ROK)
1008    {
1009       DU_LOG("\nERROR  -->  SCH : Sending DL Broadcast allocation from SCH to MAC failed");
1010       return (ret);
1011    }
1012
1013    schInitDlSlot(cell->schDlSlotInfo[slot]);
1014    schUlResAlloc(cell, schInst);
1015 #ifdef NR_DRX 
1016    schHandleExpiryDrxTimer(cell);
1017 #endif   
1018    return ret;
1019 }
1020
1021 /**********************************************************************
1022   End of file
1023  **********************************************************************/
1024
1025