5051095ef188ef309dd423c09e734568b5f5de0e
[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->schDlSlotInfo[pdcchTime.slot]->pdcchUe = ueId;
242    cell->schDlSlotInfo[pdschTime.slot]->pdschUe = ueId;
243    cell->schUlSlotInfo[pucchTime.slot]->pucchUe = ueId;
244
245    /*Re-setting the BO's of all DL LCs in this UE*/
246    for(lcIdx = 0; lcIdx < MAX_NUM_LC; lcIdx++)
247    {
248       ueCb->dlInfo.dlLcCtxt[lcIdx].bo = 0;
249    }
250
251    /* after allocation is done, unset the bo bit for that ue */
252    UNSET_ONE_BIT(ueId, cell->boIndBitMap);
253    return true;
254 }
255
256 /*******************************************************************
257  *
258  * @brief Handles sending DL Page alloc to MAC 
259  *
260  * @details
261  *
262  *    Function : sendDlPAgeAllocToMac
263  *
264  *    Functionality:
265  *     Sends DL Page Resource Allocation to MAC from SCH
266  *
267  * @params[in] 
268  * @return ROK     - success
269  *         RFAILED - failure
270  *
271  * ****************************************************************/
272 uint8_t sendDlPageAllocToMac(DlPageAlloc *dlPageAlloc, Inst inst)
273 {
274    Pst pst;
275
276    memset(&pst, 0, sizeof(Pst));
277    FILL_PST_SCH_TO_MAC(pst, inst);
278    pst.event = EVENT_DL_PAGING_ALLOC;
279
280    return(MacMessageRouter(&pst, (void *)dlPageAlloc));
281 }
282
283 /*******************************************************************
284  *
285  * @brief Handles slot indication at SCH 
286  *
287  * @details
288  *
289  *    Function : schCalcSlotValues
290  *
291  *    Functionality:
292  *     Handles TTI indication received from PHY
293  *
294  * @params[in] 
295  * @return ROK     - success
296  *         RFAILED - failure
297  *
298  * ****************************************************************/
299 void schCalcSlotValues(SlotTimingInfo slotInd, SchSlotValue *schSlotValue, uint16_t numOfSlots)
300 {
301    /****************************************************************
302     * PHY_DELTA - the physical layer delta                         * 
303     * SCHED_DELTA - scheduler schedules one slot ahead             *
304     * BO_DELTA - this delay is considered for BO response and      *
305     *            RLC buffer packet to received at MAC              *
306     * lower-mac (FAPI filling) will be working on PHY_DELTA        *
307     * brdcast scheduler will working on PHY_DELTA + SCHED_DELTA    *
308     * RAR scheduler will working on PHY_DELTA + SCHED_DELTA        *
309     * msg4 scheduler will working on PHY_DELTA + SCHED_DELTA       *
310     * dedicated DL msg scheduler will working                      *
311     *        on PHY_DELTA + SCHED_DELTA + BO_DELTA                 *
312     ****************************************************************/
313
314    ADD_DELTA_TO_TIME(slotInd, schSlotValue->currentTime, PHY_DELTA_DL, numOfSlots);
315    ADD_DELTA_TO_TIME(slotInd, schSlotValue->broadcastTime, PHY_DELTA_DL + SCHED_DELTA, numOfSlots);
316    ADD_DELTA_TO_TIME(slotInd, schSlotValue->rarTime, PHY_DELTA_DL + SCHED_DELTA, numOfSlots);
317    ADD_DELTA_TO_TIME(slotInd, schSlotValue->dlMsgTime, PHY_DELTA_DL + SCHED_DELTA, numOfSlots);
318    ADD_DELTA_TO_TIME(slotInd, schSlotValue->ulDciTime, PHY_DELTA_DL + SCHED_DELTA, numOfSlots);
319 }
320
321 /*******************************************************************
322  *
323  * @brief Checks if a slot is to be scheduled for SSB transmission
324  *
325  * @details
326  *
327  *    Function : schCheckSsbOcc 
328  *
329  *    Functionality:
330  *       Checks if a slot is to be scheduled for SSB transmission
331  *
332  * @params[in] SlotTimingInfo slotTime
333  *             SchCellCb *cell 
334  * @return  Pdu transmission 
335  *
336  * ****************************************************************/
337 PduTxOccsaion schCheckSsbOcc(SchCellCb *cell, SlotTimingInfo slotTime)
338 {
339    uint8_t  ssb_rep;
340
341    ssb_rep = cell->cellCfg.ssbPeriod;
342
343    /* Identify SSB ocassion*/
344    if ((slotTime.sfn % SCH_MIB_TRANS == 0) && (slotTime.slot ==0))
345    {
346       return NEW_TRANSMISSION;
347    }
348    else if(cell->firstSsbTransmitted) 
349    {
350       if((ssb_rep == 5) && ((slotTime.slot == 0 || slotTime.slot == 10)))
351          return REPEATITION;
352       else if((slotTime.sfn % (ssb_rep/10) == 0) && slotTime.slot == 0)
353          return REPEATITION;
354    }
355    /* not SSB occassion */
356    return NO_TRANSMISSION;
357 }
358
359 /*******************************************************************
360  *
361  * @brief Checks if a slot is to be scheduled for SIB1 transmission
362  *
363  * @details
364  *
365  *    Function : schCheckSib1Occ
366  *
367  *    Functionality:
368  *       Checks if a slot is to be scheduled for SIB1 transmission
369  *
370  * @params[in] SlotTimingInfo slotTime
371  *             SchCellCb *cell
372  * @return  Pdu transmission
373  *
374  * ****************************************************************/
375 PduTxOccsaion schCheckSib1Occ(SchCellCb *cell, SlotTimingInfo slotTime)
376 {
377    /* Identify SIB1 occasions */
378    if((slotTime.sfn % SCH_SIB1_TRANS == 0) && (slotTime.slot ==0))
379    {
380       return NEW_TRANSMISSION;
381    }
382    else if(cell->firstSib1Transmitted) 
383    {
384       if((slotTime.sfn % (SIB1_REPETITION_PERIOD/10) == 0) &&
385             (slotTime.slot == 0))
386       {
387          return REPEATITION;
388       }
389    }
390    /* not SIB1 occassion */
391    return NO_TRANSMISSION;
392 }
393
394 /*******************************************************************
395  *
396  * @brief find correct combination of k0-k1 value
397  *
398  * @details
399  *
400  *    Function : findValidK0K1Value
401  *
402  *    Functionality:
403  *       find correct combination of k0-k1 value
404  *
405  * @params[in] SchCellCb *cell, SlotTimingInfo currTime
406  * @params[in] uint8_t ueId, bool dedMsg
407  * @params[in] uint8_t *pdschStartSymbol, uint8_t *pdschSymblLen
408  * @params[in] SlotTimingInfo *pdcchTime, SlotTimingInfo *pdschTime
409  * @params[in] SlotTimingInfo *pucchTime, bool isRetx, SchDlHqProcCb *hqP
410  * @return ROK     - success
411  *         RFAILED - failure
412  *
413  *******************************************************************/
414 bool findValidK0K1Value(SchCellCb *cell, SlotTimingInfo currTime, uint8_t ueId, bool dedMsg,
415                         uint8_t *pdschStartSymbol, uint8_t *pdschSymblLen, SlotTimingInfo *pdcchTime,
416                         SlotTimingInfo *pdschTime, SlotTimingInfo *pucchTime, bool isRetx, SchDlHqProcCb *hqP)
417 {
418    uint8_t numK0 = 0, k0TblIdx = 0, k0Val = 0, k0Index =0 ;
419    uint8_t k1TblIdx = 0, k1Index = 0, k1Val = 0, numK1 = 0;
420    SchUeCb *ueCb = NULLP;
421    SchK0K1TimingInfoTbl *k0K1InfoTbl;
422
423    ADD_DELTA_TO_TIME(currTime, (*pdcchTime), PHY_DELTA_DL + SCHED_DELTA, cell->numSlots);
424 #ifdef NR_TDD
425    if(schGetSlotSymbFrmt(pdcchTime->slot, cell->slotFrmtBitMap) != DL_SLOT)
426    {
427       /* If it is not a DL slot, cannot schedule PDCCH. Return from here. */
428       return false;
429    }
430 #endif
431
432    if(cell->schDlSlotInfo[pdcchTime->slot]->pdcchUe != 0)
433    {
434       return false;
435    }
436
437    if(dedMsg == true)
438    {
439       ueCb = &cell->ueCb[ueId-1];
440       k0K1InfoTbl = &ueCb->k0K1InfoTbl;
441    }
442    else
443    {
444       k0K1InfoTbl = &cell->k0K1InfoTbl;
445    }
446
447    numK0 = k0K1InfoTbl->k0k1TimingInfo[pdcchTime->slot].numK0;
448    for(k0TblIdx = 0; k0TblIdx < numK0; k0TblIdx++)
449    {
450       k0Index = k0K1InfoTbl->k0k1TimingInfo[pdcchTime->slot].k0Indexes[k0TblIdx].k0Index;
451       if(dedMsg != true)
452       {
453          k0Val = cell->cellCfg.dlCfgCommon.schInitialDlBwp.pdschCommon.timeDomRsrcAllocList[k0Index].k0;
454          *pdschStartSymbol = cell->cellCfg.dlCfgCommon.schInitialDlBwp.pdschCommon.timeDomRsrcAllocList[k0Index].startSymbol;
455          *pdschSymblLen = cell->cellCfg.dlCfgCommon.schInitialDlBwp.pdschCommon.timeDomRsrcAllocList[k0Index].lengthSymbol;
456       }
457       else
458       {
459          if(ueCb->ueCfg.spCellCfg.servCellRecfg.initDlBwp.pdschCfg.timeDomRsrcAllociList[k0Index].k0 != NULLP)
460          {
461             k0Val = *(ueCb->ueCfg.spCellCfg.servCellRecfg.initDlBwp.pdschCfg.timeDomRsrcAllociList[k0Index].k0);
462             *pdschStartSymbol = ueCb->ueCfg.spCellCfg.servCellRecfg.initDlBwp.pdschCfg.timeDomRsrcAllociList[k0Index].startSymbol;
463             *pdschSymblLen = ueCb->ueCfg.spCellCfg.servCellRecfg.initDlBwp.pdschCfg.timeDomRsrcAllociList[k0Index].symbolLength;
464          }
465       }
466
467       ADD_DELTA_TO_TIME((*pdcchTime), (*pdschTime), k0Val, cell->numSlots);
468 #ifdef NR_TDD
469       if(schGetSlotSymbFrmt(pdschTime->slot, cell->slotFrmtBitMap) != DL_SLOT)
470       {
471          continue;
472       }
473 #endif
474       if(cell->schDlSlotInfo[pdschTime->slot]->pdschUe != 0)
475       {
476          continue; 
477       }
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          }
494          ADD_DELTA_TO_TIME((*pdschTime),(*pucchTime), k1Val, cell->numSlots);
495 #ifdef NR_TDD
496          if(schGetSlotSymbFrmt(pucchTime->slot, cell->slotFrmtBitMap) == DL_SLOT)
497          {
498             continue;
499          }
500 #endif
501          if(cell->schUlSlotInfo[pucchTime->slot]->pucchUe != 0)
502          {
503             continue; 
504          }
505          if(hqP)
506          {
507             ADD_DELTA_TO_TIME((*pucchTime), hqP->pucchTime, 0, cell->numSlots);
508          }
509          pdcchTime->cellId = cell->cellId;
510          pdschTime->cellId = cell->cellId;
511
512          return true;
513       }
514    }
515    /*
516     * Number of symbols in case of retransmisson should be same as it was in
517     * original transmisson. Symbol availablity checks need to be added.
518     */
519    return false;
520 }
521
522 /*******************************************************************
523 *
524 * @brief Process DL Resource allocation for Page
525 *
526 * @details
527 *
528 *    Function : schProcDlPageAlloc
529 *
530 *    Functionality: Process DL Resource allocation for Page
531 *
532 * @params[in] SchCellCb *cell, SlotTimingInfo currTime, Inst schInst
533 *
534 * @return pointer to return Value(ROK, RFAILED)
535 *
536 * ****************************************************************/
537 uint8_t schProcDlPageAlloc(SchCellCb *cell, SlotTimingInfo currTime, Inst schInst)
538 {
539    DlPageAlloc      dlPageAlloc;
540    CmLList          *pageInfoNode = NULLP;
541    SchPageInfo      *pageInfo = NULLP;
542    SlotTimingInfo   pdschTime;
543    uint32_t         tbSize = 0;
544    uint16_t         startPrb = 0, maxFreePRB = 0, nPRB = 0;
545    uint8_t          ret = RFAILED;
546
547    pageInfoNode = schPageInfoSearchFromPageList(currTime, &(cell->pageCb.pageIndInfoRecord[currTime.sfn]));
548
549    if(pageInfoNode == NULLP)
550    {
551       return ROK;
552    }
553    pageInfo = (SchPageInfo *)pageInfoNode->node;
554    
555    while(true)
556    {
557       dlPageAlloc.cellId = currTime.cellId;
558
559       ADD_DELTA_TO_TIME(currTime, dlPageAlloc.dlPageTime, PHY_DELTA_DL + SCHED_DELTA, cell->numSlots);
560       dlPageAlloc.shortMsgInd  = FALSE;
561       pdschTime = dlPageAlloc.dlPageTime;
562
563       /*Calculate Best FREE BLOCK with MAX PRB count*/
564       maxFreePRB = searchLargestFreeBlock(cell, pdschTime, &startPrb, DIR_DL);
565
566       if(maxFreePRB != 0)
567       {
568          tbSize = calculateEstimateTBSize(pageInfo->msgLen, pageInfo->mcs, NUM_PDSCH_SYMBOL, maxFreePRB, &nPRB);
569       }
570       else
571       {
572          DU_LOG("\nERROR  --> SCH: Unable to get any free block for Paging at SFN:%d, SLOT:%d",\
573                pdschTime.sfn, pdschTime.slot);
574          break;
575       }
576       /*Fill PDCCH: PDCCH Cfg is same as SIB1 as Paging will be a broadcast message*/
577       memcpy(dlPageAlloc.pageDlDci.freqDomainResource, cell->sib1SchCfg.sib1PdcchCfg.coresetCfg.freqDomainResource, 6 * sizeof(uint8_t));
578       dlPageAlloc.pageDlDci.durationSymbols = cell->sib1SchCfg.sib1PdcchCfg.coresetCfg.durationSymbols;
579       dlPageAlloc.pageDlDci.cceRegMappingType = INTERLEAVED_CCE_REG_MAPPING;
580       dlPageAlloc.pageDlDci.cceReg.interleaved.regBundleSize = cell->sib1SchCfg.sib1PdcchCfg.coresetCfg.regBundleSize;
581       dlPageAlloc.pageDlDci.cceReg.interleaved.interleaverSize = cell->sib1SchCfg.sib1PdcchCfg.coresetCfg.interleaverSize;
582       dlPageAlloc.pageDlDci.cceReg.interleaved.shiftIndex = cell->sib1SchCfg.sib1PdcchCfg.coresetCfg.shiftIndex;
583       dlPageAlloc.pageDlDci.ssStartSymbolIndex = cell->sib1SchCfg.sib1PdcchCfg.coresetCfg.startSymbolIndex;
584       dlPageAlloc.pageDlDci.cceIndex = cell->sib1SchCfg.sib1PdcchCfg.dci.cceIndex;
585       dlPageAlloc.pageDlDci.aggregLevel = cell->sib1SchCfg.sib1PdcchCfg.dci.aggregLevel;
586       dlPageAlloc.pageDlDci.precoderGranularity = cell->sib1SchCfg.sib1PdcchCfg.coresetCfg.precoderGranularity;
587       dlPageAlloc.pageDlDci.coreSetSize = cell->sib1SchCfg.sib1PdcchCfg.coresetCfg.coreSetSize;
588       /*Fill BWP*/
589       memcpy(&dlPageAlloc.bwp, &cell->sib1SchCfg.bwp, sizeof(BwpCfg)); 
590
591       /*Fill PDSCH*/
592       if(schFillPagePdschCfg(cell, &dlPageAlloc.pageDlSch, pdschTime, tbSize, pageInfo->mcs, startPrb) != ROK)
593       {
594          DU_LOG("\nERROR  --> SCH: Issue in PDSCH Allocation for Paging at SFN:%d, SLOT:%d",\
595                pdschTime.sfn, pdschTime.slot);
596          break;
597       }
598
599       /*Fill Page PDU information*/
600       dlPageAlloc.pageDlSch.dlPagePduLen = pageInfo->msgLen;
601
602       SCH_ALLOC(dlPageAlloc.pageDlSch.dlPagePdu, sizeof(dlPageAlloc.pageDlSch.dlPagePduLen));
603
604       if(dlPageAlloc.pageDlSch.dlPagePdu == NULLP)
605       {
606          DU_LOG("\nERROR  --> SCH: Memory Allocation Failed during Page Resource allocation");
607          break;
608       }
609       memcpy(dlPageAlloc.pageDlSch.dlPagePdu, pageInfo->pagePdu, dlPageAlloc.pageDlSch.dlPagePduLen);
610
611       /* Send msg to MAC */
612       if(sendDlPageAllocToMac(&dlPageAlloc, schInst) != ROK)
613       {
614          DU_LOG("\nERROR  -->  SCH : Sending DL Paging allocation from SCH to MAC failed");
615          SCH_FREE(dlPageAlloc.pageDlSch.dlPagePdu, sizeof(dlPageAlloc.pageDlSch.dlPagePduLen));
616          break;
617       }
618       ret = ROK;
619       break;
620    }
621
622    /*Remove the Page Node*/
623    SCH_FREE(pageInfo->pagePdu, pageInfo->msgLen);
624    schDeleteFromPageInfoList(&(cell->pageCb.pageIndInfoRecord[currTime.sfn]), pageInfoNode);
625
626    return(ret);
627
628 }
629
630 /*******************************************************************
631  *
632  * @brief Handles slot indication at SCH 
633  *
634  * @details
635  *
636  *    Function : SchProcSlotInd
637  *
638  *    Functionality:
639  *     Handles TTI indication received from PHY
640  *
641  * @params[in] 
642  * @return ROK     - success
643  *         RFAILED - failure
644  *
645  * ****************************************************************/
646 uint8_t SchProcSlotInd(Pst *pst, SlotTimingInfo *slotInd)
647 {
648    uint8_t        ueIdx, ret = ROK;
649    uint16_t       slot;
650    DlSchedInfo    dlSchedInfo;
651    DlBrdcstAlloc  *dlBrdcstAlloc = NULLP;
652    SchCellCb      *cell = NULLP;
653    Inst           schInst = pst->dstInst-SCH_INST_START;
654
655    cell = schCb[schInst].cells[schInst];
656    if(cell == NULLP)
657    {
658       DU_LOG("\nERROR  -->  SCH : Cell Does not exist");
659       return RFAILED;
660    }
661    memset(&dlSchedInfo, 0, sizeof(DlSchedInfo));
662    schCalcSlotValues(*slotInd, &dlSchedInfo.schSlotValue, cell->numSlots);
663    dlBrdcstAlloc = &dlSchedInfo.brdcstAlloc;
664    dlBrdcstAlloc->ssbTransmissionMode = NO_TRANSMISSION;
665    dlBrdcstAlloc->sib1TransmissionMode = NO_TRANSMISSION;
666
667    memcpy(&cell->slotInfo, slotInd, sizeof(SlotTimingInfo));
668    dlBrdcstAlloc->ssbIdxSupported = SSB_IDX_SUPPORTED;
669
670    dlSchedInfo.cellId = cell->cellId;
671    slot = dlSchedInfo.schSlotValue.broadcastTime.slot;
672
673 #ifdef NR_DRX 
674    schHandleStartDrxTimer(cell);
675 #endif
676    
677    /* Check for SSB occassion */
678    dlBrdcstAlloc->ssbTransmissionMode = schCheckSsbOcc(cell, dlSchedInfo.schSlotValue.broadcastTime); 
679    if(dlBrdcstAlloc->ssbTransmissionMode)
680    {
681       if(schBroadcastSsbAlloc(cell, dlSchedInfo.schSlotValue.broadcastTime, dlBrdcstAlloc) != ROK)
682       {
683          DU_LOG("\nERROR  -->  SCH : schBroadcastSsbAlloc failed");
684          dlBrdcstAlloc->ssbTransmissionMode = NO_TRANSMISSION;
685       }
686       else 
687       {
688          dlSchedInfo.isBroadcastPres = true;
689          if((dlBrdcstAlloc->ssbTransmissionMode == NEW_TRANSMISSION) && (!cell->firstSsbTransmitted))
690             cell->firstSsbTransmitted = true;
691       }
692    }
693
694    /* Check for SIB1 occassion */
695    dlBrdcstAlloc->sib1TransmissionMode = schCheckSib1Occ(cell, dlSchedInfo.schSlotValue.broadcastTime);
696    if(dlBrdcstAlloc->sib1TransmissionMode)
697    {
698       if(schBroadcastSib1Alloc(cell, dlSchedInfo.schSlotValue.broadcastTime, dlBrdcstAlloc) != ROK)
699       {
700          DU_LOG("\nERROR  -->  SCH : schBroadcastSib1Alloc failed");
701          dlBrdcstAlloc->sib1TransmissionMode = NO_TRANSMISSION;
702       }
703       else 
704       {
705          dlSchedInfo.isBroadcastPres = true;
706          if((dlBrdcstAlloc->sib1TransmissionMode == NEW_TRANSMISSION) && (!cell->firstSib1Transmitted))
707             cell->firstSib1Transmitted = true;
708       }
709    }
710
711    /*Process Paging Msg*/
712    schProcDlPageAlloc(cell, *slotInd, schInst);
713
714    cell->api->SchScheduleSlot(cell, slotInd, schInst);
715
716    /* Check if any PDU is scheduled at this slot for any UE */
717    for(ueIdx=0; ueIdx<MAX_NUM_UE; ueIdx++)
718    {
719       /* If RAR PDCCH/PDSCH is scheduled for a UE at this slot, fill RAR specific interface 
720        * structure to send to MAC */
721       if(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.rarTime.slot]->rarAlloc[ueIdx] != NULLP)
722       {
723          slot = dlSchedInfo.schSlotValue.rarTime.slot;
724          dlSchedInfo.rarAlloc[ueIdx] = cell->schDlSlotInfo[slot]->rarAlloc[ueIdx];
725          cell->schDlSlotInfo[slot]->rarAlloc[ueIdx] = NULLP;
726       }
727
728       /* If DL-Msg PDCCH/PDSCH is scheduled for a UE at this slot, fill 
729        * specific interface structure to send to MAC */
730       if(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.dlMsgTime.slot]->dlMsgAlloc[ueIdx] != NULLP)
731       {
732          slot = dlSchedInfo.schSlotValue.dlMsgTime.slot;
733          dlSchedInfo.dlMsgAlloc[ueIdx] = cell->schDlSlotInfo[slot]->dlMsgAlloc[ueIdx];
734          cell->schDlSlotInfo[slot]->dlMsgAlloc[ueIdx] = NULLP;
735       }
736    }
737
738    if(cell->schDlSlotInfo[dlSchedInfo.schSlotValue.ulDciTime.slot]->ulGrant != NULLP)
739    {
740       slot = dlSchedInfo.schSlotValue.ulDciTime.slot;
741       dlSchedInfo.ulGrant = cell->schDlSlotInfo[slot]->ulGrant;
742       cell->schDlSlotInfo[slot]->ulGrant = NULLP;
743    }
744
745    /* Send msg to MAC */
746    ret = sendDlAllocToMac(&dlSchedInfo, schInst);
747    if(ret != ROK)
748    {
749       DU_LOG("\nERROR  -->  SCH : Sending DL Broadcast allocation from SCH to MAC failed");
750       return (ret);
751    }
752
753    /* Update DL statistics */
754    if(schCb[schInst].statistics.dlTotalPrbUsage)
755    {
756       schCb[schInst].statistics.dlTotalPrbUsage->numPrbUsedForTx += cell->schUlSlotInfo[slot]->prbAlloc.numPrbAlloc; 
757       schCb[schInst].statistics.dlTotalPrbUsage->totalPrbAvailForTx += MAX_NUM_RB;
758    }
759    
760    /* Re-initialize DL slot */
761    schInitDlSlot(cell->schDlSlotInfo[slot]);
762
763    /* Send UL Resource allocation to MAC */
764    schUlResAlloc(cell, schInst);
765
766 #ifdef NR_DRX 
767    schHandleExpiryDrxTimer(cell);
768 #endif   
769
770    return ret;
771 }
772
773 /**********************************************************************
774   End of file
775  **********************************************************************/
776
777