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