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