[Epic-ID: ODUHIGH-517][Task-ID: ODUHIGH-540][SubTask-Id: ODUHIGH-549] Multi PDSCH...
[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_tmr.h"
44 #include "sch_utils.h"
45 #ifdef NR_DRX 
46 #include "sch_drx.h"
47 #endif
48
49 /*******************************************************************
50  *
51  * @brief Handles sending DL broadcast alloc to MAC 
52  *
53  * @details
54  *
55  *    Function : sendDlAllocToMac
56  *
57  *    Functionality:
58  *     Sends DL Broadcast Resource Allocation to MAC from SCH
59  *
60  * @params[in] 
61  * @return ROK     - success
62  *         RFAILED - failure
63  *
64  * ****************************************************************/
65 uint8_t sendDlAllocToMac(DlSchedInfo *dlSchedInfo, Inst inst)
66 {
67    Pst pst;
68
69    memset(&pst, 0, sizeof(Pst));
70    FILL_PST_SCH_TO_MAC(pst, inst);
71    pst.event = EVENT_DL_SCH_INFO;
72
73    return(MacMessageRouter(&pst, (void *)dlSchedInfo));
74 }
75
76 /*******************************************************************
77  *
78  * @brief 
79  *
80  * @details
81  *
82  *    Function : schFillBoGrantDlSchedInfo 
83  *
84  *    Functionality:
85  
86  *
87  * @params[in] SchCellCb *cell, SlotTimingInfo currTime, uint8_t ueId
88  * @params[in] bool isRetx, SchDlHqProcCb **hqP
89  * @return ROK     - success
90  *         RFAILED - failure
91  *
92  * ****************************************************************/
93 bool schFillBoGrantDlSchedInfo(SchCellCb *cell, SlotTimingInfo currTime, uint8_t ueId, bool isRetx, SchDlHqProcCb **hqP)
94 {
95    uint8_t pdschNumSymbols = 0, pdschStartSymbol = 0;
96    uint8_t lcIdx = 0;
97    uint16_t startPrb = 0;
98    uint16_t crnti = 0;
99    uint32_t accumalatedSize = 0;
100    SchUeCb *ueCb = NULLP;
101    DlMsgSchInfo *dciSlotAlloc, *dlMsgAlloc;
102    SlotTimingInfo pdcchTime, pdschTime, pucchTime;
103
104    GET_CRNTI(crnti,ueId);
105    ueCb = &cell->ueCb[ueId-1];
106
107    if (isRetx == FALSE)
108    {
109       if(schDlGetAvlHqProcess(cell, ueCb, hqP) != ROK)
110       {
111          return false;
112       }
113    }
114
115    if(findValidK0K1Value(cell, currTime, ueId, ueCb->k0K1TblPrsnt,\
116             &pdschStartSymbol, &pdschNumSymbols, &pdcchTime, &pdschTime, &pucchTime, isRetx, *hqP) != true )
117    {
118       /* If a valid combination of slots to scheduled PDCCH, PDSCH and PUCCH is
119        * not found, do not perform resource allocation. Return from here. */
120       return false;
121    }
122    
123    /* allocate PDCCH and PDSCH resources for the ue */
124    if(cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] == NULL)
125    {
126
127       SCH_ALLOC(dciSlotAlloc, sizeof(DlMsgSchInfo));
128       if(!dciSlotAlloc)
129       {
130          DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for ded DL msg alloc");
131          return false;
132       }
133       cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId -1] = dciSlotAlloc;
134       memset(dciSlotAlloc, 0, sizeof(DlMsgSchInfo));
135    }
136    else
137    {
138       dciSlotAlloc = cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId -1];
139    }
140    /* Dl ded Msg info is copied, this was earlier filled in macSchDlRlcBoInfo */
141    fillDlMsgInfo(dciSlotAlloc, crnti, isRetx, *hqP);
142    dciSlotAlloc->transportBlock[0].ndi = isRetx;
143
144    accumalatedSize = cell->api->SchScheduleDlLc(pdcchTime, pdschTime, pdschNumSymbols, &startPrb, isRetx, hqP);
145
146    /*Below case will hit if NO LC(s) are allocated due to resource crunch*/
147    if (!accumalatedSize)
148       return false;
149
150    /*[Step6]: pdcch and pdsch data is filled */
151    if((schDlRsrcAllocDlMsg(cell, pdschTime, crnti, accumalatedSize, dciSlotAlloc, startPrb, pdschStartSymbol, pdschNumSymbols, isRetx, *hqP)) != ROK)
152    {
153       DU_LOG("\nERROR  --> SCH : Scheduling of DL dedicated message failed");
154
155       /* Free the dl ded msg info allocated in macSchDlRlcBoInfo */
156       if(!dciSlotAlloc->dlMsgPdschCfg)
157       {
158          SCH_FREE(dciSlotAlloc, sizeof(DlMsgSchInfo));
159          cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId -1] = NULL;
160       }
161       return false;
162    }
163
164    /* TODO : Update the scheduling byte report for multiple LC based on QCI
165     * and Priority */
166    /* As of now, the total number of bytes scheduled for a slot is divided
167     * equally amongst all LC with pending data. This is avoid starving of any
168     * LC 
169     * */
170 #if 0
171    accumalatedSize = accumalatedSize/dlMsgAlloc->numLc;
172    for(lcIdx = 0; lcIdx < dlMsgAlloc->numLc; lcIdx ++)
173       dlMsgAlloc->lcSchInfo[lcIdx].schBytes = accumalatedSize;
174 #endif
175    
176    /* Check if both DCI and DL_MSG are sent in the same slot.
177     * If not, allocate memory for DL_MSG PDSCH slot to store PDSCH info */
178
179    if(pdcchTime.slot == pdschTime.slot)
180    {
181       SCH_ALLOC(dciSlotAlloc->dlMsgPdschCfg, sizeof(PdschCfg));
182       if(!dciSlotAlloc->dlMsgPdschCfg)
183       {
184          DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for dciSlotAlloc->dlMsgPdschCfg");
185          SCH_FREE(dciSlotAlloc->dlMsgPdcchCfg, sizeof(PdcchCfg));
186          SCH_FREE(dciSlotAlloc, sizeof(DlMsgSchInfo));
187          cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
188          return false;
189       }
190       memcpy(dciSlotAlloc->dlMsgPdschCfg, &dciSlotAlloc->dlMsgPdcchCfg->dci.pdschCfg,  sizeof(PdschCfg));
191    }
192    else
193    {
194       /* Allocate memory to schedule dlMsgAlloc to send DL_Msg, pointer will be checked at schProcessSlotInd() */
195       if(cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1] == NULLP)
196       {
197          SCH_ALLOC(dlMsgAlloc, sizeof(DlMsgSchInfo));
198          if(dlMsgAlloc == NULLP)
199          {
200             DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for dlMsgAlloc");
201             SCH_FREE(dciSlotAlloc->dlMsgPdcchCfg, sizeof(PdcchCfg));
202             if(dciSlotAlloc->dlMsgPdschCfg == NULLP)
203             {
204                SCH_FREE(dciSlotAlloc, sizeof(DlMsgSchInfo));
205                cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
206             }
207             return false;
208          }
209          cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1] = dlMsgAlloc;
210          memset(dlMsgAlloc, 0, sizeof(DlMsgSchInfo));
211       }
212       else
213          dlMsgAlloc = cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1];
214
215       /* Copy all DL_MSG info */
216       dlMsgAlloc->crnti =crnti;
217       dlMsgAlloc->bwp = dciSlotAlloc->bwp;
218       SCH_ALLOC(dlMsgAlloc->dlMsgPdschCfg, sizeof(PdschCfg));
219       if(dlMsgAlloc->dlMsgPdschCfg)
220       {
221          memcpy(dlMsgAlloc->dlMsgPdschCfg, &dciSlotAlloc->dlMsgPdcchCfg->dci.pdschCfg, sizeof(PdschCfg));
222       }
223       else
224       {
225          SCH_FREE(dciSlotAlloc->dlMsgPdcchCfg, sizeof(PdcchCfg));    
226          if(dciSlotAlloc->dlMsgPdschCfg == NULLP)
227          {
228             SCH_FREE(dciSlotAlloc, sizeof(DlMsgSchInfo));
229             cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
230
231          }
232          SCH_FREE(dlMsgAlloc, sizeof(DlMsgSchInfo));
233          cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
234          DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for dlMsgAlloc->dlMsgPdschCfg");
235          return false;
236       }
237    }
238
239    schAllocPucchResource(cell, pucchTime, crnti, ueCb, isRetx, *hqP);
240
241    cell->schUlSlotInfo[pucchTime.slot]->pucchUe = ueId;
242
243    /*Re-setting the BO's of all DL LCs in this UE*/
244    for(lcIdx = 0; lcIdx < MAX_NUM_LC; lcIdx++)
245    {
246       ueCb->dlInfo.dlLcCtxt[lcIdx].bo = 0;
247    }
248
249    /* after allocation is done, unset the bo bit for that ue */
250    UNSET_ONE_BIT(ueId, cell->boIndBitMap);
251    return true;
252 }
253
254 /*******************************************************************
255  *
256  * @brief Handles sending DL Page alloc to MAC 
257  *
258  * @details
259  *
260  *    Function : sendDlPAgeAllocToMac
261  *
262  *    Functionality:
263  *     Sends DL Page Resource Allocation to MAC from SCH
264  *
265  * @params[in] 
266  * @return ROK     - success
267  *         RFAILED - failure
268  *
269  * ****************************************************************/
270 uint8_t sendDlPageAllocToMac(DlPageAlloc *dlPageAlloc, Inst inst)
271 {
272    Pst pst;
273
274    memset(&pst, 0, sizeof(Pst));
275    FILL_PST_SCH_TO_MAC(pst, inst);
276    pst.event = EVENT_DL_PAGING_ALLOC;
277
278    return(MacMessageRouter(&pst, (void *)dlPageAlloc));
279 }
280
281 /*******************************************************************
282  *
283  * @brief Handles slot indication at SCH 
284  *
285  * @details
286  *
287  *    Function : schCalcSlotValues
288  *
289  *    Functionality:
290  *     Handles TTI indication received from PHY
291  *
292  * @params[in] 
293  * @return ROK     - success
294  *         RFAILED - failure
295  *
296  * ****************************************************************/
297 void schCalcSlotValues(SlotTimingInfo slotInd, SchSlotValue *schSlotValue, uint16_t numOfSlots)
298 {
299    /****************************************************************
300     * PHY_DELTA - the physical layer delta                         * 
301     * SCHED_DELTA - scheduler schedules one slot ahead             *
302     * BO_DELTA - this delay is considered for BO response and      *
303     *            RLC buffer packet to received at MAC              *
304     * lower-mac (FAPI filling) will be working on PHY_DELTA        *
305     * brdcast scheduler will working on PHY_DELTA + SCHED_DELTA    *
306     * RAR scheduler will working on PHY_DELTA + SCHED_DELTA        *
307     * msg4 scheduler will working on PHY_DELTA + SCHED_DELTA       *
308     * dedicated DL msg scheduler will working                      *
309     *        on PHY_DELTA + SCHED_DELTA + BO_DELTA                 *
310     ****************************************************************/
311
312    ADD_DELTA_TO_TIME(slotInd, schSlotValue->currentTime, PHY_DELTA_DL, numOfSlots);
313    ADD_DELTA_TO_TIME(slotInd, schSlotValue->broadcastTime, PHY_DELTA_DL + SCHED_DELTA, numOfSlots);
314    ADD_DELTA_TO_TIME(slotInd, schSlotValue->rarTime, PHY_DELTA_DL + SCHED_DELTA, numOfSlots);
315    ADD_DELTA_TO_TIME(slotInd, schSlotValue->dlMsgTime, PHY_DELTA_DL + SCHED_DELTA, numOfSlots);
316    ADD_DELTA_TO_TIME(slotInd, schSlotValue->ulDciTime, PHY_DELTA_DL + SCHED_DELTA, numOfSlots);
317 }
318
319 /*******************************************************************
320  *
321  * @brief Checks if a slot is to be scheduled for SSB transmission
322  *
323  * @details
324  *
325  *    Function : schCheckSsbOcc 
326  *
327  *    Functionality:
328  *       Checks if a slot is to be scheduled for SSB transmission
329  *
330  * @params[in] SlotTimingInfo slotTime
331  *             SchCellCb *cell 
332  * @return  Pdu transmission 
333  *
334  * ****************************************************************/
335 PduTxOccsaion schCheckSsbOcc(SchCellCb *cell, SlotTimingInfo slotTime)
336 {
337    uint8_t  ssb_rep;
338
339    ssb_rep = cell->cellCfg.ssbPeriod;
340
341    /* Identify SSB ocassion*/
342    if ((slotTime.sfn % SCH_MIB_TRANS == 0) && (slotTime.slot ==0))
343    {
344       return NEW_TRANSMISSION;
345    }
346    else if(cell->firstSsbTransmitted) 
347    {
348       if((ssb_rep == 5) && ((slotTime.slot == 0 || slotTime.slot == 10)))
349          return REPEATITION;
350       else if((slotTime.sfn % (ssb_rep/10) == 0) && slotTime.slot == 0)
351          return REPEATITION;
352    }
353    /* not SSB occassion */
354    return NO_TRANSMISSION;
355 }
356
357 /*******************************************************************
358  *
359  * @brief Checks if a slot is to be scheduled for SIB1 transmission
360  *
361  * @details
362  *
363  *    Function : schCheckSib1Occ
364  *
365  *    Functionality:
366  *       Checks if a slot is to be scheduled for SIB1 transmission
367  *
368  * @params[in] SlotTimingInfo slotTime
369  *             SchCellCb *cell
370  * @return  Pdu transmission
371  *
372  * ****************************************************************/
373 PduTxOccsaion schCheckSib1Occ(SchCellCb *cell, SlotTimingInfo slotTime)
374 {
375    /* Identify SIB1 occasions */
376    if((slotTime.sfn % SCH_SIB1_TRANS == 0) && (slotTime.slot ==0))
377    {
378       return NEW_TRANSMISSION;
379    }
380    else if(cell->firstSib1Transmitted) 
381    {
382       if((slotTime.sfn % (SIB1_REPETITION_PERIOD/10) == 0) &&
383             (slotTime.slot == 0))
384       {
385          return REPEATITION;
386       }
387    }
388    /* not SIB1 occassion */
389    return NO_TRANSMISSION;
390 }
391
392 /*******************************************************************
393  *
394  * @brief find correct combination of k0-k1 value
395  *
396  * @details
397  *
398  *    Function : findValidK0K1Value
399  *
400  *    Functionality:
401  *       find correct combination of k0-k1 value
402  *
403  * @params[in] SchCellCb *cell, SlotTimingInfo currTime
404  * @params[in] uint8_t ueId, bool dedMsg
405  * @params[in] uint8_t *pdschStartSymbol, uint8_t *pdschSymblLen
406  * @params[in] SlotTimingInfo *pdcchTime, SlotTimingInfo *pdschTime
407  * @params[in] SlotTimingInfo *pucchTime, bool isRetx, SchDlHqProcCb *hqP
408  * @return ROK     - success
409  *         RFAILED - failure
410  *
411  *******************************************************************/
412 bool findValidK0K1Value(SchCellCb *cell, SlotTimingInfo currTime, uint8_t ueId, bool dedMsg,
413                         uint8_t *pdschStartSymbol, uint8_t *pdschSymblLen, SlotTimingInfo *pdcchTime,
414                         SlotTimingInfo *pdschTime, SlotTimingInfo *pucchTime, bool isRetx, SchDlHqProcCb *hqP)
415 {
416    uint8_t numK0 = 0, k0TblIdx = 0, k0Val = 0, k0Index =0 ;
417    uint8_t k1TblIdx = 0, k1Index = 0, k1Val = 0, numK1 = 0;
418    SchUeCb *ueCb = NULLP;
419    SchK0K1TimingInfoTbl *k0K1InfoTbl;
420
421    ADD_DELTA_TO_TIME(currTime, (*pdcchTime), PHY_DELTA_DL + SCHED_DELTA, cell->numSlots);
422 #ifdef NR_TDD
423    if(schGetSlotSymbFrmt(pdcchTime->slot, cell->slotFrmtBitMap) != DL_SLOT)
424    {
425       /* If it is not a DL slot, cannot schedule PDCCH. Return from here. */
426       return false;
427    }
428 #endif
429
430    if(dedMsg == true)
431    {
432       ueCb = &cell->ueCb[ueId-1];
433       k0K1InfoTbl = &ueCb->k0K1InfoTbl;
434       if(schDlCandidateSelection(ueCb, *pdcchTime) == false)
435       {
436         DU_LOG("\nDEBUG  --> SCH: DL candidate Selection failed bcz PDCCH is unavailable for this slot");
437         return false;     
438       }
439    }
440    else
441    {
442       k0K1InfoTbl = &cell->k0K1InfoTbl;
443    }
444
445    numK0 = k0K1InfoTbl->k0k1TimingInfo[pdcchTime->slot].numK0;
446    for(k0TblIdx = 0; k0TblIdx < numK0; k0TblIdx++)
447    {
448       k0Index = k0K1InfoTbl->k0k1TimingInfo[pdcchTime->slot].k0Indexes[k0TblIdx].k0Index;
449       if(dedMsg != true)
450       {
451          k0Val = cell->cellCfg.dlCfgCommon.schInitialDlBwp.pdschCommon.timeDomRsrcAllocList[k0Index].k0;
452          *pdschStartSymbol = cell->cellCfg.dlCfgCommon.schInitialDlBwp.pdschCommon.timeDomRsrcAllocList[k0Index].startSymbol;
453          *pdschSymblLen = cell->cellCfg.dlCfgCommon.schInitialDlBwp.pdschCommon.timeDomRsrcAllocList[k0Index].lengthSymbol;
454       }
455       else
456       {
457          if(ueCb->ueCfg.spCellCfg.servCellRecfg.initDlBwp.pdschCfg.timeDomRsrcAllociList[k0Index].k0 != NULLP)
458          {
459             k0Val = *(ueCb->ueCfg.spCellCfg.servCellRecfg.initDlBwp.pdschCfg.timeDomRsrcAllociList[k0Index].k0);
460             *pdschStartSymbol = ueCb->ueCfg.spCellCfg.servCellRecfg.initDlBwp.pdschCfg.timeDomRsrcAllociList[k0Index].startSymbol;
461             *pdschSymblLen = ueCb->ueCfg.spCellCfg.servCellRecfg.initDlBwp.pdschCfg.timeDomRsrcAllociList[k0Index].symbolLength;
462          }
463          else
464          {
465             k0Val = cell->cellCfg.dlCfgCommon.schInitialDlBwp.pdschCommon.timeDomRsrcAllocList[k0Index].k0;
466             *pdschStartSymbol = cell->cellCfg.dlCfgCommon.schInitialDlBwp.pdschCommon.timeDomRsrcAllocList[k0Index].startSymbol;
467             *pdschSymblLen = cell->cellCfg.dlCfgCommon.schInitialDlBwp.pdschCommon.timeDomRsrcAllocList[k0Index].lengthSymbol;
468          }
469       }
470
471       ADD_DELTA_TO_TIME((*pdcchTime), (*pdschTime), k0Val, cell->numSlots);
472 #ifdef NR_TDD
473       if(schGetSlotSymbFrmt(pdschTime->slot, cell->slotFrmtBitMap) != DL_SLOT)
474       {
475          continue;
476       }
477 #endif
478
479       numK1 = k0K1InfoTbl->k0k1TimingInfo[pdcchTime->slot].k0Indexes[k0TblIdx].k1TimingInfo.numK1;
480       for(k1TblIdx = 0; k1TblIdx < numK1; k1TblIdx++)
481       {
482          k1Index = k0K1InfoTbl->k0k1TimingInfo[pdcchTime->slot].k0Indexes[k0TblIdx].k1TimingInfo.k1Indexes[k1TblIdx];
483          if(dedMsg != true)
484          {
485             k1Val = defaultUlAckTbl[k1Index];
486          }
487          else
488          {
489             if(ueCb->ueCfg.spCellCfg.servCellRecfg.initUlBwp.pucchCfg.dlDataToUlAck)
490             {
491                k1Val = ueCb->ueCfg.spCellCfg.servCellRecfg.initUlBwp.pucchCfg.dlDataToUlAck->dlDataToUlAckList[k1Index];
492             }
493             else
494             {
495                k1Val = defaultUlAckTbl[k1Index];
496             }
497          }
498          ADD_DELTA_TO_TIME((*pdschTime),(*pucchTime), k1Val, cell->numSlots);
499 #ifdef NR_TDD
500          if(schGetSlotSymbFrmt(pucchTime->slot, cell->slotFrmtBitMap) == DL_SLOT)
501          {
502             continue;
503          }
504 #endif
505          if(cell->schUlSlotInfo[pucchTime->slot]->pucchUe != 0)
506          {
507             continue; 
508          }
509          if(hqP)
510          {
511             ADD_DELTA_TO_TIME((*pucchTime), hqP->pucchTime, 0, cell->numSlots);
512          }
513          pdcchTime->cellId = cell->cellId;
514          pdschTime->cellId = cell->cellId;
515
516          return true;
517       }
518    }
519    /*
520     * Number of symbols in case of retransmisson should be same as it was in
521     * original transmisson. Symbol availablity checks need to be added.
522     */
523    return false;
524 }
525
526 /*******************************************************************
527 *
528 * @brief Process DL Resource allocation for Page
529 *
530 * @details
531 *
532 *    Function : schProcDlPageAlloc
533 *
534 *    Functionality: Process DL Resource allocation for Page
535 *
536 * @params[in] SchCellCb *cell, SlotTimingInfo currTime, Inst schInst
537 *
538 * @return pointer to return Value(ROK, RFAILED)
539 *
540 * ****************************************************************/
541 uint8_t schProcDlPageAlloc(SchCellCb *cell, SlotTimingInfo currTime, Inst schInst)
542 {
543    DlPageAlloc      dlPageAlloc;
544    CmLList          *pageInfoNode = NULLP;
545    SchPageInfo      *pageInfo = NULLP;
546    SlotTimingInfo   pdschTime;
547    uint32_t         tbSize = 0;
548    uint16_t         startPrb = 0, maxFreePRB = 0, nPRB = 0;
549    uint8_t          ret = RFAILED;
550
551    pageInfoNode = schPageInfoSearchFromPageList(currTime, &(cell->pageCb.pageIndInfoRecord[currTime.sfn]));
552
553    if(pageInfoNode == NULLP)
554    {
555       return ROK;
556    }
557    pageInfo = (SchPageInfo *)pageInfoNode->node;
558    
559    while(true)
560    {
561       dlPageAlloc.cellId = currTime.cellId;
562
563       ADD_DELTA_TO_TIME(currTime, dlPageAlloc.dlPageTime, PHY_DELTA_DL + SCHED_DELTA, cell->numSlots);
564       dlPageAlloc.shortMsgInd  = FALSE;
565       pdschTime = dlPageAlloc.dlPageTime;
566
567       /*Calculate Best FREE BLOCK with MAX PRB count*/
568       maxFreePRB = searchLargestFreeBlock(cell, pdschTime, &startPrb, DIR_DL);
569
570       if(maxFreePRB != 0)
571       {
572          tbSize = calculateEstimateTBSize(pageInfo->msgLen, pageInfo->mcs, NUM_PDSCH_SYMBOL, maxFreePRB, &nPRB);
573       }
574       else
575       {
576          DU_LOG("\nERROR  --> SCH: Unable to get any free block for Paging at SFN:%d, SLOT:%d",\
577                pdschTime.sfn, pdschTime.slot);
578          break;
579       }
580       /*Fill PDCCH: PDCCH Cfg is same as SIB1 as Paging will be a broadcast message*/
581       memcpy(dlPageAlloc.pageDlDci.freqDomainResource, cell->sib1SchCfg.sib1PdcchCfg.coresetCfg.freqDomainResource, 6 * sizeof(uint8_t));
582       dlPageAlloc.pageDlDci.durationSymbols = cell->sib1SchCfg.sib1PdcchCfg.coresetCfg.durationSymbols;
583       dlPageAlloc.pageDlDci.cceRegMappingType = INTERLEAVED_CCE_REG_MAPPING;
584       dlPageAlloc.pageDlDci.cceReg.interleaved.regBundleSize = cell->sib1SchCfg.sib1PdcchCfg.coresetCfg.regBundleSize;
585       dlPageAlloc.pageDlDci.cceReg.interleaved.interleaverSize = cell->sib1SchCfg.sib1PdcchCfg.coresetCfg.interleaverSize;
586       dlPageAlloc.pageDlDci.cceReg.interleaved.shiftIndex = cell->sib1SchCfg.sib1PdcchCfg.coresetCfg.shiftIndex;
587       dlPageAlloc.pageDlDci.ssStartSymbolIndex = cell->sib1SchCfg.sib1PdcchCfg.coresetCfg.startSymbolIndex;
588       dlPageAlloc.pageDlDci.cceIndex = cell->sib1SchCfg.sib1PdcchCfg.dci.cceIndex;
589       dlPageAlloc.pageDlDci.aggregLevel = cell->sib1SchCfg.sib1PdcchCfg.dci.aggregLevel;
590       dlPageAlloc.pageDlDci.precoderGranularity = cell->sib1SchCfg.sib1PdcchCfg.coresetCfg.precoderGranularity;
591       dlPageAlloc.pageDlDci.coreSetSize = cell->sib1SchCfg.sib1PdcchCfg.coresetCfg.coreSetSize;
592       /*Fill BWP*/
593       memcpy(&dlPageAlloc.bwp, &cell->sib1SchCfg.bwp, sizeof(BwpCfg)); 
594
595       /*Fill PDSCH*/
596       if(schFillPagePdschCfg(cell, &dlPageAlloc.pageDlSch, pdschTime, tbSize, pageInfo->mcs, startPrb) != ROK)
597       {
598          DU_LOG("\nERROR  --> SCH: Issue in PDSCH Allocation for Paging at SFN:%d, SLOT:%d",\
599                pdschTime.sfn, pdschTime.slot);
600          break;
601       }
602
603       /*Fill Page PDU information*/
604       dlPageAlloc.pageDlSch.dlPagePduLen = pageInfo->msgLen;
605
606       SCH_ALLOC(dlPageAlloc.pageDlSch.dlPagePdu, sizeof(dlPageAlloc.pageDlSch.dlPagePduLen));
607
608       if(dlPageAlloc.pageDlSch.dlPagePdu == NULLP)
609       {
610          DU_LOG("\nERROR  --> SCH: Memory Allocation Failed during Page Resource allocation");
611          break;
612       }
613       memcpy(dlPageAlloc.pageDlSch.dlPagePdu, pageInfo->pagePdu, dlPageAlloc.pageDlSch.dlPagePduLen);
614
615       /* Send msg to MAC */
616       if(sendDlPageAllocToMac(&dlPageAlloc, schInst) != ROK)
617       {
618          DU_LOG("\nERROR  -->  SCH : Sending DL Paging allocation from SCH to MAC failed");
619          SCH_FREE(dlPageAlloc.pageDlSch.dlPagePdu, sizeof(dlPageAlloc.pageDlSch.dlPagePduLen));
620          break;
621       }
622       ret = ROK;
623       break;
624    }
625
626    /*Remove the Page Node*/
627    SCH_FREE(pageInfo->pagePdu, pageInfo->msgLen);
628    schDeleteFromPageInfoList(&(cell->pageCb.pageIndInfoRecord[currTime.sfn]), pageInfoNode);
629
630    return(ret);
631
632 }
633
634 /*******************************************************************
635  *
636  * @brief Handles slot indication at SCH 
637  *
638  * @details
639  *
640  *    Function : SchProcSlotInd
641  *
642  *    Functionality:
643  *     Handles TTI indication received from PHY
644  *
645  * @params[in] 
646  * @return ROK     - success
647  *         RFAILED - failure
648  *
649  * ****************************************************************/
650 uint8_t SchProcSlotInd(Pst *pst, SlotTimingInfo *slotInd)
651 {
652    uint8_t        ueIdx, ret = ROK;
653    uint16_t       slot;
654    DlSchedInfo    dlSchedInfo;
655    DlBrdcstAlloc  *dlBrdcstAlloc = NULLP;
656    SchCellCb      *cell = NULLP;
657    Inst           schInst = pst->dstInst-SCH_INST_START;
658    CmLList        *node = NULLP;
659    TotalPrbUsage  *dlTotalPrbUsage = NULLP;
660
661    cell = schCb[schInst].cells[schInst];
662    if(cell == NULLP)
663    {
664       DU_LOG("\nERROR  -->  SCH : Cell Does not exist");
665       return RFAILED;
666    }
667    memset(&dlSchedInfo, 0, sizeof(DlSchedInfo));
668    schCalcSlotValues(*slotInd, &dlSchedInfo.schSlotValue, cell->numSlots);
669    dlBrdcstAlloc = &dlSchedInfo.brdcstAlloc;
670    dlBrdcstAlloc->ssbTransmissionMode = NO_TRANSMISSION;
671    dlBrdcstAlloc->sib1TransmissionMode = NO_TRANSMISSION;
672
673    memcpy(&cell->slotInfo, slotInd, sizeof(SlotTimingInfo));
674    dlBrdcstAlloc->ssbIdxSupported = SSB_IDX_SUPPORTED;
675
676    dlSchedInfo.cellId = cell->cellId;
677    slot = dlSchedInfo.schSlotValue.broadcastTime.slot;
678
679 #ifdef NR_DRX 
680    schHandleStartDrxTimer(cell);
681 #endif
682    
683    /* Check for SSB occassion */
684    dlBrdcstAlloc->ssbTransmissionMode = schCheckSsbOcc(cell, dlSchedInfo.schSlotValue.broadcastTime); 
685    if(dlBrdcstAlloc->ssbTransmissionMode)
686    {
687       if(schBroadcastSsbAlloc(cell, dlSchedInfo.schSlotValue.broadcastTime, dlBrdcstAlloc) != ROK)
688       {
689          DU_LOG("\nERROR  -->  SCH : schBroadcastSsbAlloc failed");
690          dlBrdcstAlloc->ssbTransmissionMode = NO_TRANSMISSION;
691       }
692       else 
693       {
694          dlSchedInfo.isBroadcastPres = true;
695          if((dlBrdcstAlloc->ssbTransmissionMode == NEW_TRANSMISSION) && (!cell->firstSsbTransmitted))
696             cell->firstSsbTransmitted = true;
697       }
698    }
699
700    /* Check for SIB1 occassion */
701    dlBrdcstAlloc->sib1TransmissionMode = schCheckSib1Occ(cell, dlSchedInfo.schSlotValue.broadcastTime);
702    if(dlBrdcstAlloc->sib1TransmissionMode)
703    {
704       if(schBroadcastSib1Alloc(cell, dlSchedInfo.schSlotValue.broadcastTime, dlBrdcstAlloc) != ROK)
705       {
706          DU_LOG("\nERROR  -->  SCH : schBroadcastSib1Alloc failed");
707          dlBrdcstAlloc->sib1TransmissionMode = NO_TRANSMISSION;
708       }
709       else 
710       {
711          dlSchedInfo.isBroadcastPres = true;
712          if((dlBrdcstAlloc->sib1TransmissionMode == NEW_TRANSMISSION) && (!cell->firstSib1Transmitted))
713             cell->firstSib1Transmitted = true;
714       }
715    }
716
717    /*Process Paging Msg*/
718    schProcDlPageAlloc(cell, *slotInd, schInst);
719
720    cell->api->SchScheduleSlot(cell, slotInd, schInst);
721
722    /* Check if any PDU is scheduled at this slot for any UE */
723    for(ueIdx=0; ueIdx<MAX_NUM_UE; ueIdx++)
724    {
725       /* If RAR PDCCH/PDSCH is scheduled for a UE at this slot, fill RAR specific interface 
726        * structure to send to MAC */
727       if(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.rarTime.slot]->rarAlloc[ueIdx] != NULLP)
728       {
729          slot = dlSchedInfo.schSlotValue.rarTime.slot;
730          dlSchedInfo.rarAlloc[ueIdx] = cell->schDlSlotInfo[slot]->rarAlloc[ueIdx];
731          cell->schDlSlotInfo[slot]->rarAlloc[ueIdx] = NULLP;
732       }
733
734       /* If DL-Msg PDCCH/PDSCH is scheduled for a UE at this slot, fill 
735        * specific interface structure to send to MAC */
736       if(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.dlMsgTime.slot]->dlMsgAlloc[ueIdx] != NULLP)
737       {
738          slot = dlSchedInfo.schSlotValue.dlMsgTime.slot;
739          dlSchedInfo.dlMsgAlloc[ueIdx] = cell->schDlSlotInfo[slot]->dlMsgAlloc[ueIdx];
740          cell->schDlSlotInfo[slot]->dlMsgAlloc[ueIdx] = NULLP;
741       }
742    }
743
744    if(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.ulDciTime.slot]->ulGrant != NULLP)
745    {
746       slot = dlSchedInfo.schSlotValue.ulDciTime.slot;
747       dlSchedInfo.ulGrant = cell->schDlSlotInfo[slot]->ulGrant;
748       cell->schDlSlotInfo[slot]->ulGrant = NULLP;
749    }
750
751    /* Send msg to MAC */
752    ret = sendDlAllocToMac(&dlSchedInfo, schInst);
753    if(ret != ROK)
754    {
755       DU_LOG("\nERROR  -->  SCH : Sending DL Broadcast allocation from SCH to MAC failed");
756       return (ret);
757    }
758
759    /* Update DL PRB Usage for all stats group which requested for DL Total PRB Usage */
760    node = cmLListFirst(&schCb[schInst].statistics.activeKpiList.dlTotPrbUseList);
761    while(node)
762    {
763       dlTotalPrbUsage = (TotalPrbUsage *)node->node;
764       if(dlTotalPrbUsage)
765       {
766          dlTotalPrbUsage->numPrbUsedForTx += cell->schDlSlotInfo[slot]->prbAlloc.numPrbAlloc;
767          dlTotalPrbUsage->totalPrbAvailForTx += MAX_NUM_RB;
768       }
769       node = node->next;
770    }
771    
772    /* Re-initialize DL slot */
773    schInitDlSlot(cell->schDlSlotInfo[slot]);
774
775    /* Send UL Resource allocation to MAC */
776    schUlResAlloc(cell, schInst);
777
778 #ifdef NR_DRX 
779    schHandleExpiryDrxTimer(cell);
780 #endif   
781
782    return ret;
783 }
784
785 /**********************************************************************
786   End of file
787  **********************************************************************/
788
789