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