61992eb909c555f0c5f3acd0376a8f9404a6b98d
[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 #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.servCellRecfg.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.servCellRecfg.initDlBwp.pdschCfg.timeDomRsrcAllociList[k0Index].k0 != NULLP)
295          {
296             k0Val = *(ueCb->ueCfg.spCellCfg.servCellRecfg.initDlBwp.pdschCfg.timeDomRsrcAllociList[k0Index].k0);
297             *pdschStartSymbol = ueCb->ueCfg.spCellCfg.servCellRecfg.initDlBwp.pdschCfg.timeDomRsrcAllociList[k0Index].startSymbol;
298             *pdschSymblLen = ueCb->ueCfg.spCellCfg.servCellRecfg.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.servCellRecfg.initUlBwp.pucchCfg.dlDataToUlAck)
325             {
326                k1Val = ueCb->ueCfg.spCellCfg.servCellRecfg.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          if(hqP)
341          {
342             ADD_DELTA_TO_TIME((*pucchTime), hqP->pucchTime, 0, cell->numSlots);
343          }
344          return true;
345       }
346    }
347    /*
348     * Number of symbols in case of retransmisson should be same as it was in
349     * original transmisson. Symbol availablity checks need to be added.
350     */
351    return false;
352 }
353
354 /*******************************************************************
355  *
356  * @brief 
357  *
358  * @details
359  *
360  *    Function : schFillBoGrantDlSchedInfo 
361  *
362  *    Functionality:
363  
364  *
365  * @params[in] SchCellCb *cell, SlotTimingInfo currTime, uint8_t ueId
366  * @params[in] bool isRetx, SchDlHqProcCb **hqP
367  * @return ROK     - success
368  *         RFAILED - failure
369  *
370  * ****************************************************************/
371 bool schFillBoGrantDlSchedInfo(SchCellCb *cell, SlotTimingInfo currTime, uint8_t ueId, bool isRetx, SchDlHqProcCb **hqP)
372 {
373    uint8_t lcIdx = 0;
374    uint8_t pdschNumSymbols = 0, pdschStartSymbol = 0;
375    uint16_t startPrb = 0, maxFreePRB = 0;
376    uint16_t crnti = 0, mcsIdx = 0;
377    uint32_t accumalatedSize = 0;
378    SchUeCb *ueCb = NULLP;
379    CmLListCp *lcLL = NULLP;
380    DlMsgAlloc *dciSlotAlloc, *dlMsgAlloc;
381    SlotTimingInfo pdcchTime, pdschTime, pucchTime;
382    uint16_t rsvdDedicatedPRB = 0;
383
384    /* TX_PAYLOAD_HDR_LEN: Overhead which is to be Added once for any UE while estimating Accumulated TB Size
385     * Following flag added to keep the record whether TX_PAYLOAD_HDR_LEN is added to the first Node getting allocated.
386     * If both Dedicated and Default LC lists are present then First LC in Dedicated List will include this overhead
387     * else if only Default list is present then first node in this List will add this overhead len*/
388    bool isTxPayloadLenAdded = FALSE;
389    GET_CRNTI(crnti,ueId);
390    ueCb = &cell->ueCb[ueId-1];
391
392    if (isRetx == FALSE)
393    {
394       if(schDlGetAvlHqProcess(cell, ueCb, hqP) != ROK)
395       {
396          return false;
397       }
398    }
399
400    if(findValidK0K1Value(cell, currTime, ueId, ueCb->ueCfg.spCellCfg.servCellRecfg.initDlBwp.k0K1TblPrsnt,\
401             &pdschStartSymbol, &pdschNumSymbols, &pdcchTime, &pdschTime, &pucchTime, isRetx, *hqP) != true )
402    {
403       /* If a valid combination of slots to scheduled PDCCH, PDSCH and PUCCH is
404        * not found, do not perform resource allocation. Return from here. */
405       return false;
406    }
407    
408    /* allocate PDCCH and PDSCH resources for the ue */
409    if(cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] == NULL)
410    {
411
412       SCH_ALLOC(dciSlotAlloc, sizeof(DlMsgAlloc));
413       if(!dciSlotAlloc)
414       {
415          DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for ded DL msg alloc");
416          return false;
417       }
418       cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId -1] = dciSlotAlloc;
419       memset(dciSlotAlloc, 0, sizeof(DlMsgAlloc));
420       dciSlotAlloc->crnti = crnti;
421    }
422    else
423    {
424       dciSlotAlloc = cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId -1];
425    }
426    /* Dl ded Msg info is copied, this was earlier filled in macSchDlRlcBoInfo */
427    fillDlMsgInfo(&dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo].dlMsgInfo, dciSlotAlloc->crnti, isRetx, *hqP);
428    dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo].isRetx = isRetx;
429
430
431    if (isRetx == FALSE)
432    {
433       /*Re-Initalization per UE*/
434       /* scheduled LC data fill */
435       dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo].numLc = 0;
436       isTxPayloadLenAdded = FALSE; /*Re-initlaize the flag for every UE*/
437       accumalatedSize = 0;
438
439       for(lcIdx = 0; lcIdx < MAX_NUM_LC; lcIdx++)
440       {
441          if(ueCb->dlInfo.dlLcCtxt[lcIdx].bo)
442          {
443             /*Check the LC is Dedicated or default and accordingly LCList will
444             * be used*/
445             if(ueCb->dlInfo.dlLcCtxt[lcIdx].isDedicated)
446             {
447                lcLL = &((*hqP)->dlLcPrbEst.dedLcList);
448                rsvdDedicatedPRB = ueCb->dlInfo.dlLcCtxt[lcIdx].rsvdDedicatedPRB;
449             }
450             else
451             {
452                lcLL = &((*hqP)->dlLcPrbEst.defLcList);
453             }
454
455             /*[Step2]: Update the reqPRB and Payloadsize for this LC in the appropriate List*/
456             if(updateLcListReqPRB(lcLL, ueCb->dlInfo.dlLcCtxt[lcIdx].lcId,\
457                      (ueCb->dlInfo.dlLcCtxt[lcIdx].bo + MAC_HDR_SIZE)) != ROK)
458             {
459                DU_LOG("\nERROR  --> SCH : Updation in LC List Failed");
460                /* Free the dl ded msg info allocated in macSchDlRlcBoInfo */
461                if(dciSlotAlloc->numSchedInfo == 0)
462                {
463                   SCH_FREE(dciSlotAlloc, sizeof(DlMsgAlloc));
464                   cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId -1] = NULL;
465                }
466                else
467                   memset(&dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo], 0, sizeof(DlMsgSchInfo));
468                return false;
469             }
470          }
471          ueCb->dlInfo.dlLcCtxt[lcIdx].bo = 0;
472       }//End of for loop
473       if (((*hqP)->dlLcPrbEst.defLcList.count == 0) && ( ((*hqP)->dlLcPrbEst.dedLcList.count == 0)))
474       {
475          DU_LOG("\nDEBUG  -->  SCH : No pending BO for any LC id\n");
476          UNSET_ONE_BIT(ueId, cell->boIndBitMap);
477
478          /* Free the dl ded msg info allocated in macSchDlRlcBoInfo */
479          if(dciSlotAlloc->numSchedInfo == 0)
480          {
481             SCH_FREE(dciSlotAlloc, sizeof(DlMsgAlloc));
482             cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId -1] = NULL;
483          }
484          else
485             memset(&dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo], 0, sizeof(DlMsgSchInfo));
486
487          /*TRUE because this UE has nothing to be scheduled*/
488          return true;
489       }
490    }
491
492    /*[Step3]: Calculate Best FREE BLOCK with MAX PRB count*/
493    maxFreePRB = searchLargestFreeBlock(cell, pdschTime, &startPrb, DIR_DL);
494
495    /*[Step4]: Estimation of PRB and BO which can be allocated to each LC in
496     * the list based on RRM policy*/
497
498    /*Either this UE contains no reservedPRB pool fir dedicated S-NSSAI or 
499     * Num of Free PRB available is not enough to reserve Dedicated PRBs*/
500    if(isRetx == FALSE)
501    {
502       if(maxFreePRB != 0)
503       {
504          mcsIdx = ueCb->ueCfg.dlModInfo.mcsIndex;
505
506          if(((*hqP)->dlLcPrbEst.dedLcList.count == NULLP) 
507                || ((maxFreePRB < rsvdDedicatedPRB)))
508          { 
509             (*hqP)->dlLcPrbEst.sharedNumPrb = maxFreePRB;
510             DU_LOG("\nDEBUG  --> SCH : DL Only Default Slice is scheduled, sharedPRB Count:%d",\
511                   (*hqP)->dlLcPrbEst.sharedNumPrb);
512
513             /*PRB Alloc for Default LCs*/
514             prbAllocUsingRRMPolicy(&((*hqP)->dlLcPrbEst.defLcList), FALSE, mcsIdx, pdschNumSymbols,\
515                   &((*hqP)->dlLcPrbEst.sharedNumPrb), NULLP, &isTxPayloadLenAdded, NULLP);
516          }
517          else
518          {
519             (*hqP)->dlLcPrbEst.sharedNumPrb = maxFreePRB - rsvdDedicatedPRB;
520             /*PRB Alloc for Dedicated LCs*/
521             prbAllocUsingRRMPolicy(&((*hqP)->dlLcPrbEst.dedLcList), TRUE, mcsIdx, pdschNumSymbols,\
522                   &((*hqP)->dlLcPrbEst.sharedNumPrb), &(rsvdDedicatedPRB), &isTxPayloadLenAdded, NULLP);
523
524             /*PRB Alloc for Default LCs*/
525             prbAllocUsingRRMPolicy(&((*hqP)->dlLcPrbEst.defLcList), FALSE, mcsIdx, pdschNumSymbols, \
526                   &((*hqP)->dlLcPrbEst.sharedNumPrb), &(rsvdDedicatedPRB), &isTxPayloadLenAdded, NULLP);
527          }
528       }
529    }
530
531    /*[Step5]:Traverse each LCID in LcList to calculate the exact Scheduled Bytes
532     * using allocated BO per LC and Update dlMsgAlloc(BO report for MAC*/
533    if (isRetx == FALSE)
534    {
535       if((*hqP)->dlLcPrbEst.dedLcList.count != 0)
536          updateGrantSizeForBoRpt(&((*hqP)->dlLcPrbEst.dedLcList), dciSlotAlloc, NULLP, &(accumalatedSize));
537
538       updateGrantSizeForBoRpt(&((*hqP)->dlLcPrbEst.defLcList), dciSlotAlloc, NULLP, &(accumalatedSize));
539    }
540    else
541    {
542       accumalatedSize = (*hqP)->tbInfo[0].tbSzReq;
543    }
544
545    /*Below case will hit if NO LC(s) are allocated due to resource crunch*/
546    if (!accumalatedSize)
547    {
548       if(maxFreePRB == 0)
549       {
550          DU_LOG("\nERROR  --> SCH : NO FREE PRB!!");
551       }
552       else
553       {
554          /*Schedule the LC for next slot*/
555          DU_LOG("\nDEBUG  -->  SCH : No LC has been scheduled");
556       }
557       /* Not Freeing dlMsgAlloc as ZERO BO REPORT to be sent to RLC so that
558        * Allocation can be done in next slot*/
559       return false;
560    }
561
562    /*[Step6]: pdcch and pdsch data is filled */
563    if((schDlRsrcAllocDlMsg(cell, pdschTime, crnti, accumalatedSize, dciSlotAlloc, startPrb, pdschStartSymbol, pdschNumSymbols, isRetx, *hqP)) != ROK)
564    {
565       DU_LOG("\nERROR  --> SCH : Scheduling of DL dedicated message failed");
566
567       /* Free the dl ded msg info allocated in macSchDlRlcBoInfo */
568       if(dciSlotAlloc->numSchedInfo == 0)
569       {
570          SCH_FREE(dciSlotAlloc, sizeof(DlMsgAlloc));
571          cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId -1] = NULL;
572       }
573       else
574       {
575          memset(&dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo], 0, sizeof(DlMsgSchInfo));
576       }
577       return false;
578    }
579
580    /* TODO : Update the scheduling byte report for multiple LC based on QCI
581     * and Priority */
582    /* As of now, the total number of bytes scheduled for a slot is divided
583     * equally amongst all LC with pending data. This is avoid starving of any
584     * LC 
585     * */
586 #if 0
587    accumalatedSize = accumalatedSize/dlMsgAlloc->numLc;
588    for(lcIdx = 0; lcIdx < dlMsgAlloc->numLc; lcIdx ++)
589       dlMsgAlloc->lcSchInfo[lcIdx].schBytes = accumalatedSize;
590 #endif
591    
592    /* Check if both DCI and DL_MSG are sent in the same slot.
593     * If not, allocate memory for DL_MSG PDSCH slot to store PDSCH info */
594
595    if(pdcchTime.slot == pdschTime.slot)
596    {
597       dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo].pduPres = BOTH;
598       dciSlotAlloc->numSchedInfo++;
599    }
600    else
601    {
602       /* Allocate memory to schedule dlMsgAlloc to send DL_Msg, pointer will be checked at schProcessSlotInd() */
603       if(cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1] == NULLP)
604       {
605          SCH_ALLOC(dlMsgAlloc, sizeof(DlMsgAlloc));
606          if(dlMsgAlloc == NULLP)
607          {
608             DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for dlMsgAlloc");
609             if(dciSlotAlloc->numSchedInfo == 0)
610             {
611                SCH_FREE(dciSlotAlloc, sizeof(DlMsgAlloc));
612                cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
613             }
614             else
615                memset(&dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo], 0, sizeof(DlMsgSchInfo));
616             return false;
617          }
618          cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1] = dlMsgAlloc;
619          memset(dlMsgAlloc, 0, sizeof(DlMsgAlloc));
620          dlMsgAlloc->crnti = dciSlotAlloc->crnti;
621       }
622       else
623          dlMsgAlloc = cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1];
624
625       /* Copy all DL_MSG info */
626       memcpy(&dlMsgAlloc->dlMsgSchedInfo[dlMsgAlloc->numSchedInfo], \
627             &dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo], sizeof(DlMsgSchInfo));
628       dlMsgAlloc->dlMsgSchedInfo[dlMsgAlloc->numSchedInfo].dlMsgPdcchCfg.dci.pdschCfg = \
629             &dlMsgAlloc->dlMsgSchedInfo[dlMsgAlloc->numSchedInfo].dlMsgPdschCfg;
630
631       /* Assign correct PDU types in corresponding slots */
632       dlMsgAlloc->dlMsgSchedInfo[dlMsgAlloc->numSchedInfo].pduPres = PDSCH_PDU;
633       dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo].pduPres = PDCCH_PDU;
634       dciSlotAlloc->dlMsgSchedInfo[dciSlotAlloc->numSchedInfo].pdschSlot = pdschTime.slot;
635
636       dciSlotAlloc->numSchedInfo++;
637       dlMsgAlloc->numSchedInfo++;
638    }
639
640    schAllocPucchResource(cell, pucchTime, crnti, ueCb, isRetx, *hqP);
641
642    cell->schDlSlotInfo[pdcchTime.slot]->pdcchUe = ueId;
643    cell->schDlSlotInfo[pdschTime.slot]->pdschUe = ueId;
644    cell->schUlSlotInfo[pucchTime.slot]->pucchUe = ueId;
645
646    /* after allocation is done, unset the bo bit for that ue */
647    UNSET_ONE_BIT(ueId, cell->boIndBitMap);
648    return true;
649 }
650
651 /*******************************************************************
652 *
653 * @brief Process DL Resource allocation for Page
654 *
655 * @details
656 *
657 *    Function : schProcDlPageAlloc
658 *
659 *    Functionality: Process DL Resource allocation for Page
660 *
661 * @params[in] SchCellCb *cell, SlotTimingInfo currTime, Inst schInst
662 *
663 * @return pointer to return Value(ROK, RFAILED)
664 *
665 * ****************************************************************/
666 uint8_t schProcDlPageAlloc(SchCellCb *cell, SlotTimingInfo currTime, Inst schInst)
667 {
668    DlPageAlloc      dlPageAlloc;
669    CmLList          *pageInfoNode = NULLP;
670    SchPageInfo      *pageInfo = NULLP;
671    SlotTimingInfo   pdschTime;
672    uint32_t         tbSize = 0;
673    uint16_t         startPrb = 0, maxFreePRB = 0, nPRB = 0;
674    uint8_t          ret = RFAILED;
675
676    pageInfoNode = schPageInfoSearchFromPageList(currTime, &(cell->pageCb.pageIndInfoRecord[currTime.sfn]));
677
678    if(pageInfoNode == NULLP)
679    {
680       return ROK;
681    }
682    pageInfo = (SchPageInfo *)pageInfoNode->node;
683    
684    while(true)
685    {
686       dlPageAlloc.cellId = currTime.cellId;
687
688       ADD_DELTA_TO_TIME(currTime, dlPageAlloc.dlPageTime, PHY_DELTA_DL + SCHED_DELTA, cell->numSlots);
689       dlPageAlloc.shortMsgInd  = FALSE;
690       pdschTime = dlPageAlloc.dlPageTime;
691
692       /*Calculate Best FREE BLOCK with MAX PRB count*/
693       maxFreePRB = searchLargestFreeBlock(cell, pdschTime, &startPrb, DIR_DL);
694
695       if(maxFreePRB != 0)
696       {
697          tbSize = calculateEstimateTBSize(pageInfo->msgLen, pageInfo->mcs, NUM_PDSCH_SYMBOL, maxFreePRB, &nPRB);
698       }
699       else
700       {
701          DU_LOG("\nERROR  --> SCH: Unable to get any free block for Paging at SFN:%d, SLOT:%d",\
702                pdschTime.sfn, pdschTime.slot);
703          break;
704       }
705       /*Fill PDCCH: PDCCH Cfg is same as SIB1 as Paging will be a broadcast message*/
706       memcpy(&dlPageAlloc.pagePdcchCfg, &cell->cellCfg.sib1SchCfg.sib1PdcchCfg, sizeof(PdcchCfg));
707       dlPageAlloc.pagePdcchCfg.dci.rnti = P_RNTI;
708
709       /*Fill BWP*/
710       memcpy(&dlPageAlloc.bwp, &cell->cellCfg.sib1SchCfg.bwp, sizeof(BwpCfg)); 
711
712       /*Fill PDSCH*/
713       if(schFillPagePdschCfg(cell, &dlPageAlloc.pagePdschCfg, pdschTime, tbSize, pageInfo->mcs, startPrb) != ROK)
714       {
715          DU_LOG("\nERROR  --> SCH: Issue in PDSCH Allocation for Paging at SFN:%d, SLOT:%d",\
716                pdschTime.sfn, pdschTime.slot);
717          break;
718       }
719       dlPageAlloc.pagePdcchCfg.dci.pdschCfg = &dlPageAlloc.pagePdschCfg;
720
721       /*Fill Page PDU information*/
722       dlPageAlloc.dlPagePduLen = pageInfo->msgLen;
723
724       SCH_ALLOC(dlPageAlloc.dlPagePdu, sizeof(dlPageAlloc.dlPagePduLen));
725
726       if(dlPageAlloc.dlPagePdu == NULLP)
727       {
728          DU_LOG("\nERROR  --> SCH: Memory Allocation Failed during Page Resource allocation");
729          break;
730       }
731       memcpy(dlPageAlloc.dlPagePdu, pageInfo->pagePdu, dlPageAlloc.dlPagePduLen);
732
733       /* Send msg to MAC */
734       if(sendDlPageAllocToMac(&dlPageAlloc, schInst) != ROK)
735       {
736          DU_LOG("\nERROR  -->  SCH : Sending DL Paging allocation from SCH to MAC failed");
737          SCH_FREE(dlPageAlloc.dlPagePdu, sizeof(dlPageAlloc.dlPagePduLen));
738          break;
739       }
740       ret = ROK;
741       break;
742    }
743
744    /*Remove the Page Node*/
745    SCH_FREE(pageInfo->pagePdu, pageInfo->msgLen);
746    schDeleteFromPageInfoList(&(cell->pageCb.pageIndInfoRecord[currTime.sfn]), pageInfoNode);
747
748    return(ret);
749
750 }
751
752 /*******************************************************************
753  *
754  * @brief Handles slot indication at SCH 
755  *
756  * @details
757  *
758  *    Function : schProcessSlotInd
759  *
760  *    Functionality:
761  *     Handles TTI indication received from PHY
762  *
763  * @params[in] 
764  * @return ROK     - success
765  *         RFAILED - failure
766  *
767  * ****************************************************************/
768 uint8_t schProcessSlotInd(SlotTimingInfo *slotInd, Inst schInst)
769 {
770    uint8_t   ueId, ueIdx, ret = ROK;
771    uint16_t  slot;
772    bool      isRarPending = false, isRarScheduled = false;
773    bool      isMsg4Pending = false, isMsg4Scheduled = false;
774    bool      isUlGrantPending = false, isUlGrantScheduled = false;
775    bool      isDlMsgPending = false, isDlMsgScheduled = false;
776    CmLList        *pendingUeNode;
777    DlSchedInfo    dlSchedInfo;
778    DlBrdcstAlloc  *dlBrdcstAlloc = NULLP;
779    SchCellCb      *cell = NULLP;
780    CmLList        *node;
781    uint8_t*       ueNode;
782    SchDlHqProcCb  *hqP = NULLP;
783    SchUlHqProcCb *ulHqP = NULLP;
784
785    cell = schCb[schInst].cells[schInst];
786    if(cell == NULLP)
787    {
788       DU_LOG("\nERROR  -->  SCH : Cell Does not exist");
789       return RFAILED;
790    }
791    memset(&dlSchedInfo, 0, sizeof(DlSchedInfo));
792    schCalcSlotValues(*slotInd, &dlSchedInfo.schSlotValue, cell->numSlots);
793    dlBrdcstAlloc = &dlSchedInfo.brdcstAlloc;
794    dlBrdcstAlloc->ssbTrans = NO_TRANSMISSION;
795    dlBrdcstAlloc->sib1Trans = NO_TRANSMISSION;
796
797    memcpy(&cell->slotInfo, slotInd, sizeof(SlotTimingInfo));
798    dlBrdcstAlloc->ssbIdxSupported = SSB_IDX_SUPPORTED;
799
800    dlSchedInfo.cellId = cell->cellId;
801    slot = dlSchedInfo.schSlotValue.broadcastTime.slot;
802
803 #ifdef NR_DRX 
804    schHandleStartDrxTimer(cell);
805 #endif
806    
807    /* Check for SSB occassion */
808    dlBrdcstAlloc->ssbTrans = schCheckSsbOcc(cell, dlSchedInfo.schSlotValue.broadcastTime); 
809    if(dlBrdcstAlloc->ssbTrans)
810    {
811       if(schBroadcastSsbAlloc(cell, dlSchedInfo.schSlotValue.broadcastTime, dlBrdcstAlloc) != ROK)
812       {
813          DU_LOG("\nERROR  -->  SCH : schBroadcastSsbAlloc failed");
814          dlBrdcstAlloc->ssbTrans = NO_TRANSMISSION;
815       }
816       else 
817       {
818          dlSchedInfo.isBroadcastPres = true;
819          if((dlBrdcstAlloc->ssbTrans == NEW_TRANSMISSION) && (!cell->firstSsbTransmitted))
820             cell->firstSsbTransmitted = true;
821       }
822    }
823
824    /* Check for SIB1 occassion */
825    dlBrdcstAlloc->sib1Trans = schCheckSib1Occ(cell, dlSchedInfo.schSlotValue.broadcastTime);
826    if(dlBrdcstAlloc->sib1Trans)
827    {
828       if(schBroadcastSib1Alloc(cell, dlSchedInfo.schSlotValue.broadcastTime, dlBrdcstAlloc) != ROK)
829       {
830          DU_LOG("\nERROR  -->  SCH : schBroadcastSib1Alloc failed");
831          dlBrdcstAlloc->sib1Trans = NO_TRANSMISSION;
832       }
833       else 
834       {
835          dlSchedInfo.isBroadcastPres = true;
836          if((dlBrdcstAlloc->sib1Trans == NEW_TRANSMISSION) && (!cell->firstSib1Transmitted))
837             cell->firstSib1Transmitted = true;
838       }
839    }
840
841    /*Process Paging Msg*/
842    schProcDlPageAlloc(cell, *slotInd, schInst);
843
844    /* Select first UE in the linked list to be scheduled next */
845    pendingUeNode = cell->ueToBeScheduled.first;
846    if(pendingUeNode)
847    {
848       if(pendingUeNode->node)
849       {
850          ueNode = (uint8_t *)pendingUeNode->node;
851          ueId = *(uint8_t *)(pendingUeNode->node);
852          /* If RAR is pending for this UE, schedule PDCCH,PDSCH to send RAR and 
853           * PUSCH to receive MSG3 as per k0-k2 configuration*/
854          if(cell->raReq[ueId-1] != NULLP)
855          {
856             isRarPending = true;
857             isRarScheduled = schProcessRaReq(schInst, cell, *slotInd, ueId);
858          }
859
860          /*MSG3 retransmisson*/
861          if(cell->raCb[ueId-1].retxMsg3HqProc)
862          {            
863             schMsg3RetxSchedulingForUe(&(cell->raCb[ueId-1]));
864          }
865
866          /* If MSG4 is pending for this UE, schedule PDCCH,PDSCH to send MSG4 and
867           * PUCCH to receive UL msg as per k0-k1 configuration  */
868          if (cell->ueCb[ueId-1].retxMsg4HqProc) //should work from dlmap later tbd
869          {
870             /* Retransmission of MSG4 */
871             isMsg4Pending = true;
872             if(schProcessMsg4Req(cell, *slotInd, ueId, TRUE, &cell->ueCb[ueId-1].retxMsg4HqProc) == ROK)
873                isMsg4Scheduled = true;
874          }
875          else
876          {
877             /* First transmission of MSG4 */
878             if(cell->raCb[ueId-1].msg4recvd)
879             {
880                isMsg4Pending = true;
881                if(schProcessMsg4Req(cell, *slotInd, ueId, FALSE, &cell->ueCb[ueId-1].msg4Proc) == ROK)
882                   isMsg4Scheduled = true;
883
884                /* If MSG4 scheduling failed, free the newly assigned HARQ process */
885                if(!isMsg4Scheduled)
886                   schDlReleaseHqProcess(cell->ueCb[ueId-1].msg4Proc);
887             }
888          }
889
890          if(isRarPending || isMsg4Pending)
891          {
892             /* If RAR or MSG is successfully scheduled then
893              * remove UE from linked list since no pending msgs for this UE */
894             if(isRarScheduled || isMsg4Scheduled)
895             {
896                SCH_FREE(pendingUeNode->node, sizeof(uint8_t));
897                deleteNodeFromLList(&cell->ueToBeScheduled, pendingUeNode);
898             }
899             /* If RAR/MSG4 is pending but couldnt be scheduled then,
900              * put this UE at the end of linked list to be scheduled later */
901             else
902             {
903                cmLListAdd2Tail(&cell->ueToBeScheduled, cmLListDelFrm(&cell->ueToBeScheduled, pendingUeNode));
904             }
905          }
906
907 #ifdef NR_DRX 
908          if((cell->ueCb[ueId-1].ueDrxInfoPres == true) && (cell->ueCb[ueId-1].drxUeCb.drxDlUeActiveStatus != true))
909          {
910             if(pendingUeNode->node)
911             {
912                cmLListAdd2Tail(&cell->ueToBeScheduled, cmLListDelFrm(&cell->ueToBeScheduled, pendingUeNode));
913             }
914          }
915          else 
916 #endif
917          {
918             
919             /* DL Data */
920             node = cell->ueCb[ueId-1].dlRetxHqList.first;
921             if(node != NULLP)
922             {
923                /* DL Data ReTransmisson */
924                isDlMsgPending = true;
925                isDlMsgScheduled = schFillBoGrantDlSchedInfo(cell, *slotInd, ueId, TRUE, ((SchDlHqProcCb**) &(node->node)));
926 #ifdef NR_DRX 
927                if(isDlMsgScheduled)
928                {
929                   schDrxStopDlHqRetxTmr(cell, &cell->ueCb[ueId-1], ((SchDlHqProcCb**) &(node->node)));
930                }
931 #endif
932                cmLListDelFrm(&cell->ueCb[ueId-1].dlRetxHqList, node);
933             }
934             else
935             {
936                /* DL Data new transmission */
937                if((cell->boIndBitMap) & (1<<ueId))
938                {
939                   isDlMsgPending = true;               
940                   isDlMsgScheduled = schFillBoGrantDlSchedInfo(cell, *slotInd, ueId, FALSE, &hqP);
941
942                   /* If DL scheduling failed, free the newly assigned HARQ process */
943                   if(!isDlMsgScheduled)
944                      schDlReleaseHqProcess(hqP);
945                   else
946                   {
947 #ifdef NR_DRX
948                      schHdlDrxInActvStrtTmr(cell, &cell->ueCb[ueId-1], PHY_DELTA_DL + SCHED_DELTA);
949 #endif
950                   }
951                }
952             }
953
954             /* Scheduling of UL grant */
955             node = cell->ueCb[ueId-1].ulRetxHqList.first;
956             if(node != NULLP)
957             {
958                /* UL Data ReTransmisson */
959                isUlGrantPending = true;
960                isUlGrantScheduled = schProcessSrOrBsrReq(cell, *slotInd, ueId, TRUE, (SchUlHqProcCb**) &(node->node));
961 #ifdef NR_DRX 
962                if(isUlGrantScheduled)
963                {
964                   schDrxStopUlHqRetxTmr(cell, &cell->ueCb[ueId-1], ((SchUlHqProcCb**) &(node->node)));
965                }
966 #endif
967                cmLListDelFrm(&cell->ueCb[ueId-1].ulRetxHqList, node);
968             }
969             else
970             {
971                /* UL Data new transmission */
972                if(cell->ueCb[ueId-1].srRcvd || cell->ueCb[ueId-1].bsrRcvd)
973                {
974                   isUlGrantPending = true;
975                   isUlGrantScheduled = schProcessSrOrBsrReq(cell, *slotInd, ueId, FALSE, &ulHqP);
976                   if(!isUlGrantScheduled)
977                      schUlReleaseHqProcess(ulHqP, FALSE);
978                   else
979                   {
980 #ifdef NR_DRX
981                      schHdlDrxInActvStrtTmr(cell, &cell->ueCb[ueId-1], PHY_DELTA_UL + SCHED_DELTA);
982 #endif
983                   }
984                }
985             }
986
987             if(!isUlGrantPending && !isDlMsgPending)
988             {
989                /* No action required */  
990             }
991             else if((isUlGrantPending && !isUlGrantScheduled) || (isDlMsgPending && !isDlMsgScheduled))
992             {
993                cmLListAdd2Tail(&cell->ueToBeScheduled, cmLListDelFrm(&cell->ueToBeScheduled, pendingUeNode));
994             }
995             else
996             {
997                SCH_FREE(ueNode, sizeof(uint8_t));
998                deleteNodeFromLList(&cell->ueToBeScheduled, pendingUeNode);
999             }
1000          }
1001       }
1002    }
1003
1004    /* Check if any PDU is scheduled at this slot for any UE */
1005    for(ueIdx=0; ueIdx<MAX_NUM_UE; ueIdx++)
1006    {
1007       /* If RAR PDCCH/PDSCH is scheduled for a UE at this slot, fill RAR specific interface 
1008        * structure to send to MAC */
1009       if(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.rarTime.slot]->rarAlloc[ueIdx] != NULLP)
1010       {
1011          slot = dlSchedInfo.schSlotValue.rarTime.slot;
1012          dlSchedInfo.rarAlloc[ueIdx] = cell->schDlSlotInfo[slot]->rarAlloc[ueIdx];
1013          cell->schDlSlotInfo[slot]->rarAlloc[ueIdx] = NULLP;
1014       }
1015
1016       /* If DL-Msg PDCCH/PDSCH is scheduled for a UE at this slot, fill 
1017        * specific interface structure to send to MAC */
1018       if(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.dlMsgTime.slot]->dlMsgAlloc[ueIdx] != NULLP)
1019       {
1020          slot = dlSchedInfo.schSlotValue.dlMsgTime.slot;
1021          dlSchedInfo.dlMsgAlloc[ueIdx] = cell->schDlSlotInfo[slot]->dlMsgAlloc[ueIdx];
1022          cell->schDlSlotInfo[slot]->dlMsgAlloc[ueIdx] = NULLP;
1023       }
1024    }
1025
1026    if(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.ulDciTime.slot]->ulGrant != NULLP)
1027    {
1028       slot = dlSchedInfo.schSlotValue.ulDciTime.slot;
1029       dlSchedInfo.ulGrant = cell->schDlSlotInfo[slot]->ulGrant;
1030       cell->schDlSlotInfo[slot]->ulGrant = NULLP;
1031    }
1032
1033    /* Send msg to MAC */
1034    ret = sendDlAllocToMac(&dlSchedInfo, schInst);
1035    if(ret != ROK)
1036    {
1037       DU_LOG("\nERROR  -->  SCH : Sending DL Broadcast allocation from SCH to MAC failed");
1038       return (ret);
1039    }
1040
1041    schInitDlSlot(cell->schDlSlotInfo[slot]);
1042    schUlResAlloc(cell, schInst);
1043 #ifdef NR_DRX 
1044    schHandleExpiryDrxTimer(cell);
1045 #endif   
1046    return ret;
1047 }
1048
1049 /**********************************************************************
1050   End of file
1051  **********************************************************************/
1052
1053