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