d8c677fca29724af4a4c47e6c2b83d3487f76dd6
[o-du/l2.git] / src / 5gnrsch / sch_common.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
26
27 File:     sch_common.c
28
29  **********************************************************************/
30
31 /** @file sch_common.c
32   @brief This module performs common scheduling
33  */
34 #include "common_def.h"
35 #include "tfu.h"
36 #include "lrg.h"
37
38 #include "tfu.x"
39 #include "lrg.x"
40 #include "du_log.h"
41 #include "du_app_mac_inf.h"
42 #include "mac_sch_interface.h"
43 #include "sch.h"
44 #include "sch_tmr.h"
45 #include "sch_utils.h"
46
47 /**
48  * @brief common resource allocation for SSB
49  *
50  * @details
51  *
52  *     Function : schBroadcastSsbAlloc
53  *     
54  *     This function handles common scheduling for SSB
55  *     
56  *  @param[in]  SchCellCb *cell, cell cb
57  *  @param[in]  DlBrdcstAlloc *dlBrdcstAlloc, DL brdcst allocation
58  *  @return  void
59  **/
60 uint8_t schBroadcastSsbAlloc(SchCellCb *cell, SlotTimingInfo slotTime, DlBrdcstAlloc *dlBrdcstAlloc)
61 {
62    /* schedule SSB */
63    uint8_t ssbStartSymb, idx;
64    uint16_t ssbStartPrb;
65    SchDlSlotInfo *schDlSlotInfo;
66    SsbInfo ssbInfo;
67
68    if(cell == NULL)
69    {
70       DU_LOG("\nERROR  -->  SCH: schBroadcastSsbAlloc() : Cell is NULL");
71       return RFAILED;
72    }
73
74    if(dlBrdcstAlloc == NULL)
75    {
76       DU_LOG("\nERROR  -->  SCH: schBroadcastSsbAlloc() : dlBrdcstAlloc is NULL");
77       return RFAILED;
78    }
79
80    schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
81    ssbStartPrb = cell->cellCfg.ssbSubcOffset; //+Kssb
82    ssbStartSymb = cell->ssbStartSymbArr[dlBrdcstAlloc->ssbIdxSupported-1]; /*since we are supporting only 1 ssb beam */
83
84    /* Assign interface structure */
85    for(idx=0; idx<dlBrdcstAlloc->ssbIdxSupported; idx++)
86    {
87       ssbInfo.ssbIdx              = idx;
88       ssbInfo.fdAlloc.startPrb    = ssbStartPrb;
89       ssbInfo.fdAlloc.numPrb      = SCH_SSB_NUM_PRB;
90       ssbInfo.tdAlloc.startSymb   = ssbStartSymb;
91       ssbInfo.tdAlloc.numSymb     = SCH_SSB_NUM_SYMB;
92       dlBrdcstAlloc->ssbInfo[idx] = ssbInfo;
93       schDlSlotInfo->ssbInfo[idx] = ssbInfo;
94    }
95
96    if((allocatePrbDl(cell, slotTime, ssbStartSymb, SCH_SSB_NUM_SYMB, &ssbInfo.fdAlloc.startPrb, ssbInfo.fdAlloc.numPrb)) != ROK)
97    {
98        DU_LOG("\nERROR  -->  SCH: PRB allocation failed for SSB in SFN:SLOT [%d : %d]", slotTime.sfn, slotTime.slot);
99        return RFAILED;
100    }
101
102
103    schDlSlotInfo->ssbPres = true;
104    schDlSlotInfo->ssbIdxSupported = dlBrdcstAlloc->ssbIdxSupported;
105    return ROK;
106 }
107
108 /**
109  * @brief common resource allocation for SIB1
110  *
111  * @details
112  *
113  *     Function : schBroadcastSib1Alloc
114  *     
115  *     This function handles common scheduling for SIB1
116  *     
117  *  @param[in]  SchCellCb *cell, cell cb
118  *  @param[in]  DlBrdcstAlloc *dlBrdcstAlloc, DL brdcst allocation
119  *  @return  void
120  **/
121 uint8_t schBroadcastSib1Alloc(SchCellCb *cell, SlotTimingInfo slotTime, DlBrdcstAlloc *dlBrdcstAlloc)
122 {
123    uint8_t dmrsStartSymbol, startSymbol, numSymbol ;
124    DmrsInfo dmrs;
125    PdschFreqAlloc freqAlloc;
126    PdschTimeAlloc timeAlloc;
127    SchDlSlotInfo *schDlSlotInfo = NULLP;
128
129    if(cell == NULL)
130    {
131       DU_LOG("\nERROR  -->  SCH: schBroadcastSsbAlloc() : Cell is NULL");
132       return RFAILED;
133    }
134
135    if(dlBrdcstAlloc == NULL)
136    {
137       DU_LOG("\nERROR  -->  SCH: schBroadcastSsbAlloc() : dlBrdcstAlloc is NULL");
138       return RFAILED;
139    }
140    
141    dlBrdcstAlloc->crnti = SI_RNTI;
142    dmrs = cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.dmrs;
143    freqAlloc = cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc;
144    timeAlloc = cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschTimeAlloc;
145    schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
146
147    /* Find total symbols used including DMRS */
148    /* If there are no DRMS symbols, findDmrsStartSymbol() returns MAX_SYMB_PER_SLOT,
149     * in that case only PDSCH symbols are marked as occupied */
150    dmrsStartSymbol = findDmrsStartSymbol(dmrs.dlDmrsSymbPos);   
151    if(dmrsStartSymbol == MAX_SYMB_PER_SLOT)
152    {
153       startSymbol = timeAlloc.startSymb;
154       numSymbol = timeAlloc.numSymb;
155    }
156    /* If DMRS symbol is found, mark DMRS and PDSCH symbols as occupied */
157    else
158    {
159       startSymbol = dmrsStartSymbol;
160       numSymbol = dmrs.nrOfDmrsSymbols + timeAlloc.numSymb;
161    }
162
163    /* Allocate PRB */
164    if((allocatePrbDl(cell, slotTime, startSymbol, numSymbol, &freqAlloc.startPrb, freqAlloc.numPrb)) != ROK)
165    {
166        DU_LOG("\nERROR  -->  SCH: PRB allocation failed for SIB1 in SFN:Slot [%d : %d]", slotTime.sfn, slotTime.slot);
167        return RFAILED;
168    }
169
170    memcpy(&dlBrdcstAlloc->sib1Alloc.bwp, &cell->sib1SchCfg.bwp, sizeof(BwpCfg)); 
171    SCH_ALLOC(dlBrdcstAlloc->sib1Alloc.sib1PdcchCfg,sizeof(PdcchCfg));
172    if(dlBrdcstAlloc->sib1Alloc.sib1PdcchCfg)
173    {
174       memcpy(dlBrdcstAlloc->sib1Alloc.sib1PdcchCfg, &cell->sib1SchCfg.sib1PdcchCfg, sizeof(PdcchCfg)); 
175       schDlSlotInfo->sib1Pres = true;
176    }
177    else
178    {
179       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in %s", __func__);
180       return RFAILED;
181    }
182    return ROK;
183 }
184
185 /*******************************************************************
186  *
187  * @brief Handles sending UL scheduler info to MAC 
188  *
189  * @details
190  *
191  *    Function : sendUlSchInfoToMac
192  *
193  *    Functionality:
194  *     Sends UL Sch info to MAC from SCH
195  *
196  * @params[in] 
197  * @return ROK     - success
198  *         RFAILED - failure
199  *
200  * ****************************************************************/
201 int sendUlSchInfoToMac(UlSchedInfo *ulSchedInfo, Inst inst)
202 {
203    Pst pst;
204
205    memset(&pst, 0, sizeof(Pst));
206    FILL_PST_SCH_TO_MAC(pst, inst);
207    pst.event = EVENT_UL_SCH_INFO;
208
209    return(MacMessageRouter(&pst, (void *)ulSchedInfo));
210 }
211
212 /**
213  * @brief Function to fill Pucch Format 0
214  *
215  * @details
216  *
217  *     Function : fillPucchFormat0
218  *     
219  *     Function to fill Pucch format 0
220  *     
221  *  @param[in]  SchPucchInfo pointer, SchPucchResrcInfo pointer
222  *  @return  void
223  **/
224
225 void fillPucchFormat0(SchPucchInfo *ulSchedPucch, SchPucchResrcInfo *resrcInfo)
226 {
227    if(resrcInfo->SchPucchFormat.format0)
228    {
229       ulSchedPucch->fdAlloc.numPrb = PUCCH_NUM_PRB_FORMAT_0_1_4;
230       ulSchedPucch->pucchFormat  = PUCCH_FORMAT_0;
231       ulSchedPucch->initialCyclicShift =  resrcInfo->SchPucchFormat.format0->initialCyclicShift;
232       ulSchedPucch->tdAlloc.numSymb = resrcInfo->SchPucchFormat.format0->numSymbols;
233       ulSchedPucch->tdAlloc.startSymb = resrcInfo->SchPucchFormat.format0->startSymbolIdx;
234    }
235 }
236
237 /**
238  * @brief Function to fill Pucch Format 1
239  *
240  * @details
241  *
242  *     Function : fillPucchFormat1
243  *     
244  *     Function to fill Pucch format 1
245  *     
246  *  @param[in]  SchPucchInfo pointer, SchPucchResrcInfo pointer
247  *  @return  void
248  **/
249
250 void fillPucchFormat1(SchPucchInfo *ulSchedPucch, SchPucchResrcInfo *resrcInfo)
251 {
252    if(resrcInfo->SchPucchFormat.format1)
253    {
254       ulSchedPucch->fdAlloc.numPrb = PUCCH_NUM_PRB_FORMAT_0_1_4;
255       ulSchedPucch->pucchFormat  = PUCCH_FORMAT_1;
256       ulSchedPucch->initialCyclicShift =  resrcInfo->SchPucchFormat.format1->initialCyclicShift;
257       ulSchedPucch->tdAlloc.numSymb = resrcInfo->SchPucchFormat.format1->numSymbols;
258       ulSchedPucch->tdAlloc.startSymb = resrcInfo->SchPucchFormat.format1->startSymbolIdx;
259       ulSchedPucch->timeDomOCC =  resrcInfo->SchPucchFormat.format1->timeDomOCC;
260   }
261 }
262
263 /**
264  * @brief Function to fill Pucch format for UL Sched Info
265  *
266  * @details
267  *
268  *     Function : fillUlSchedPucchFormat
269  *     
270  *     Function to fill Pucch format for UL Sched Info
271  *     
272  *  @param[in]  pucchFormat , SchPucchInfo pointer,
273  *  @param[in]  SchPucchFormatCfg pointer, SchPucchResrcInfo pointer
274  *  @return  void
275  **/
276
277 uint8_t fillUlSchedPucchFormat(uint8_t pucchFormat, SchPucchInfo *ulSchedPucch,\
278    SchPucchResrcInfo *resrcInfo, SchPucchFormatCfg *formatCfg)
279 {
280    uint8_t ret = ROK;
281
282    switch(pucchFormat)
283    {
284       case PUCCH_FORMAT_0:
285          {
286             if(resrcInfo)
287                fillPucchFormat0(ulSchedPucch, resrcInfo);
288             return ret;
289          }
290       case PUCCH_FORMAT_1:
291          {
292             if(resrcInfo)
293             {
294                fillPucchFormat1(ulSchedPucch, resrcInfo);
295             }
296             if(formatCfg)
297             {
298                ulSchedPucch->addDmrs = formatCfg->addDmrs;
299                ulSchedPucch->pi2BPSK = formatCfg->pi2BPSK;
300             }
301             return ret;
302          }/* To Add support for more Pucch Format */
303
304       default:
305          DU_LOG("\nERROR  --> SCH : Invalid PUCCH format[%d] in fillUlSchedPucchFormatCfg()", pucchFormat);
306          ret = RFAILED;
307          return ret;
308    }
309    return ret;
310 }
311
312 /**
313  * @brief Function to fill Pucch Dedicated Cfg for UL Sched Info
314  *
315  * @details
316  *
317  *     Function : fillUlSchedPucchDedicatedCfg
318  *     
319  *     Function to fill Pucch Dedicated Cfg for UL Sched Info
320  *     
321  *  @param[in]  pucchFormat to be filled
322  *  @param[in]  SchPucchFormatCfg pointer, SchPucchCfg pointer
323  *  @return  void
324  **/
325
326 uint8_t fillUlSchedPucchDedicatedCfg(SchCellCb *cell, SchPucchCfg *pucchDedCfg,\
327    SlotTimingInfo *slotInfo, SchPucchInfo *ulSchedPucch)
328 {
329    uint8_t ret, resrcSetIdx, resrcIdx, schedReqIdx, srPeriodicity = 0;
330    uint16_t srOffset = 0;
331    uint16_t numSlots = cell->numSlots;
332    bool isAllocated = false;
333    uint16_t pucchStartPrb;
334    ret = ROK;
335    if(pucchDedCfg->resrcSet && pucchDedCfg->resrc)
336    {
337       //Assuming one entry in the list
338       for(resrcSetIdx = 0; resrcSetIdx < pucchDedCfg->resrcSet->resrcSetToAddModListCount; resrcSetIdx++)
339       {
340          for(resrcIdx = 0; resrcIdx < pucchDedCfg->resrc->resrcToAddModListCount; resrcIdx++)
341          {
342             if(pucchDedCfg->resrcSet->resrcSetToAddModList[resrcSetIdx].resrcList[resrcSetIdx] ==\
343                   pucchDedCfg->resrc->resrcToAddModList[resrcIdx].resrcId)
344             {
345                ulSchedPucch->intraFreqHop = pucchDedCfg->resrc->resrcToAddModList[resrcIdx].intraFreqHop;
346                ulSchedPucch->secondPrbHop = pucchDedCfg->resrc->resrcToAddModList[resrcIdx].secondPrbHop;
347                ulSchedPucch->fdAlloc.startPrb = pucchDedCfg->resrc->resrcToAddModList[resrcIdx].startPrb;
348                ulSchedPucch->pucchFormat = pucchDedCfg->resrc->resrcToAddModList[resrcIdx].pucchFormat;
349                ret = fillUlSchedPucchFormat(ulSchedPucch->pucchFormat, ulSchedPucch,\
350                      &pucchDedCfg->resrc->resrcToAddModList[resrcIdx], NULLP);
351                if(ret == RFAILED)
352                   return ret;
353
354                pucchStartPrb = pucchDedCfg->resrc->resrcToAddModList[resrcIdx].startPrb;
355                ret = allocatePrbUl(cell, *slotInfo, ulSchedPucch->tdAlloc.startSymb, ulSchedPucch->tdAlloc.numSymb, &pucchStartPrb, PUCCH_NUM_PRB_FORMAT_0_1_4);
356                if(ret == ROK)
357                {
358                   isAllocated = true;
359                   break;
360                }
361             }
362          }
363          if(isAllocated)
364          break;
365       }
366    }
367
368    if(pucchDedCfg->format1)
369    {
370       ret = fillUlSchedPucchFormat(ulSchedPucch->pucchFormat, ulSchedPucch, NULLP, pucchDedCfg->format1);
371       if(ret == RFAILED)
372          return ret;
373    }
374
375    if(!isAllocated)
376    {
377       return RFAILED;
378    }
379
380    /* setting SR and UCI flag */
381    if(pucchDedCfg->schedReq)
382    {
383       for(schedReqIdx = 0; schedReqIdx < pucchDedCfg->schedReq->schedAddModListCount; schedReqIdx++)
384       {
385          srPeriodicity = pucchDedCfg->schedReq->schedAddModList[schedReqIdx].periodicity;
386          srOffset      = pucchDedCfg->schedReq->schedAddModList[schedReqIdx].offset;
387          break;
388       }
389       if(((numSlots * slotInfo->sfn + slotInfo->slot - srOffset) % srPeriodicity) == 0)
390       {
391          ulSchedPucch->srFlag  = true;
392       }
393    }
394    return ret;
395 }
396
397 /**
398  * @brief Function to fill Pucch Resource Info
399  *
400  * @details
401  *
402  *     Function : fillPucchResourceInfo
403  *     
404  *     Function to fill Pucch Resource Info
405  *     
406  *  @param[in]  SchPucchInfo *schPucchInfo, Inst inst
407  *  @return  ROK/RFAILED
408  **/
409
410 uint16_t fillPucchResourceInfo(uint8_t ueId, SchPucchInfo *schPucchInfo, Inst inst, SlotTimingInfo slotInfo)
411 {
412    uint8_t ret = ROK,  ueIdx = 0, pucchIdx = 0;
413    SchCellCb  *cell = schCb[inst].cells[inst];
414    SchPucchCfgCmn *pucchCfg = NULLP;
415    SchBwpParams *ulBwp = NULLP;
416 #ifdef NR_DRX 
417    SchUeCb *ueCb = NULLP;
418 #endif
419    uint16_t startPrb;
420
421    ueIdx = ueId -1;
422 #ifdef NR_DRX 
423    ueCb = &(cell->ueCb[ueIdx]); 
424    if(ueCb->ueDrxInfoPres)
425    {
426       if(!ueCb->drxUeCb.drxUlUeActiveStatus)
427          return RFAILED;
428    }
429 #endif
430    if(cell->ueCb[ueIdx].ueCfg.spCellCfg.servCellRecfg.initUlBwp.pucchCfgPres)
431    {
432       /* fill pucch dedicated cfg */
433       ret = fillUlSchedPucchDedicatedCfg(cell,\
434        &cell->ueCb[ueIdx].ueCfg.spCellCfg.servCellRecfg.initUlBwp.pucchCfg, &slotInfo, schPucchInfo);
435       if(ret == RFAILED)
436       {
437          memset(schPucchInfo, 0, sizeof(SchPucchInfo));
438          DU_LOG("\nERROR  --> SCH : Filling PUCCH dedicated cfg failed at fillPucchResourceInfo()");
439          return ret;
440       }
441    }
442    else
443    {
444       /* fill pucch common cfg */
445       /* derive pucchResourceSet from schCellCfg */
446       pucchCfg = &cell->cellCfg.ulCfgCommon.schInitialUlBwp.pucchCommon;
447       pucchIdx = pucchCfg->pucchResourceCommon;
448       ulBwp = &cell->cellCfg.ulCfgCommon.schInitialUlBwp.bwp;
449       startPrb = ulBwp->freqAlloc.startPrb + pucchResourceSet[pucchIdx][3];
450       ret = allocatePrbUl(cell, slotInfo, pucchResourceSet[pucchIdx][1], pucchResourceSet[pucchIdx][2],\
451             &startPrb, PUCCH_NUM_PRB_FORMAT_0_1_4);
452       if (ret == ROK)
453       {
454          schPucchInfo->fdAlloc.startPrb = ulBwp->freqAlloc.startPrb + pucchResourceSet[pucchIdx][3];
455          schPucchInfo->fdAlloc.numPrb = PUCCH_NUM_PRB_FORMAT_0_1_4;
456          schPucchInfo->tdAlloc.startSymb = pucchResourceSet[pucchIdx][1];
457          schPucchInfo->tdAlloc.numSymb = pucchResourceSet[pucchIdx][2];
458          schPucchInfo->pucchFormat = pucchResourceSet[pucchIdx][0];
459
460          /* set SR and UCI flag to false */
461          schPucchInfo->srFlag  = true;
462       }
463    }
464    return ROK;
465 }
466
467 /**
468  * @brief resource allocation for UL
469  *
470  * @details
471  *
472  *     Function : schUlResAlloc
473  *     
474  *     This function handles UL Resource allocation
475  *     
476  *  @param[in]  SchCellCb *cell, cellCb
477  *  @return  void
478  **/
479 uint8_t schUlResAlloc(SchCellCb *cell, Inst schInst)
480 {
481    int ret = ROK;
482 #ifdef NR_DRX 
483    SchUeCb   *ueCb;
484 #endif
485    UlSchedInfo ulSchedInfo;
486    SchUlSlotInfo  *schUlSlotInfo = NULLP;
487    SlotTimingInfo ulTimingInfo;
488    CmLList        *node = NULLP;
489    TotalPrbUsage  *ulTotalPrbUsage = NULLP;
490
491    memset(&ulSchedInfo, 0, sizeof(UlSchedInfo));
492
493    /* add PHY delta */
494    ADD_DELTA_TO_TIME(cell->slotInfo,ulTimingInfo,PHY_DELTA_UL+SCHED_DELTA, cell->numSlots);
495
496    ulSchedInfo.cellId = cell->cellId;
497    ulSchedInfo.slotIndInfo.cellId = ulSchedInfo.cellId;
498    ulSchedInfo.slotIndInfo.sfn = ulTimingInfo.sfn;
499    ulSchedInfo.slotIndInfo.slot = ulTimingInfo.slot;
500
501    /* Schedule resources for PRACH */
502    if(cell->firstSib1Transmitted)
503     schPrachResAlloc(cell, &ulSchedInfo, ulTimingInfo);
504
505    schUlSlotInfo = cell->schUlSlotInfo[ulTimingInfo.slot]; 
506    if(schUlSlotInfo->schPuschInfo)
507    {
508       GET_CRNTI(ulSchedInfo.crnti, schUlSlotInfo->puschUe);
509       /* Check the ue drx status if the UE is active for uplink scheduling or not  */
510 #ifdef NR_DRX 
511       ueCb = schGetUeCb(cell, ulSchedInfo.crnti);
512       if(ueCb->ueDrxInfoPres)
513       {
514          if(!ueCb->drxUeCb.drxUlUeActiveStatus)
515             return RFAILED;
516       }
517 #endif
518       ulSchedInfo.dataType |= SCH_DATATYPE_PUSCH;
519       memcpy(&ulSchedInfo.schPuschInfo, schUlSlotInfo->schPuschInfo,
520             sizeof(SchPuschInfo));
521       SCH_FREE(schUlSlotInfo->schPuschInfo, sizeof(SchPuschInfo));
522       schUlSlotInfo->schPuschInfo = NULL;
523    }
524
525    if(schUlSlotInfo->pucchPres)
526    {
527       GET_CRNTI(ulSchedInfo.crnti, schUlSlotInfo->pucchUe);
528       ret = fillPucchResourceInfo(schUlSlotInfo->pucchUe, &schUlSlotInfo->schPucchInfo, schInst, ulTimingInfo);
529       if (ret == ROK)
530       {
531          ulSchedInfo.dataType |= SCH_DATATYPE_UCI;
532          memcpy(&ulSchedInfo.schPucchInfo, &schUlSlotInfo->schPucchInfo,
533                sizeof(SchPucchInfo));
534       }
535       else
536       {
537          return RFAILED;
538       }
539       memset(&schUlSlotInfo->schPucchInfo, 0, sizeof(SchPucchInfo));
540    }
541
542    /* Send msg to MAC */
543    ret = sendUlSchInfoToMac(&ulSchedInfo, schInst);
544    if(ret != ROK)
545    {
546       DU_LOG("\nERROR  -->  SCH : Sending UL Sch info from SCH to MAC failed");
547    }
548
549    /* Update DL PRB Usage for all stats group which requested for DL Total PRB Usage */
550    node = cmLListFirst(&schCb[schInst].statistics.activeKpiList.ulTotPrbUseList);
551    while(node)
552    {
553       ulTotalPrbUsage = (TotalPrbUsage *)node->node;
554       ulTotalPrbUsage->numPrbUsedForTx += schUlSlotInfo->prbAlloc.numPrbAlloc;
555       ulTotalPrbUsage->totalPrbAvailForTx += MAX_NUM_RB;
556       node = node->next;
557    }
558
559    /* Re-initialize UL Slot */
560    schInitUlSlot(schUlSlotInfo);
561    return ret;
562 }
563
564 /*******************************************************************
565  *
566  * @brief Fills pdcch and pdsch info for msg4
567  *
568  * @details
569  *
570  *    Function : schDlRsrcAllocMsg4
571  *
572  *    Functionality:
573  *       Fills pdcch and pdsch info for msg4
574  *
575  * @params[in] SchCellCb *cell, SlotTimingInfo msg4Time
576  * @params[in] uint8_t ueId, DlMsgSchInfo *dlMsgAlloc
577  * @params[in] uint8_t pdschStartSymbol, uint8_t pdschNumSymbols
578  * @params[in] bool isRetx, SchDlHqProcCb *hqP
579  * @return ROK     - success
580  *         RFAILED - failure
581  *
582  * ****************************************************************/
583 uint8_t schDlRsrcAllocMsg4(SchCellCb *cell, SlotTimingInfo msg4Time, uint8_t ueId, DlMsgSchInfo *dlMsgAlloc,\
584                            uint8_t pdschStartSymbol, uint8_t pdschNumSymbols, bool isRetx, SchDlHqProcCb *hqP)
585 {
586    uint8_t coreset0Idx = 0;
587    uint8_t firstSymbol = 0;
588    uint8_t numSymbols = 0;
589    uint8_t mcs = DEFAULT_MCS;                         /* MCS fixed to 4 */
590    uint8_t dmrsStartSymbol = 0, startSymbol = 0, numSymbol = 0;
591    uint16_t tbSize = 0;
592    uint16_t numRbs;
593    SchBwpDlCfg *initialBwp = NULLP;
594    PdcchCfg *pdcch = NULLP;
595    PdschCfg *pdsch = NULLP;
596    BwpCfg *bwp = NULLP;
597    DlMsgSchInfo *msg4Alloc = NULLP;
598
599    if(cell == NULL)
600    {
601       DU_LOG("\nERROR  -->  SCH: schDlRsrcAllocMsg4() : Cell is NULL");
602       return RFAILED;
603    }
604
605    if(dlMsgAlloc == NULL)
606    {
607       DU_LOG("\nERROR  -->  SCH: schDlRsrcAllocMsg4() :  dlMsgAlloc is NULL");
608       return RFAILED;
609    }
610
611    msg4Alloc = dlMsgAlloc;
612    initialBwp   = &cell->cellCfg.dlCfgCommon.schInitialDlBwp;
613    SCH_ALLOC(msg4Alloc->dlMsgPdcchCfg, sizeof(PdcchCfg));
614
615    if(!msg4Alloc->dlMsgPdcchCfg)
616    {
617       DU_LOG("\nERROR  --> SCH : Memory allocation failed in %s",__func__);
618       return RFAILED;
619    }
620    pdcch = msg4Alloc->dlMsgPdcchCfg;
621    bwp = &msg4Alloc->bwp;
622    coreset0Idx  = initialBwp->pdcchCommon.commonSearchSpace.coresetId;
623
624    fillDlMsgInfo(msg4Alloc, cell->raCb[ueId-1].tcrnti, isRetx, hqP);
625    msg4Alloc->dlMsgPduLen = cell->raCb[ueId-1].dlMsgPduLen;
626
627    /* derive the sib1 coreset0 params from table 13-1 spec 38.213 */
628    numRbs     = coresetIdxTable[coreset0Idx][1];
629    numSymbols = coresetIdxTable[coreset0Idx][2];
630
631    /* calculate time domain parameters */
632    uint16_t mask = 0x2000;
633    for(firstSymbol=0; firstSymbol<MAX_SYMB_PER_SLOT; firstSymbol++)
634    {
635       if(initialBwp->pdcchCommon.commonSearchSpace.monitoringSymbol & mask)
636          break;
637       else
638          mask = mask>>1;
639    }
640
641    /* fill BWP */
642    bwp->freqAlloc.numPrb   = initialBwp->bwp.freqAlloc.numPrb;
643    bwp->freqAlloc.startPrb = initialBwp->bwp.freqAlloc.startPrb;
644    bwp->subcarrierSpacing  = initialBwp->bwp.scs;
645    bwp->cyclicPrefix       = initialBwp->bwp.cyclicPrefix;
646
647    /* fill the PDCCH PDU */
648    pdcch->coresetCfg.startSymbolIndex = firstSymbol;
649    pdcch->coresetCfg.durationSymbols = numSymbols;
650    memcpy(pdcch->coresetCfg.freqDomainResource, \
651       cell->cellCfg.dlCfgCommon.schInitialDlBwp.pdcchCommon.commonSearchSpace.freqDomainRsrc, FREQ_DOM_RSRC_SIZE);
652
653    pdcch->coresetCfg.cceRegMappingType = 1; /* coreset0 is always interleaved */
654    pdcch->coresetCfg.regBundleSize = 6;    /* spec-38.211 sec 7.3.2.2 */
655    pdcch->coresetCfg.interleaverSize = 2;  /* spec-38.211 sec 7.3.2.2 */
656    pdcch->coresetCfg.coreSetType = 0;
657    pdcch->coresetCfg.coreSetSize = numRbs;
658    pdcch->coresetCfg.shiftIndex = cell->cellCfg.phyCellId;
659    pdcch->coresetCfg.precoderGranularity = 0; /* sameAsRegBundle */
660    pdcch->numDlDci = 1;
661    pdcch->dci.rnti = cell->raCb[ueId-1].tcrnti;
662    pdcch->dci.scramblingId = cell->cellCfg.phyCellId;
663    pdcch->dci.scramblingRnti = 0;
664    pdcch->dci.cceIndex = 4; /* considering SIB1 is sent at cce 0-1-2-3 */
665    pdcch->dci.aggregLevel = 4;
666    pdcch->dci.beamPdcchInfo.numPrgs = 1;
667    pdcch->dci.beamPdcchInfo.prgSize = 1;
668    pdcch->dci.beamPdcchInfo.digBfInterfaces = 0;
669    pdcch->dci.beamPdcchInfo.prg[0].pmIdx = 0;
670    pdcch->dci.beamPdcchInfo.prg[0].beamIdx[0] = 0;
671    pdcch->dci.txPdcchPower.beta_pdcch_1_0 = 0;
672    pdcch->dci.txPdcchPower.powerControlOffsetSS = 0;
673    pdsch = &pdcch->dci.pdschCfg; 
674    
675    /* fill the PDSCH PDU */
676    uint8_t cwCount = 0;
677    pdsch->pduBitmap = 0; /* PTRS and CBG params are excluded */
678    pdsch->rnti = cell->raCb[ueId-1].tcrnti;
679    pdsch->pduIndex = 0;
680    pdsch->numCodewords = 1;
681    for(cwCount = 0; cwCount < pdsch->numCodewords; cwCount++)
682    {
683       pdsch->codeword[cwCount].targetCodeRate = 308;
684       pdsch->codeword[cwCount].qamModOrder = 2;
685       pdsch->codeword[cwCount].mcsIndex = mcs; /* mcs configured to 4 */
686       pdsch->codeword[cwCount].mcsTable = 0; /* notqam256 */
687       if(isRetx != TRUE)
688       {
689          tbSize = schCalcTbSize(msg4Alloc->dlMsgPduLen + TX_PAYLOAD_HDR_LEN); /* MSG4 size + FAPI header size*/
690          hqP->tbInfo[cwCount].tbSzReq = tbSize;
691          pdsch->codeword[cwCount].rvIndex = 0;
692       }
693       else
694       {
695          pdsch->codeword[cwCount].rvIndex = (pdsch->codeword[cwCount].rvIndex +1) & 0x03;
696          tbSize = hqP->tbInfo[cwCount].tbSzReq;
697       }
698       pdsch->codeword[cwCount].tbSize = tbSize;
699    }
700    pdsch->dataScramblingId = cell->cellCfg.phyCellId;
701    pdsch->numLayers = 1;
702    pdsch->transmissionScheme = 0;
703    pdsch->refPoint = 0;
704    pdsch->dmrs.dlDmrsSymbPos = DL_DMRS_SYMBOL_POS; 
705    pdsch->dmrs.dmrsConfigType = 0; /* type-1 */
706    pdsch->dmrs.dlDmrsScramblingId = cell->cellCfg.phyCellId;
707    pdsch->dmrs.scid = 0;
708    pdsch->dmrs.numDmrsCdmGrpsNoData = 1;
709    pdsch->dmrs.dmrsPorts = 0;
710    pdsch->dmrs.mappingType      = DMRS_MAP_TYPE_A; /* Setting to Type-A */
711    pdsch->dmrs.nrOfDmrsSymbols  = NUM_DMRS_SYMBOLS;
712    pdsch->dmrs.dmrsAddPos       = DMRS_ADDITIONAL_POS;
713
714    pdsch->pdschTimeAlloc.startSymb = pdschStartSymbol; 
715    pdsch->pdschTimeAlloc.numSymb = pdschNumSymbols;
716
717    pdsch->pdschFreqAlloc.resourceAllocType = 1; /* RAT type-1 RIV format */
718    pdsch->pdschFreqAlloc.startPrb = MAX_NUM_RB;
719    pdsch->pdschFreqAlloc.numPrb = schCalcNumPrb(tbSize, mcs, pdschNumSymbols);
720    pdsch->pdschFreqAlloc.vrbPrbMapping = 0; /* non-interleaved */
721
722    /* Find total symbols occupied including DMRS */
723    dmrsStartSymbol = findDmrsStartSymbol(pdsch->dmrs.dlDmrsSymbPos);
724    /* If there are no DRMS symbols, findDmrsStartSymbol() returns MAX_SYMB_PER_SLOT,
725     * in that case only PDSCH symbols are marked as occupied */
726    if(dmrsStartSymbol == MAX_SYMB_PER_SLOT)
727    {
728       startSymbol = pdsch->pdschTimeAlloc.startSymb;
729       numSymbol = pdsch->pdschTimeAlloc.numSymb;
730    }
731    /* If DMRS symbol is found, mark DMRS and PDSCH symbols as occupied */
732    else
733    {
734       startSymbol = dmrsStartSymbol;
735       numSymbol = pdsch->dmrs.nrOfDmrsSymbols + pdsch->pdschTimeAlloc.numSymb;
736    }
737
738    /* Allocate the number of PRBs required for RAR PDSCH */
739    if((allocatePrbDl(cell, msg4Time, startSymbol, numSymbol,\
740       &pdsch->pdschFreqAlloc.startPrb, pdsch->pdschFreqAlloc.numPrb)) != ROK)
741    {
742       DU_LOG("\nERROR  --> SCH : Resource allocation failed for MSG4");
743       SCH_FREE(msg4Alloc->dlMsgPdcchCfg, sizeof(PdcchCfg));
744       return RFAILED;
745    }
746
747    pdsch->beamPdschInfo.numPrgs = 1;
748    pdsch->beamPdschInfo.prgSize = 1;
749    pdsch->beamPdschInfo.digBfInterfaces = 0;
750    pdsch->beamPdschInfo.prg[0].pmIdx = 0;
751    pdsch->beamPdschInfo.prg[0].beamIdx[0] = 0;
752    pdsch->txPdschPower.powerControlOffset = 0;
753    pdsch->txPdschPower.powerControlOffsetSS = 0;
754
755    return ROK;
756 }
757  
758 /*******************************************************************
759  *
760  * @brief Scheduling for Pucch Resource
761  *
762  * @details
763  *
764  *    Function : schAllocPucchResource
765  *
766  *    Functionality:
767  *       Scheduling for Pucch Resource
768  *
769  * @params[in] SchCellCb *cell, SlotTimingInfo pucchTime, crnti
770  * @params[in] SchUeCb *ueCb, bool isRetx, SchDlHqProcCb *hqP
771  * @return ROK     - success
772  *         RFAILED - failure
773  *
774  *******************************************************************/
775
776 uint16_t schAllocPucchResource(SchCellCb *cell, SlotTimingInfo pucchTime, uint16_t crnti,
777                                SchUeCb *ueCb, bool isRetx, SchDlHqProcCb *hqP)
778 {
779    uint16_t pucchSlot = 0;
780    SchUlSlotInfo  *schUlSlotInfo = NULLP;
781
782    pucchSlot = pucchTime.slot;
783    schUlSlotInfo = cell->schUlSlotInfo[pucchSlot];
784    memset(&schUlSlotInfo->schPucchInfo, 0, sizeof(SchPucchInfo));
785
786    schUlSlotInfo->pucchPres = true;
787    if(ueCb != NULLP)
788    {
789       /* set HARQ flag to true */
790       schUlSlotInfo->schPucchInfo.harqInfo.harqBitLength = 1; /* 1 bit for HARQ */
791       ADD_DELTA_TO_TIME(pucchTime, pucchTime, 3, cell->numSlots); /* SLOT_DELAY=3 */
792       cmLListAdd2Tail(&(ueCb->hqDlmap[pucchTime.slot]->hqList), &hqP->ulSlotLnk);
793    }
794    return ROK;
795 }
796
797 /*******************************************************************
798  *
799  * @brief Fills pdcch and pdsch info for dedicated DL msg
800  *
801  * @details
802  *
803  *    Function : schDlRsrcAllocDlMsg
804  *
805  *    Functionality:
806  *       Fills pdcch and pdsch info for dl msg
807  *
808  * @params[in] SchCellCb *cell, SlotTimingInfo slotTime
809  * @params[in] uint16_t crnti, uint32_t tbSize
810  * @params[in] DlMsgSchInfo *dlMsgAlloc, uint16_t startPRB
811  * @params[in] uint8_t pdschStartSymbol, uint8_t pdschNumSymbols
812  * @params[in] bool isRetx, SchDlHqProcCb *hqP
813  * @return ROK     - success
814  *         RFAILED - failure
815  *
816  * ****************************************************************/
817 uint8_t schDlRsrcAllocDlMsg(SchCellCb *cell, SlotTimingInfo slotTime, uint16_t crnti,
818                 uint32_t tbSize, DlMsgSchInfo *dlMsgAlloc, uint16_t startPRB, uint8_t pdschStartSymbol,
819                 uint8_t pdschNumSymbols, bool isRetx, SchDlHqProcCb *hqP)
820 {
821    uint8_t ueId=0;
822    uint8_t cwCount = 0, rbgCount = 0, pdcchStartSymbol = 0;
823    PdcchCfg *pdcch = NULLP;
824    PdschCfg *pdsch = NULLP;
825    BwpCfg *bwp = NULLP;
826    SchUeCb ueCb;
827    SchControlRsrcSet coreset1;
828    SchSearchSpace searchSpace;
829    SchPdschConfig pdschCfg;
830    uint8_t dmrsStartSymbol, startSymbol, numSymbol;
831
832    SCH_ALLOC(dlMsgAlloc->dlMsgPdcchCfg, sizeof(PdcchCfg));
833    if(!dlMsgAlloc->dlMsgPdcchCfg)
834    {
835       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schDlRsrcAllocDlMsg");
836       return RFAILED;
837    }
838    pdcch = dlMsgAlloc->dlMsgPdcchCfg;
839    bwp = &dlMsgAlloc->bwp;
840
841    GET_UE_ID(crnti, ueId);
842    ueCb  = cell->ueCb[ueId-1];
843    coreset1 = ueCb.ueCfg.spCellCfg.servCellRecfg.initDlBwp.pdcchCfg.cRSetToAddModList[0];
844    searchSpace = ueCb.ueCfg.spCellCfg.servCellRecfg.initDlBwp.pdcchCfg.searchSpcToAddModList[0];
845    pdschCfg = ueCb.ueCfg.spCellCfg.servCellRecfg.initDlBwp.pdschCfg;
846
847    /* fill BWP */
848    bwp->freqAlloc.numPrb = MAX_NUM_RB;
849    bwp->freqAlloc.startPrb = 0;
850    bwp->subcarrierSpacing = cell->sib1SchCfg.bwp.subcarrierSpacing;
851    bwp->cyclicPrefix = cell->sib1SchCfg.bwp.cyclicPrefix;
852
853    /* fill the PDCCH PDU */
854    /*StartSymbol of PDCCH*/
855    pdcchStartSymbol = findSsStartSymbol(searchSpace.mSymbolsWithinSlot);
856    if(pdcchStartSymbol < MAX_SYMB_PER_SLOT)
857       pdcch->coresetCfg.startSymbolIndex = pdcchStartSymbol;
858    else
859    {
860       DU_LOG("\nERROR  -->  SCH : Invalid SymbolIndex in schDlRsrcAllocDlMsg");
861       return RFAILED;
862    }
863    pdcch->coresetCfg.durationSymbols = coreset1.duration;
864    memcpy(pdcch->coresetCfg.freqDomainResource, coreset1.freqDomainRsrc, FREQ_DOM_RSRC_SIZE);
865    pdcch->coresetCfg.cceRegMappingType = coreset1.cceRegMappingType; /* non-interleaved */
866    pdcch->coresetCfg.regBundleSize = 6;   /* must be 6 for non-interleaved */
867    pdcch->coresetCfg.interleaverSize = 0; /* NA for non-interleaved */
868    pdcch->coresetCfg.coreSetType = 1; /* non PBCH coreset */
869
870    /*Size of coreset: Number of PRBs in a coreset*/
871    rbgCount = countRBGFrmCoresetFreqRsrc(coreset1.freqDomainRsrc);
872    if(rbgCount)
873    {
874       pdcch->coresetCfg.coreSetSize = ((rbgCount) * NUM_PRBS_PER_RBG);
875    }
876    else
877    {
878       DU_LOG("\nERROR  -->  SCH : CORESETSize is zero in schDlRsrcAllocDlMsg");
879       return RFAILED;
880    }
881
882    pdcch->coresetCfg.shiftIndex = cell->cellCfg.phyCellId;
883    pdcch->coresetCfg.precoderGranularity =  coreset1.precoderGranularity;
884    pdcch->numDlDci = 1;
885    pdcch->dci.rnti = ueCb.crnti;
886    pdcch->dci.scramblingId = cell->cellCfg.phyCellId;
887    pdcch->dci.scramblingRnti = 0;
888
889    /*TODO below assumptions of CCE Index is wrong:
890     * Range 0 to 135 as per ORAN.WG8.AAD Table 9-35 CORESET configuration and
891     * it has to be calculated using the formula given in 3GPP TS 38.213, Sec 10.1 */
892    pdcch->dci.cceIndex = 0; /* 0-3 for UL and 4-7 for DL */
893    pdcch->dci.aggregLevel = 4;
894    pdcch->dci.beamPdcchInfo.numPrgs = 1;
895    pdcch->dci.beamPdcchInfo.prgSize = 1;
896    pdcch->dci.beamPdcchInfo.digBfInterfaces = 0;
897    pdcch->dci.beamPdcchInfo.prg[0].pmIdx = 0;
898    pdcch->dci.beamPdcchInfo.prg[0].beamIdx[0] = 0;
899    pdcch->dci.txPdcchPower.beta_pdcch_1_0 = 0;
900    pdcch->dci.txPdcchPower.powerControlOffsetSS = 0;
901
902    pdsch = &pdcch->dci.pdschCfg;
903    pdsch->pduBitmap = 0; /* PTRS and CBG params are excluded */
904    pdsch->rnti = ueCb.crnti;
905    pdsch->pduIndex = 0;
906    pdsch->numCodewords = 1;
907    for(cwCount = 0; cwCount < pdsch->numCodewords; cwCount++)
908    {
909       pdsch->codeword[cwCount].targetCodeRate = 308;
910       pdsch->codeword[cwCount].qamModOrder = ueCb.ueCfg.dlModInfo.modOrder;
911       pdsch->codeword[cwCount].mcsIndex = ueCb.ueCfg.dlModInfo.mcsIndex;
912       pdsch->codeword[cwCount].mcsTable = ueCb.ueCfg.dlModInfo.mcsTable;
913       pdsch->codeword[cwCount].rvIndex = 0;
914
915       if (isRetx != TRUE)
916       {
917          tbSize +=TX_PAYLOAD_HDR_LEN;
918          hqP->tbInfo[cwCount].tbSzReq = tbSize;
919       }
920       pdsch->codeword[cwCount].tbSize = tbSize;
921    }
922    pdsch->dataScramblingId = cell->cellCfg.phyCellId;
923    pdsch->numLayers = 1;
924    pdsch->transmissionScheme = 0;
925    pdsch->refPoint = 0;
926    pdsch->dmrs.dlDmrsSymbPos = DL_DMRS_SYMBOL_POS; 
927    pdsch->dmrs.dmrsConfigType = 0; /* type-1 */
928    pdsch->dmrs.dlDmrsScramblingId = cell->cellCfg.phyCellId;
929    pdsch->dmrs.scid = 0;
930    pdsch->dmrs.numDmrsCdmGrpsNoData = 1;
931    pdsch->dmrs.dmrsPorts = 0;
932    pdsch->dmrs.mappingType      = DMRS_MAP_TYPE_A; /* Setting to Type-A */
933    pdsch->dmrs.nrOfDmrsSymbols  = NUM_DMRS_SYMBOLS;
934    pdsch->dmrs.dmrsAddPos       = pdschCfg.dmrsDlCfgForPdschMapTypeA.addPos;
935
936    pdsch->pdschTimeAlloc.startSymb = pdschStartSymbol; 
937    pdsch->pdschTimeAlloc.numSymb = pdschNumSymbols;
938
939    pdsch->pdschFreqAlloc.vrbPrbMapping = 0; /* non-interleaved */
940    pdsch->pdschFreqAlloc.resourceAllocType = 1; /* RAT type-1 RIV format */
941    pdsch->pdschFreqAlloc.startPrb = startPRB; /*Start PRB will be already known*/
942    pdsch->pdschFreqAlloc.numPrb = schCalcNumPrb(tbSize, ueCb.ueCfg.dlModInfo.mcsIndex, pdschNumSymbols);
943
944    /* Find total symbols occupied including DMRS */
945    dmrsStartSymbol = findDmrsStartSymbol(pdsch->dmrs.dlDmrsSymbPos);
946    /* If there are no DRMS symbols, findDmrsStartSymbol() returns MAX_SYMB_PER_SLOT,
947     * in that case only PDSCH symbols are marked as occupied */
948    if(dmrsStartSymbol == MAX_SYMB_PER_SLOT)
949    {
950       startSymbol = pdsch->pdschTimeAlloc.startSymb;
951       numSymbol = pdsch->pdschTimeAlloc.numSymb;
952    }
953    /* If DMRS symbol is found, mark DMRS and PDSCH symbols as occupied */
954    else
955    {
956       startSymbol = dmrsStartSymbol;
957       numSymbol = pdsch->dmrs.nrOfDmrsSymbols + pdsch->pdschTimeAlloc.numSymb;
958    }
959
960    /* Allocate the number of PRBs required for DL PDSCH */
961    if((allocatePrbDl(cell, slotTime, startSymbol, numSymbol,\
962       &pdsch->pdschFreqAlloc.startPrb, pdsch->pdschFreqAlloc.numPrb)) != ROK)
963    {
964       DU_LOG("\nERROR  --> SCH : allocatePrbDl() failed for DL MSG");
965       SCH_FREE(dlMsgAlloc->dlMsgPdcchCfg, sizeof(PdcchCfg));
966       return RFAILED;
967    }
968
969    pdsch->beamPdschInfo.numPrgs = 1;
970    pdsch->beamPdschInfo.prgSize = 1;
971    pdsch->beamPdschInfo.digBfInterfaces = 0;
972    pdsch->beamPdschInfo.prg[0].pmIdx = 0;
973    pdsch->beamPdschInfo.prg[0].beamIdx[0] = 0;
974    pdsch->txPdschPower.powerControlOffset = 0;
975    pdsch->txPdschPower.powerControlOffsetSS = 0;
976
977    return ROK;
978 }
979
980 /*******************************************************************
981  *
982  * @brief Fills k0 and k1 information table for FDD 
983  *
984  * @details
985  *
986  *    Function : BuildK0K1TableForFdd 
987  *
988  *    Functionality:
989  *      Fills k0 and k1 information table for FDD
990  *
991  * @params[in] SchCellCb *cell,SchK0K1TimingInfoTbl *k0K1InfoTbl,bool
992  * pdschCfgCmnPres,uint8_t numTimeDomAlloc, SchPdschCfgCmnTimeDomRsrcAlloc
993  * cmnTimeDomRsrcAllocList[], SchPdschTimeDomRsrcAlloc
994  * dedTimeDomRsrcAllocList[], uint8_t ulAckListCount, uint8_t *UlAckTbl
995  * @return ROK     - success
996  *         RFAILED - failure
997  *
998  * ****************************************************************/
999 void BuildK0K1TableForFdd(SchCellCb *cell, SchK0K1TimingInfoTbl *k0K1InfoTbl, bool pdschCfgCmnPres,SchPdschCfgCmn pdschCmnCfg,\
1000 SchPdschConfig pdschDedCfg, uint8_t ulAckListCount, uint8_t *UlAckTbl)
1001 {
1002    
1003    uint8_t k1TmpVal =0, cfgIdx=0;
1004    uint8_t slotIdx=0, k0Index=0, k1Index=0, numK0=0, numK1=0, numTimeDomAlloc=0;
1005    
1006    /* TODO Commented these below lines for resolving warnings. Presently these variable are not 
1007     * required but this will require for harq processing */
1008    // uint8_t k0TmpVal = 0; 
1009    // SchPdschCfgCmnTimeDomRsrcAlloc cmnTimeDomRsrcAllocList[MAX_NUM_DL_ALLOC];
1010    // SchPdschTimeDomRsrcAlloc dedTimeDomRsrcAllocList[MAX_NUM_DL_ALLOC];
1011
1012    /* Initialization the structure and storing the total slot values. */
1013    memset(k0K1InfoTbl, 0, sizeof(SchK0K1TimingInfoTbl));
1014    k0K1InfoTbl->tblSize = cell->numSlots;
1015    
1016    /* Storing time domain resource allocation list based on common or dedicated configuration. */
1017    if(pdschCfgCmnPres == true)
1018    {
1019       numTimeDomAlloc = pdschCmnCfg.numTimeDomAlloc;
1020       for(cfgIdx = 0; cfgIdx<numTimeDomAlloc; cfgIdx++)
1021       {
1022          /*TODO uncomment this line during harq processing */
1023          //cmnTimeDomRsrcAllocList[cfgIdx] = pdschCmnCfg.timeDomRsrcAllocList[cfgIdx];
1024       }
1025    }
1026    else
1027    {
1028       numTimeDomAlloc = pdschDedCfg.numTimeDomRsrcAlloc;
1029       for(cfgIdx = 0; cfgIdx<numTimeDomAlloc; cfgIdx++)
1030       {
1031          /*TODO uncomment this line during harq processing */
1032          //dedTimeDomRsrcAllocList[cfgIdx] = pdschDedCfg.timeDomRsrcAllociList[cfgIdx];
1033       }
1034    }
1035    
1036    /* Checking all the slots for K0 and K1 values. */
1037    for(slotIdx = 0; slotIdx < cell->numSlots; slotIdx++)
1038    {
1039       numK0 = 0;
1040       /* Storing the values of k0 based on time domain resource
1041        * allocation list. If the value is unavailable then fill default values,
1042        * As per 38.331 PDSCH-TimeDomainResourceAllocation field descriptions. */
1043       for(k0Index = 0; ((k0Index < numTimeDomAlloc) && (k0Index < MAX_NUM_K0_IDX));  k0Index++)
1044       {
1045          /* TODO These if 0 we will remove during harq processing */
1046 #if 0
1047          if(pdschCfgCmnPres == true)
1048          {
1049             k0TmpVal = cmnTimeDomRsrcAllocList[k0Index].k0;
1050          }
1051          else
1052          {
1053             if(dedTimeDomRsrcAllocList[k0Index].k0 != NULLP)
1054             {
1055                k0TmpVal = *(dedTimeDomRsrcAllocList[k0Index].k0);
1056             }
1057             else
1058             { 
1059                k0TmpVal = DEFAULT_K0_VALUE;
1060             }
1061          }
1062 #endif         
1063          /* Checking all the Ul Alloc values. If value is less than MIN_NUM_K1_IDX
1064           * then skip else continue storing the values. */
1065          numK1 = 0;
1066          for(k1Index = 0; k1Index < ulAckListCount; k1Index++)
1067          {
1068             k1TmpVal = UlAckTbl[k1Index];
1069             if(k1TmpVal <= MIN_NUM_K1_IDX)
1070             {
1071                continue;
1072             }
1073
1074             k0K1InfoTbl->k0k1TimingInfo[slotIdx].k0Indexes[numK0].k1TimingInfo.k1Indexes[numK1++] = k1Index;
1075             /* TODO Store K1 index where harq feedback will be received in harq table. */ 
1076          }
1077          if(numK1)
1078          {
1079             k0K1InfoTbl->k0k1TimingInfo[slotIdx].k0Indexes[numK0].k1TimingInfo.numK1 = numK1;
1080             k0K1InfoTbl->k0k1TimingInfo[slotIdx].k0Indexes[numK0].k0Index = k0Index;
1081             numK0++;
1082          }
1083       }
1084       if(numK0)
1085       {
1086          k0K1InfoTbl->k0k1TimingInfo[slotIdx].numK0 = numK0;
1087       }
1088    }
1089 }
1090
1091 /*******************************************************************
1092  *
1093  * @brief Fills k0 and k1 information table  
1094  *
1095  * @details
1096  *
1097  *    Function : BuildK0K1Table
1098  *
1099  *    Functionality:
1100  *       Fills K0 and k1 information table 
1101  *
1102  * @params[in] SchCellCb *cell,SchK0K1TimingInfoTbl *k0K1InfoTbl,bool
1103  * pdschCfgCmnPres,uint8_t numTimeDomAlloc, SchPdschCfgCmnTimeDomRsrcAlloc
1104  * cmnTimeDomRsrcAllocList[], SchPdschTimeDomRsrcAlloc
1105  * dedTimeDomRsrcAllocList[], uint8_t ulAckListCount, uint8_t *UlAckTbl
1106  * @return ROK     - success
1107  *         RFAILED - failure
1108  *
1109  * ****************************************************************/
1110 void BuildK0K1Table(SchCellCb *cell, SchK0K1TimingInfoTbl *k0K1InfoTbl, bool pdschCfgCmnPres, SchPdschCfgCmn pdschCmnCfg,\
1111 SchPdschConfig pdschDedCfg, uint8_t ulAckListCount, uint8_t *UlAckTbl)
1112 {
1113
1114 #ifdef NR_TDD
1115    SlotConfig  slotCfg;
1116    bool ulSlotPresent = false;
1117    uint8_t k0TmpVal = 0, k1TmpVal =0, tmpSlot=0, startSymbol=0, endSymbol=0, checkSymbol=0;
1118    uint8_t slotIdx=0, k0Index=0, k1Index=0, numK0=0, numK1=0, cfgIdx=0, numTimeDomAlloc =0, totalCfgSlot =0;
1119    SchPdschCfgCmnTimeDomRsrcAlloc cmnTimeDomRsrcAllocList[MAX_NUM_DL_ALLOC];
1120    SchPdschTimeDomRsrcAlloc dedTimeDomRsrcAllocList[MAX_NUM_DL_ALLOC];
1121 #endif
1122
1123    if(cell->cellCfg.dupMode == DUPLEX_MODE_FDD)
1124    {
1125       BuildK0K1TableForFdd(cell, k0K1InfoTbl, pdschCfgCmnPres, pdschCmnCfg, pdschDedCfg, ulAckListCount, UlAckTbl);
1126    }
1127    else
1128    {
1129 #ifdef NR_TDD
1130       
1131       /* Initialization the K0K1 structure, total num of slot and calculating the slot pattern length. */
1132       memset(k0K1InfoTbl, 0, sizeof(SchK0K1TimingInfoTbl));
1133       k0K1InfoTbl->tblSize = cell->numSlots;
1134       totalCfgSlot = calculateSlotPatternLength(cell->cellCfg.ssbScs, cell->cellCfg.tddCfg.tddPeriod);
1135       
1136       /* Storing time domain resource allocation list based on common or 
1137        * dedicated configuration availability. */
1138       if(pdschCfgCmnPres == true)
1139       {
1140          numTimeDomAlloc = pdschCmnCfg.numTimeDomAlloc;
1141          for(cfgIdx = 0; cfgIdx<numTimeDomAlloc; cfgIdx++)
1142          {
1143             cmnTimeDomRsrcAllocList[cfgIdx] = pdschCmnCfg.timeDomRsrcAllocList[cfgIdx];
1144          }
1145       }
1146       else
1147       {
1148          numTimeDomAlloc = pdschDedCfg.numTimeDomRsrcAlloc;
1149          for(cfgIdx = 0; cfgIdx<numTimeDomAlloc; cfgIdx++)
1150          {
1151             dedTimeDomRsrcAllocList[cfgIdx] = pdschDedCfg.timeDomRsrcAllociList[cfgIdx];
1152          }
1153       }
1154
1155       /* Checking all possible indexes for K0 and K1 values. */
1156       for(slotIdx = 0; slotIdx < cell->numSlots; slotIdx++)
1157       {
1158          /* If current slot is UL or FLEXI then Skip because PDCCH is sent only in DL slots. */
1159          slotCfg = schGetSlotSymbFrmt(slotIdx%totalCfgSlot, cell->slotFrmtBitMap);
1160          if(slotCfg == UL_SLOT || slotCfg == FLEXI_SLOT)
1161          {
1162             continue;
1163          }
1164         
1165          ulSlotPresent = false;
1166          /* Storing K0 , start symbol and length symbol for further processing.
1167           * If K0 value is not available then we can fill the default values
1168           * given in spec 38.331. */
1169          numK0 = 0;
1170          for(k0Index = 0; ((k0Index < numTimeDomAlloc) && (k0Index < MAX_NUM_K0_IDX)); k0Index++)
1171          {
1172             if(pdschCfgCmnPres == true)
1173             {
1174                k0TmpVal = cmnTimeDomRsrcAllocList[k0Index].k0;
1175                startSymbol = cmnTimeDomRsrcAllocList[k0Index].startSymbol;
1176                endSymbol = startSymbol + cmnTimeDomRsrcAllocList[k0Index].lengthSymbol;
1177             }
1178             else
1179             {
1180                if(dedTimeDomRsrcAllocList[k0Index].k0 != NULLP)
1181                {
1182                   k0TmpVal =  *(dedTimeDomRsrcAllocList[k0Index].k0);
1183                }
1184                else
1185                {
1186                   k0TmpVal = DEFAULT_K0_VALUE;
1187                }
1188                startSymbol = dedTimeDomRsrcAllocList[k0Index].startSymbol;
1189                endSymbol = startSymbol + dedTimeDomRsrcAllocList[k0Index].symbolLength;
1190             }
1191             
1192             /* If current slot + k0 is UL then skip the slot
1193              * else if it is DL slot then continue the next steps
1194              * else if it is a FLEXI slot then check symbols of slot, It should not
1195              * contain any UL slot. */
1196             tmpSlot = (slotIdx+k0TmpVal) % totalCfgSlot;
1197             slotCfg = schGetSlotSymbFrmt(tmpSlot, cell->slotFrmtBitMap);
1198             if(slotCfg == UL_SLOT)
1199             {
1200                continue;
1201             }
1202             if(slotCfg == FLEXI_SLOT)
1203             {
1204                for(checkSymbol = startSymbol; checkSymbol<endSymbol; checkSymbol ++)
1205                {
1206                   slotCfg = cell->slotCfg[tmpSlot][checkSymbol];
1207                   if(slotCfg == UL_SLOT)
1208                   {
1209                      ulSlotPresent = true;
1210                      break;
1211                   }
1212                }
1213                if(ulSlotPresent == true)
1214                {
1215                   continue;
1216                }
1217             }
1218
1219              ulSlotPresent = false; //Re-initializing
1220
1221             /* If current slot + k0 + k1 is a DL slot then skip the slot
1222              * else if it is UL slot then store the information 
1223              * else if it is FLEXI slot then check the symbols, it must have
1224              * at least one UL symbol. */
1225             numK1 = 0;
1226             for(k1Index = 0; k1Index < ulAckListCount; k1Index++)
1227             {
1228                k1TmpVal = UlAckTbl[k1Index];
1229                if(k1TmpVal > MIN_NUM_K1_IDX)
1230                {
1231                   tmpSlot = (slotIdx+k0TmpVal+k1TmpVal) % totalCfgSlot;
1232                   slotCfg =  schGetSlotSymbFrmt(tmpSlot, cell->slotFrmtBitMap);
1233                   if(slotCfg == DL_SLOT) 
1234                   {
1235                      continue;
1236                   }   
1237                   if(slotCfg == FLEXI_SLOT)
1238                   {
1239                      for(checkSymbol = 0; checkSymbol< MAX_SYMB_PER_SLOT;checkSymbol++)
1240                      {
1241                         if(cell->slotCfg[tmpSlot][checkSymbol] == UL_SYMBOL)
1242                         {
1243                            ulSlotPresent = true;
1244                            break;
1245                         }
1246                      }
1247                   }
1248                   if(ulSlotPresent == true || slotCfg ==  UL_SLOT)
1249                   {
1250                      k0K1InfoTbl->k0k1TimingInfo[slotIdx].k0Indexes[numK0].k1TimingInfo.k1Indexes[numK1++] = k1Index;
1251                      /* TODO Store K1 index where harq feedback will be received
1252                       * in harq table. */
1253                   }
1254                }
1255             }
1256             
1257             /* Store all the values if all condition satisfies. */
1258             if(numK1)
1259             {
1260                k0K1InfoTbl->k0k1TimingInfo[slotIdx].k0Indexes[numK0].k1TimingInfo.numK1 = numK1;
1261                k0K1InfoTbl->k0k1TimingInfo[slotIdx].k0Indexes[numK0].k0Index = k0Index;
1262                numK0++;
1263             }
1264          }
1265          if(numK0)
1266          {
1267             k0K1InfoTbl->k0k1TimingInfo[slotIdx].numK0 = numK0;
1268          }
1269       }
1270 #endif
1271    }
1272 }
1273
1274 /*******************************************************************
1275 *
1276 * @brief Fills K2 information table for FDD
1277 *
1278 * @details
1279 *
1280 *    Function : BuildK2InfoTableForFdd 
1281 *
1282 *    Functionality:
1283 *       Fills K2 information table for FDD
1284 *
1285 * @params[in] SchCellCb *cell,SchPuschTimeDomRsrcAlloc timeDomRsrcAllocList[],
1286 * uint16_t puschSymTblSize,SchK2TimingInfoTbl *k2InfoTbl
1287 * @return ROK     - success
1288 *         RFAILED - failure
1289 *
1290 * ****************************************************************/
1291 void BuildK2InfoTableForFdd(SchCellCb *cell, SchPuschTimeDomRsrcAlloc timeDomRsrcAllocList[], uint16_t puschSymTblSize,\
1292 SchK2TimingInfoTbl *msg3K2InfoTbl, SchK2TimingInfoTbl *k2InfoTbl)
1293 {
1294    uint16_t slotIdx=0, k2Index=0, k2TmpIdx=0, msg3K2TmpIdx=0;
1295
1296    /* Initialization the structure and storing the total slot values. */
1297    memset(k2InfoTbl, 0, sizeof(SchK2TimingInfoTbl));
1298    k2InfoTbl->tblSize = cell->numSlots;
1299    if(msg3K2InfoTbl)
1300       msg3K2InfoTbl->tblSize = cell->numSlots;
1301    
1302    /* Checking all possible indexes for K2. */
1303    for(slotIdx = 0; slotIdx < cell->numSlots; slotIdx++)
1304    {
1305       /* Storing K2 values. */
1306       for(k2Index = 0; ((k2Index < puschSymTblSize) && (k2Index < MAX_NUM_K2_IDX)); k2Index++)
1307       {
1308          k2TmpIdx= k2InfoTbl->k2TimingInfo[slotIdx].numK2;
1309          k2InfoTbl->k2TimingInfo[slotIdx].k2Indexes[k2TmpIdx] = k2Index;
1310          k2InfoTbl->k2TimingInfo[slotIdx].numK2++;
1311
1312          /* Updating K2 values for MSG3 */
1313          if(msg3K2InfoTbl)
1314          {
1315             msg3K2TmpIdx = msg3K2InfoTbl->k2TimingInfo[slotIdx].numK2;
1316             msg3K2InfoTbl->k2TimingInfo[slotIdx].k2Indexes[msg3K2TmpIdx] = k2Index;
1317             msg3K2InfoTbl->k2TimingInfo[slotIdx].numK2++;
1318          }
1319       }
1320    }
1321 }
1322
1323 /*******************************************************************
1324  *
1325  * @brief Fills K2 information table
1326  *
1327  * @details
1328  *
1329  *    Function : BuildK2InfoTable 
1330  *
1331  *    Functionality:
1332  *       Fills K2 information table
1333  *
1334  * @params[in] SchCellCb *cell,SchPuschTimeDomRsrcAlloc timeDomRsrcAllocList[],
1335  * uint16_t puschSymTblSize, SchK2TimingInfoTbl *k2InfoTbl
1336  * @return ROK     - success
1337  *         RFAILED - failure
1338  *
1339  * ****************************************************************/
1340 void BuildK2InfoTable(SchCellCb *cell, SchPuschTimeDomRsrcAlloc timeDomRsrcAllocList[], uint16_t puschSymTblSize,\
1341 SchK2TimingInfoTbl *msg3K2InfoTbl, SchK2TimingInfoTbl *k2InfoTbl)
1342 {
1343
1344 #ifdef NR_TDD
1345    bool dlSymbolPresent = false;
1346    uint8_t slotIdx=0, k2Index=0, k2Val=0, k2TmpVal=0, msg3K2TmpVal=0, msg3Delta=0, numK2 =0, currentSymbol =0;
1347    uint8_t startSymbol =0, endSymbol =0, checkSymbol=0, totalCfgSlot=0, slotCfg=0;
1348    SlotConfig currentSlot;
1349 #endif
1350
1351    if(cell->cellCfg.dupMode == DUPLEX_MODE_FDD)
1352    {
1353       BuildK2InfoTableForFdd(cell, timeDomRsrcAllocList, puschSymTblSize, msg3K2InfoTbl, k2InfoTbl);
1354    }
1355    else
1356    {
1357 #ifdef NR_TDD
1358
1359       /* Initialization the structure and storing the total slot values. */
1360       memset(k2InfoTbl, 0, sizeof(SchK2TimingInfoTbl));
1361       k2InfoTbl->tblSize = cell->numSlots;
1362       if(msg3K2InfoTbl)
1363          msg3K2InfoTbl->tblSize = cell->numSlots;
1364       totalCfgSlot = calculateSlotPatternLength(cell->cellCfg.ssbScs, cell->cellCfg.tddCfg.tddPeriod);
1365
1366       /* Checking all possible indexes for K2. */
1367       for(slotIdx = 0; slotIdx < cell->numSlots; slotIdx++)
1368       {
1369          currentSlot = schGetSlotSymbFrmt(slotIdx % totalCfgSlot, cell->slotFrmtBitMap);
1370          
1371          /* If current slot is UL then skip because PDCCH is sent only in DL slots */
1372          if(currentSlot != UL_SLOT)
1373          {
1374             for(k2Index = 0; ((k2Index < puschSymTblSize) && (k2Index < MAX_NUM_K2_IDX)); k2Index++)
1375             {
1376                /* Storing k2, startSymbol, endSymbol information for further processing.
1377                 * If k2 is absent then fill the default values given in spec 38.331
1378                 * PUSCH-TimeDomainResourceAllocationList field descriptions */
1379                k2Val = timeDomRsrcAllocList[k2Index].k2;
1380                if(!k2Val)
1381                {
1382                   switch(cell->cellCfg.ssbScs)
1383                   {
1384                      case SCS_15KHZ:
1385                         k2Val = DEFAULT_K2_VALUE_FOR_SCS15;
1386                         break;
1387                      case SCS_30KHZ:
1388                         k2Val = DEFAULT_K2_VALUE_FOR_SCS30;
1389                         break;
1390                      case SCS_60KHZ:
1391                         k2Val = DEFAULT_K2_VALUE_FOR_SCS60;
1392                         break;
1393                      case SCS_120KHZ:
1394                         k2Val = DEFAULT_K2_VALUE_FOR_SCS120;
1395                         break;
1396                   }
1397                }
1398                
1399                /* Current slot + k2 should be either UL or FLEXI slot.
1400                 * If slot is FLEXI then check all the symbols of that slot,
1401                 * it should not contain any DL or FLEXI slot */
1402                k2TmpVal = (slotIdx + k2Val) % totalCfgSlot;
1403                slotCfg = schGetSlotSymbFrmt(k2TmpVal, cell->slotFrmtBitMap);
1404                if(slotCfg != DL_SLOT)
1405                {
1406                   if(slotCfg == FLEXI_SLOT)
1407                   {
1408                      startSymbol =  timeDomRsrcAllocList[k2Index].startSymbol;
1409                      endSymbol   =  startSymbol+ timeDomRsrcAllocList[k2Index].symbolLength;
1410                      dlSymbolPresent = false;
1411                      for(checkSymbol= startSymbol; checkSymbol<endSymbol; checkSymbol++)
1412                      {
1413                         currentSymbol = cell->slotCfg[k2TmpVal][checkSymbol];
1414                         if(currentSymbol == DL_SLOT || currentSymbol == FLEXI_SLOT)
1415                         {
1416                            dlSymbolPresent = true;
1417                            break;
1418                         }
1419                      }
1420                   }
1421                   /* Store all the values if all condition satisfies. */
1422                   if(dlSymbolPresent != true || slotCfg == UL_SLOT)
1423                   {
1424                      numK2 = k2InfoTbl->k2TimingInfo[slotIdx].numK2;
1425                      k2InfoTbl->k2TimingInfo[slotIdx].k2Indexes[numK2] = k2Index;
1426                      k2InfoTbl->k2TimingInfo[slotIdx].numK2++;
1427                   }
1428                }
1429
1430                if(msg3K2InfoTbl)
1431                {
1432                    msg3Delta = puschDeltaTable[cell->numerology];
1433
1434                   /* Check for K2 for MSG3 */
1435                   /* Current slot + k2 should be either UL or FLEXI slot.
1436                    * If slot is FLEXI then check all the symbols of that slot,
1437                    * it should not contain any DL or FLEXI slot */
1438                   msg3K2TmpVal = (slotIdx + k2Val + msg3Delta) % totalCfgSlot;
1439                   slotCfg = schGetSlotSymbFrmt(msg3K2TmpVal, cell->slotFrmtBitMap);
1440                   if(slotCfg != DL_SLOT)
1441                   {
1442                      if(slotCfg == FLEXI_SLOT)
1443                      {
1444                         startSymbol =  timeDomRsrcAllocList[k2Index].startSymbol;
1445                         endSymbol   =  startSymbol+ timeDomRsrcAllocList[k2Index].symbolLength;
1446                         dlSymbolPresent = false;
1447                         for(checkSymbol= startSymbol; checkSymbol<endSymbol; checkSymbol++)
1448                         {
1449                            currentSymbol = cell->slotCfg[msg3K2TmpVal][checkSymbol];
1450                            if(currentSymbol == DL_SLOT || currentSymbol == FLEXI_SLOT)
1451                            {
1452                               dlSymbolPresent = true;
1453                               break;
1454                            }
1455                         }
1456                      }
1457                      /* Store all the values if all condition satisfies. */
1458                      if(dlSymbolPresent != true || slotCfg == UL_SLOT)
1459                      {
1460                         numK2 = msg3K2InfoTbl->k2TimingInfo[slotIdx].numK2;
1461                         msg3K2InfoTbl->k2TimingInfo[slotIdx].k2Indexes[numK2] = k2Index;
1462                         msg3K2InfoTbl->k2TimingInfo[slotIdx].numK2++;
1463                      }
1464                   }
1465                }
1466             }
1467          }
1468       }
1469 #endif
1470    }
1471 }
1472
1473 /*******************************************************************************************
1474  *
1475  * @brief Allocate the PRB using RRM policy
1476  *
1477  * @details
1478  *
1479  *    Function : prbAllocUsingRRMPolicy
1480  *
1481  *    Functionality:
1482  *      [Step1]: Traverse each Node in the LC list
1483  *      [Step2]: Check whether the LC has ZERO requirement then clean this LC
1484  *      [Step3]: Calcualte the maxPRB for this LC.
1485  *              a. For Dedicated LC, maxPRB = sum of remainingReservedPRB and
1486  *              sharedPRB
1487  *              b. For Default, just SharedPRB count
1488  *      [Step4]: If the LC is the First one to be allocated for this UE then add
1489  *      TX_PAYLODN_LEN to reqBO 
1490  *      [Step5]: Calculate the estimate PRB and estimate BO to be allocated
1491  *               based on reqBO and maxPRB left.
1492  *      [Step6]: Based on calculated PRB, Update Reserved PRB and Shared PRB counts
1493  *      [Step7]: Deduce the reqBO based on allocBO and move the LC node to last.
1494  *      [Step8]: Continue the next loop from List->head
1495  *
1496  *      [Loop Exit]:
1497  *        [Exit1]: If all the LCs are allocated in list
1498  *        [Exit2]: If PRBs are exhausted
1499  *
1500  * @params[in] I/P > lcLinkList pointer (LcInfo list)
1501  *             I/P > IsDedicatedPRB (Flag to indicate that RESERVED PRB to use 
1502  *             I/P > mcsIdx and PDSCH symbols count 
1503  *             I/P & O/P > Shared PRB , reserved PRB Count
1504  *             I/P & O/P > Total TBS size accumulated
1505  *             I/P & O/P > isTxPayloadLenAdded[For DL] : Decision flag to add the TX_PAYLOAD_HDR_LEN
1506  *             I/P & O/P > srRcvd Flag[For UL] : Decision flag to add UL_GRANT_SIZE
1507  *
1508  * @return void
1509  *
1510  * *******************************************************************************************/
1511 void prbAllocUsingRRMPolicy(CmLListCp *lcLL, bool isDedicatedPRB, uint16_t mcsIdx,uint8_t numSymbols,\
1512                   uint16_t *sharedPRB, uint16_t *reservedPRB, bool *isTxPayloadLenAdded, bool *srRcvd)
1513 {
1514    CmLList *node = NULLP;
1515    LcInfo *lcNode = NULLP;
1516    uint16_t remReservedPRB = 0, estPrb = 0, maxPRB = 0;
1517
1518    if(lcLL == NULLP)
1519    {
1520       DU_LOG("\nERROR --> SCH: LcList not present");
1521       return;
1522    }
1523    node = lcLL->first;
1524
1525    /*Only for Dedicated LcList, Valid value will be assigned to remReservedPRB
1526     * For Other LcList, remReservedPRB = 0*/
1527    if(reservedPRB != NULLP && isDedicatedPRB == TRUE)
1528    {
1529       remReservedPRB = *reservedPRB;
1530    }
1531
1532    /*[Step1]*/
1533    while(node)
1534    {
1535 #if 0
1536       /*For Debugging purpose*/
1537       printLcLL(lcLL);
1538 #endif
1539       lcNode = (LcInfo *)node->node;
1540
1541       /* [Step2]: Below condition will hit in rare case as it has been taken care during the cleaning 
1542        * process of LCID which was fully allocated. Check is just for safety purpose*/
1543       if(lcNode->reqBO == 0 && lcNode->allocBO == 0)
1544       {
1545          DU_LOG("\nERROR --> SCH: LCID:%d has no requirement, clearing this node",\
1546                lcNode->lcId);
1547          deleteNodeFromLList(lcLL, node);
1548          SCH_FREE(lcNode, sizeof(LcInfo));
1549          node = lcLL->first; 
1550          continue;
1551       }
1552
1553       /*[Exit1]: All LCs are allocated(allocBO = 0 for fully unallocated LC)*/
1554       if(lcNode->allocBO != 0)
1555       {
1556          DU_LOG("\nDEBUG  -->  SCH: All LC are allocated [SharedPRB:%d]",*sharedPRB);
1557          return;
1558       }
1559
1560       /*[Exit2]: If PRBs are exhausted*/
1561       if(isDedicatedPRB)
1562       {
1563          /*Loop Exit: All resources exhausted*/
1564          if(remReservedPRB == 0 && *sharedPRB == 0)
1565          {
1566             DU_LOG("\nDEBUG  -->  SCH: Dedicated resources exhausted for LC:%d",lcNode->lcId);
1567             return;
1568          }
1569       }
1570       else
1571       {
1572          /*Loop Exit: All resources exhausted*/
1573          if(*sharedPRB == 0)
1574          {
1575             DU_LOG("\nDEBUG  -->  SCH: Default resources exhausted for LC:%d",lcNode->lcId);
1576             return;
1577          }
1578       }
1579
1580       /*[Step3]*/
1581       maxPRB = remReservedPRB + *sharedPRB;
1582
1583       /*[Step4]*/
1584       if((isTxPayloadLenAdded != NULLP) && (*isTxPayloadLenAdded == FALSE))
1585       {
1586          DU_LOG("\nDEBUG  -->  SCH: LC:%d is the First node to be allocated which includes TX_PAYLOAD_HDR_LEN",\
1587                lcNode->lcId);
1588          *isTxPayloadLenAdded = TRUE;
1589          lcNode->allocBO = calculateEstimateTBSize((lcNode->reqBO + TX_PAYLOAD_HDR_LEN),\
1590                mcsIdx, numSymbols, maxPRB, &estPrb);
1591          lcNode->allocBO -=TX_PAYLOAD_HDR_LEN;
1592       }
1593       else if((srRcvd != NULLP) && (*srRcvd == TRUE))
1594       {
1595          DU_LOG("\nDEBUG  --> SCH: LC:%d is the First node to be allocated which includes UL_GRANT_SIZE",\
1596                lcNode->lcId);
1597          *srRcvd = FALSE;
1598          lcNode->reqBO += UL_GRANT_SIZE;
1599          lcNode->allocBO = calculateEstimateTBSize(lcNode->reqBO, mcsIdx, numSymbols, maxPRB, &estPrb);
1600       }
1601       else
1602       {
1603          /*[Step4]*/
1604          lcNode->allocBO = calculateEstimateTBSize(lcNode->reqBO,\
1605                mcsIdx, numSymbols, maxPRB, &estPrb);
1606       }
1607
1608       /*[Step6]:Re-adjust the reservedPRB pool count and *SharedPRB Count based on
1609        * estimated PRB allocated*/
1610       if((isDedicatedPRB == TRUE) && (estPrb <= remReservedPRB))
1611       {
1612          remReservedPRB = remReservedPRB - estPrb;
1613       }
1614       else   /*LC requirement need PRB share from SharedPRB*/
1615       {
1616          if(*sharedPRB <=  (estPrb - remReservedPRB))
1617          {
1618             DU_LOG("\nDEBUG  -->  SCH: SharedPRB is less");
1619             *sharedPRB = 0;
1620          }
1621          else
1622          {
1623             *sharedPRB = *sharedPRB - (estPrb - remReservedPRB);
1624          }
1625          remReservedPRB = 0;
1626       }
1627
1628       /*[Step7]*/
1629       lcNode->reqBO -= lcNode->allocBO;  /*Update the reqBO with remaining bytes unallocated*/
1630       lcNode->allocPRB = estPrb;
1631       cmLListAdd2Tail(lcLL, cmLListDelFrm(lcLL, node));
1632
1633       /*[Step8]:Next loop: First LC to be picked from the list
1634        * because Allocated Nodes are moved to the last*/
1635       node = lcLL->first; 
1636
1637    }
1638    return;
1639 }
1640
1641 /*******************************************************************************************
1642  *
1643  * @brief Check the LC List and fill the LC and GrantSize to be sent to MAC as
1644  * BO Report
1645  *
1646  * @details
1647  *
1648  *    Function : updateGrantSizeForBoRpt
1649  *
1650  *    Functionality:
1651  *             Check the LC List and fill the LC and GrantSize to be sent to MAC as
1652  *             BO Report in dlMsgAlloc Pointer
1653  *
1654  * @params[in] I/P > lcLinkList pointer (LcInfo list)
1655  *             I/P & O/P > dlMsgAlloc[for DL](Pending LC to be added in this context) 
1656  *             I/P & O/P > BsrInfo (applicable for UL)
1657  *             I/P & O/P > accumalatedBOSize
1658  * @return void
1659  *
1660  * *******************************************************************************************/
1661 void updateGrantSizeForBoRpt(CmLListCp *lcLL, DlMsgSchInfo *dlMsgAlloc,\
1662                                 BsrInfo *bsrInfo, uint32_t *accumalatedBOSize)
1663 {
1664    CmLList *node = NULLP, *next = NULLP;
1665    LcInfo *lcNode = NULLP;
1666
1667    if(lcLL == NULLP)
1668    {
1669       DU_LOG("\nERROR --> SCH: LcList not present");
1670       return;
1671    }
1672
1673    if(lcLL->count)
1674    {
1675       node = lcLL->first;
1676    }
1677    else
1678    {
1679       /*lcLL is empty*/
1680       return;
1681    }
1682
1683    /*Traverse List*/
1684    while(node)
1685    {
1686       next = node->next;
1687       lcNode = (LcInfo *)node->node;
1688       if(lcNode != NULLP)
1689       {
1690          DU_LOG("\nINFO   -->  SCH : LcID:%d, [reqBO, allocBO, allocPRB]:[%d,%d,%d]",\
1691                lcNode->lcId, lcNode->reqBO, lcNode->allocBO, lcNode->allocPRB);
1692          if(dlMsgAlloc != NULLP)
1693          {
1694
1695             /*Add this LC to dlMsgAlloc so that if this LC gets allocated, BO
1696              * report for allocation can be sent to MAC*/
1697             dlMsgAlloc->numOfTbs = 1;
1698             dlMsgAlloc->transportBlock[0].lcSchInfo[dlMsgAlloc->transportBlock[0].numLc].lcId = lcNode->lcId;
1699             dlMsgAlloc->transportBlock[0].lcSchInfo[dlMsgAlloc->transportBlock[0].numLc].schBytes = lcNode->allocBO;
1700
1701             /*Calculate the Total Payload/BO size allocated*/
1702             *accumalatedBOSize += dlMsgAlloc->transportBlock[0].lcSchInfo[dlMsgAlloc->transportBlock[0].numLc].schBytes; 
1703
1704             DU_LOG("\nINFO   -->  SCH: Added in MAC BO report: LCID:%d,reqBO:%d,Idx:%d, TotalBO Size:%d",\
1705                   lcNode->lcId,lcNode->reqBO, dlMsgAlloc->transportBlock[0].numLc, *accumalatedBOSize);
1706
1707             dlMsgAlloc->transportBlock[0].numLc++;
1708             handleLcLList(lcLL, lcNode->lcId, DELETE);
1709          }
1710          else if(bsrInfo != NULLP)
1711          {
1712             *accumalatedBOSize += lcNode->allocBO;   
1713             DU_LOG("\nINFO   --> SCH: UL : LCID:%d,reqBO:%d, TotalBO Size:%d",\
1714                   lcNode->lcId,lcNode->reqBO, *accumalatedBOSize);
1715          }
1716       }
1717       node = next;
1718    }/*End of while*/
1719    return;
1720 }
1721
1722 /*******************************************************************
1723 *
1724 * @brief fill DL message information for MSG4 and Dedicated DL Msg
1725 *
1726 * @details
1727 *
1728 *    Function : fillDlMsgInfo
1729 *
1730 *    Functionality:
1731 *       fill DL message information for MSG4 and Dedicated DL Msg
1732 *
1733 * @params[in] DlMsgInfo *dlMsgInfo,  uint16_t crnti
1734 * @params[in] bool isRetx, SchDlHqProcCb *hqP
1735 * @return void
1736 *
1737 *******************************************************************/
1738 void fillDlMsgInfo(DlMsgSchInfo *dlMsgSchInfo, uint16_t crnti, bool isRetx, SchDlHqProcCb *hqP)
1739 {
1740    hqP->tbInfo[0].isEnabled = TRUE;
1741    hqP->tbInfo[0].state = HQ_TB_WAITING;
1742    hqP->tbInfo[0].txCntr++;
1743    hqP->tbInfo[1].isEnabled = TRUE;
1744    hqP->tbInfo[1].state = HQ_TB_WAITING;
1745    hqP->tbInfo[1].txCntr++;
1746    dlMsgSchInfo->crnti = crnti;
1747    dlMsgSchInfo->transportBlock[0].ndi = hqP->tbInfo[0].ndi; /*How to handle two tb case?TBD*/
1748    dlMsgSchInfo->harqProcNum = hqP->procId;
1749    dlMsgSchInfo->dlAssignIdx = 0;
1750    dlMsgSchInfo->pucchTpc = 0;
1751    dlMsgSchInfo->pucchResInd = 0;
1752    dlMsgSchInfo->harqFeedbackInd = hqP->k1;
1753    dlMsgSchInfo->dciFormatId = 1;
1754 }
1755
1756 /*******************************************************************
1757  *
1758  * @brief sch Process pending Msg4 Req
1759  *
1760  * @details
1761  *
1762  *    Function : schProcessMsg4Req
1763  *
1764  *    Functionality:
1765  *       sch Process pending Msg4 Req
1766  *
1767  * @params[in] SchCellCb *cell, cell cb struct pointer
1768  * @params[in] SlotTimingInfo currTime, current timing info
1769  * @params[in] uint8_t ueId, ue ID
1770  * @params[in] bool isRetxMsg4, indicator to MSG4 retransmission
1771  * @params[in] SchDlHqProcCb **msg4HqProc, address of MSG4 HARQ proc pointer
1772  * @return ROK     - success
1773  *         RFAILED - failure
1774  *
1775  *******************************************************************/
1776
1777 uint8_t schProcessMsg4Req(SchCellCb *cell, SlotTimingInfo currTime, uint8_t ueId, bool isRetxMsg4, SchDlHqProcCb **msg4HqProc)
1778 {
1779    uint8_t pdschStartSymbol = 0, pdschNumSymbols = 0;
1780    SlotTimingInfo pdcchTime, pdschTime, pucchTime;
1781    DlMsgSchInfo *dciSlotAlloc = NULLP;    /* Stores info for transmission of PDCCH for Msg4 */
1782    DlMsgSchInfo *msg4SlotAlloc = NULLP;   /* Stores info for transmission of PDSCH for Msg4 */
1783
1784    if(cell == NULL)
1785    {
1786       DU_LOG("\nERROR  -->  SCH: schProcessMsg4Req() : Cell is NULL");
1787       return RFAILED;
1788    }
1789
1790    if (isRetxMsg4 == FALSE)
1791    {
1792       if (RFAILED == schDlGetAvlHqProcess(cell, &cell->ueCb[ueId - 1], msg4HqProc))
1793       {
1794          DU_LOG("\nERROR  -->  SCH: schProcessMsg4Req() : No process");
1795          return RFAILED;
1796       }
1797    }
1798
1799    if(findValidK0K1Value(cell, currTime, ueId, false, &pdschStartSymbol, &pdschNumSymbols, &pdcchTime, &pdschTime,\
1800             &pucchTime, isRetxMsg4, *msg4HqProc) != true )
1801    {
1802       DU_LOG("\nERROR  -->  SCH: schProcessMsg4Req() : k0 k1 not found");
1803       return RFAILED;
1804    }
1805
1806    if(cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] == NULL)
1807    {
1808       SCH_ALLOC(dciSlotAlloc, sizeof(DlMsgSchInfo));
1809       if(dciSlotAlloc == NULLP)
1810       {
1811          DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for dciSlotAlloc");
1812          return RFAILED;
1813       }
1814       cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = dciSlotAlloc;
1815       memset(dciSlotAlloc, 0, sizeof(DlMsgSchInfo));
1816    }
1817    else
1818       dciSlotAlloc = cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1];
1819
1820    /* Fill PDCCH and PDSCH scheduling information for Msg4 */
1821    if((schDlRsrcAllocMsg4(cell, pdschTime, ueId, dciSlotAlloc, pdschStartSymbol, pdschNumSymbols, isRetxMsg4, *msg4HqProc)) != ROK)
1822    {
1823       DU_LOG("\nERROR  -->  SCH: Scheduling of Msg4 failed in slot [%d]", pdschTime.slot);
1824       if(!dciSlotAlloc->dlMsgPdschCfg)
1825       {
1826          SCH_FREE(dciSlotAlloc, sizeof(DlMsgSchInfo));
1827          cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
1828       }
1829       return RFAILED;
1830    }
1831
1832    /* Check if both DCI and RAR are sent in the same slot.
1833     * If not, allocate memory RAR PDSCH slot to store RAR info
1834     */
1835    if(pdcchTime.slot == pdschTime.slot)
1836    {
1837       SCH_ALLOC(dciSlotAlloc->dlMsgPdschCfg, sizeof(PdschCfg));
1838       if(!dciSlotAlloc->dlMsgPdschCfg)
1839       {
1840          DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for dciSlotAlloc->dlMsgPdschCfg");
1841          SCH_FREE(dciSlotAlloc->dlMsgPdcchCfg, sizeof(PdcchCfg));
1842          SCH_FREE(dciSlotAlloc, sizeof(DlMsgSchInfo));
1843          cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
1844          return RFAILED;
1845       }
1846       memcpy(dciSlotAlloc->dlMsgPdschCfg, &dciSlotAlloc->dlMsgPdcchCfg->dci.pdschCfg, sizeof(PdschCfg));
1847    }
1848    else
1849    {
1850       /* Allocate memory to schedule rarSlot to send RAR, pointer will be checked at schProcessSlotInd() */
1851       if(cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1] == NULL)
1852       {
1853          SCH_ALLOC(msg4SlotAlloc, sizeof(DlMsgSchInfo));
1854          if(msg4SlotAlloc == NULLP)
1855          {
1856             DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for msg4SlotAlloc");
1857             SCH_FREE(dciSlotAlloc->dlMsgPdcchCfg, sizeof(PdcchCfg));
1858             if(!dciSlotAlloc->dlMsgPdschCfg)
1859             {
1860                SCH_FREE(dciSlotAlloc, sizeof(DlMsgSchInfo));
1861                cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
1862             }
1863             return RFAILED;
1864          }
1865          cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1] = msg4SlotAlloc;
1866          memset(msg4SlotAlloc, 0, sizeof(DlMsgSchInfo));
1867       }
1868       else
1869          msg4SlotAlloc = cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1];
1870
1871       /* Copy all msg4 pdschcfg info */
1872       msg4SlotAlloc->crnti =dciSlotAlloc->crnti;
1873       msg4SlotAlloc->bwp = dciSlotAlloc->bwp;
1874       SCH_ALLOC(msg4SlotAlloc->dlMsgPdschCfg, sizeof(PdschCfg));
1875       if(msg4SlotAlloc->dlMsgPdschCfg)
1876       {
1877          memcpy(msg4SlotAlloc->dlMsgPdschCfg, &dciSlotAlloc->dlMsgPdcchCfg->dci.pdschCfg, sizeof(PdschCfg));
1878       }
1879       else
1880       {
1881          SCH_FREE(dciSlotAlloc->dlMsgPdcchCfg, sizeof(PdcchCfg));    
1882          if(dciSlotAlloc->dlMsgPdschCfg == NULLP)
1883          {
1884             SCH_FREE(dciSlotAlloc, sizeof(DlMsgSchInfo));
1885             cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
1886
1887          }
1888          SCH_FREE(msg4SlotAlloc, sizeof(DlMsgSchInfo));
1889          cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
1890          DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for msg4SlotAlloc->dlMsgPdschCfg");
1891          return RFAILED;
1892       }
1893    }
1894
1895    /* PUCCH resource */
1896    schAllocPucchResource(cell, pucchTime, cell->raCb[ueId-1].tcrnti, &cell->ueCb[ueId-1], isRetxMsg4, *msg4HqProc);
1897
1898    cell->schDlSlotInfo[pdcchTime.slot]->pdcchUe = ueId;
1899    cell->schDlSlotInfo[pdschTime.slot]->pdschUe = ueId;
1900    cell->schUlSlotInfo[pucchTime.slot]->pucchUe = ueId;
1901    cell->raCb[ueId-1].msg4recvd = FALSE;
1902    if(isRetxMsg4)
1903    {
1904       cell->ueCb[ueId-1].retxMsg4HqProc= NULLP;
1905    }
1906    return ROK;
1907 }
1908
1909 /*******************************************************************
1910  *
1911  * @brief sch Process pending Sr or Bsr Req
1912  *
1913  * @details
1914  *
1915  *    Function : updateBsrAndLcList
1916  *
1917  *    Functionality:
1918  *       Updating the BSRInfo in UECB and Lclist
1919  *
1920  * @params[in] SchCellCb *cell,  SlotTimingInfo currTime 
1921  * @return ROK     - success
1922  *         RFAILED - failure
1923  *
1924  *******************************************************************/
1925 void updateBsrAndLcList(CmLListCp *lcLL, BsrInfo *bsrInfo, uint8_t status)
1926 {
1927    CmLList *node = NULLP, *next = NULLP;
1928    LcInfo *lcNode = NULLP;
1929
1930    if(lcLL == NULLP)
1931    {
1932       DU_LOG("\nERROR --> SCH: LcList not present");
1933       return;
1934    }
1935
1936    if(lcLL->count)
1937    {
1938       node = lcLL->first;
1939    }
1940    else
1941    {
1942       /*lcLL is empty*/
1943       return;
1944    }
1945
1946    while(node)
1947    {
1948       next = node->next;
1949       lcNode = (LcInfo *)node->node;
1950       if(lcNode != NULLP)
1951       {
1952           /*Only when Status is OK then allocation is marked as ZERO and reqBO
1953            * is updated in UE's DB. If Failure, then allocation is added to reqBO 
1954            * and same is updated in Ue's DB inside BSR Info structure*/
1955          if(status == ROK)
1956          {
1957             lcNode->allocBO = 0;
1958          }
1959
1960          lcNode->reqBO += lcNode->allocBO;
1961          bsrInfo[lcNode->lcId].dataVol = lcNode->reqBO;
1962          if(lcNode->reqBO == 0)
1963          {
1964             handleLcLList(lcLL, lcNode->lcId, DELETE);
1965          }
1966       }
1967       node = next;
1968    }
1969 }
1970
1971 /*******************************************************************
1972  *
1973  * @brief sch Process pending Sr or Bsr Req
1974  *
1975  * @details
1976  *
1977  *    Function : schProcessSrOrBsrReq
1978  *
1979  *    Functionality:
1980  *       sch Process pending Sr or Bsr Req
1981  *
1982  * @params[in] SchCellCb *cell,  SlotTimingInfo currTime
1983  * @params[in] uint8_t ueId, Bool isRetx, SchUlHqProcCb **hqP
1984  * @return true  - success
1985  *         false - failure
1986  *
1987  *******************************************************************/
1988 bool schProcessSrOrBsrReq(SchCellCb *cell, SlotTimingInfo currTime, uint8_t ueId, bool isRetx, SchUlHqProcCb **hqP)
1989 {
1990    bool k2Found = FALSE;
1991    uint8_t startSymb = 0, symbLen = 0;
1992    uint8_t k2TblIdx = 0, k2Index = 0, k2Val = 0;
1993    SchUeCb *ueCb;
1994    SchK2TimingInfoTbl *k2InfoTbl=NULLP;
1995    SlotTimingInfo dciTime, puschTime;
1996    
1997    if(cell == NULLP)
1998    {
1999       DU_LOG("\nERROR  -->  SCH: schProcessSrOrBsrReq() : Cell is NULL");
2000       return false;
2001    }
2002
2003    ueCb = &cell->ueCb[ueId-1];
2004
2005    if(ueCb == NULLP)
2006    {
2007       DU_LOG("\nERROR  -->  SCH: schProcessSrOrBsrReq() : UE is NULL");
2008       return false;
2009    }
2010
2011    if (isRetx == FALSE)
2012    {
2013       if (schUlGetAvlHqProcess(cell, ueCb, hqP) != ROK)
2014       {
2015          return RFAILED;
2016       }
2017    }
2018
2019    /* Calculating time frame to send DCI for SR */
2020    ADD_DELTA_TO_TIME(currTime, dciTime, PHY_DELTA_DL + SCHED_DELTA, cell->numSlots);
2021 #ifdef NR_TDD
2022    if(schGetSlotSymbFrmt(dciTime.slot, cell->slotFrmtBitMap) == DL_SLOT)
2023 #endif
2024    {     
2025       if(ueCb->k2TblPrsnt)
2026          k2InfoTbl = &ueCb->k2InfoTbl;
2027       else
2028          k2InfoTbl =  &cell->k2InfoTbl;
2029
2030       for(k2TblIdx = 0; k2TblIdx < k2InfoTbl->k2TimingInfo[dciTime.slot].numK2; k2TblIdx++)
2031       {
2032          k2Index = k2InfoTbl->k2TimingInfo[dciTime.slot].k2Indexes[k2TblIdx];
2033
2034          if(!ueCb->k2TblPrsnt)
2035          {
2036             k2Val = cell->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList[k2Index].k2;
2037             startSymb = cell->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList[k2Index].startSymbol;
2038             symbLen = cell->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList[k2Index].symbolLength;
2039          }
2040          else
2041          {
2042             k2Val = ueCb->ueCfg.spCellCfg.servCellRecfg.initUlBwp.puschCfg.timeDomRsrcAllocList[k2Index].k2;
2043             startSymb =  ueCb->ueCfg.spCellCfg.servCellRecfg.initUlBwp.puschCfg.timeDomRsrcAllocList[k2Index].startSymbol;
2044             symbLen =  ueCb->ueCfg.spCellCfg.servCellRecfg.initUlBwp.puschCfg.timeDomRsrcAllocList[k2Index].symbolLength;
2045          }
2046          /* Check for number of Symbol of PUSCH should be same as original in case of transmisson*/
2047          /* Calculating time frame to send PUSCH for SR */
2048          ADD_DELTA_TO_TIME(dciTime, puschTime, k2Val, cell->numSlots);
2049 #ifdef NR_TDD
2050          if(schGetSlotSymbFrmt(puschTime.slot, cell->slotFrmtBitMap) == DL_SLOT)
2051             continue;
2052 #endif
2053          if(cell->schUlSlotInfo[puschTime.slot]->puschUe != 0)
2054          {
2055             continue;
2056          }
2057          k2Found = true;
2058          if(hqP)
2059          {
2060             ADD_DELTA_TO_TIME(puschTime, (*hqP)->puschTime, 0, cell->numSlots);
2061          }
2062          break;
2063       }
2064    }
2065    
2066    if(k2Found == true)
2067    {
2068       if(cell->api->SchScheduleUlLc(dciTime, puschTime, startSymb, symbLen, isRetx, hqP) != ROK)
2069          return false;
2070    }
2071    else
2072    {
2073       DU_LOG("\nDEBUG  -->  SCH : schProcessSrOrBsrReq(): K2 value is not found");
2074       return false;     
2075    }
2076    return true;
2077 }
2078
2079 /********************************************************************************
2080  *
2081  * @brief Increment the Slot by a input factor
2082  *
2083  * @details
2084  *
2085  *    Function : schIncrSlot
2086  *
2087  *    Functionality:
2088  *       Increment the slot by a input factor till num of Slots configured in a
2089  *       Radio Frame. If it exceeds, move to next sfn.
2090  *
2091  * @params[in/out] SlotTimingInfo timingInfo
2092  *        [in]     uint8_t incr [Increment factor]
2093  *        [in]     numSlotsPerRF [Number of Slots configured per RF as per
2094  *                                numerology]
2095  * @return ROK     - success
2096  *         RFAILED - failure
2097  *
2098  *******************************************************************/
2099 void schIncrSlot(SlotTimingInfo *timingInfo, uint8_t incr, uint16_t numSlotsPerRF)
2100 {
2101    timingInfo->slot += incr;
2102    if(timingInfo->slot >= numSlotsPerRF)
2103    {
2104       timingInfo->sfn += timingInfo->slot/numSlotsPerRF;
2105       timingInfo->slot %= numSlotsPerRF;
2106       if(timingInfo->sfn >  MAX_SFN)
2107       {
2108          timingInfo->sfn %= MAX_SFN;
2109       }
2110    }
2111 }
2112
2113 /*******************************************************************
2114 *
2115 * @brief   Fill PDSCH info in Page Alloc
2116 *
2117 * @details
2118 *
2119 *    Function : schFillPagePdschCfg 
2120 *
2121 *    Functionality: Fill PDSCH info in Page Alloc
2122 *
2123 * @params[in] SchCellCb *cell, PdschCfg *pagePdschCfg, SlotTimingInfo slotTime, 
2124 *             uint16_t tbsSize, uint8_t mcs, uint16_t startPrb
2125 *
2126 * @return pointer to return Value(ROK, RFAILED) 
2127 *
2128 * ****************************************************************/
2129 uint8_t schFillPagePdschCfg(SchCellCb *cell, PageDlSch *pageDlSch, SlotTimingInfo slotTime, uint16_t tbSize, uint8_t mcs, uint16_t startPrb)
2130 {
2131    uint8_t dmrsStartSymbol, startSymbol, numSymbol;
2132
2133    /* fill the PDSCH PDU */
2134
2135    pageDlSch->tbInfo.mcs = mcs;
2136    tbSize = tbSize + TX_PAYLOAD_HDR_LEN;
2137    pageDlSch->tbInfo.tbSize = tbSize;
2138    pageDlSch->dmrs.dmrsType = 0; /* type-1 */
2139    pageDlSch->dmrs.nrOfDmrsSymbols               = NUM_DMRS_SYMBOLS;
2140    pageDlSch->dmrs.dmrsAddPos                    = DMRS_ADDITIONAL_POS;
2141
2142    /* the RB numbering starts from coreset0, and PDSCH is always above SSB */
2143    pageDlSch->freqAlloc.startPrb  = startPrb;
2144    pageDlSch->freqAlloc.numPrb    = schCalcNumPrb(tbSize, mcs, NUM_PDSCH_SYMBOL);
2145    pageDlSch->vrbPrbMapping       = 0; /* non-interleaved */
2146    /* This is Intel's requirement. PDSCH should start after PDSCH DRMS symbol */
2147    pageDlSch->timeAlloc.mappingType         = DMRS_MAP_TYPE_A; /* Type-A */
2148    pageDlSch->timeAlloc.startSymb = 3; /* spec-38.214, Table 5.1.2.1-1 */
2149    pageDlSch->timeAlloc.numSymb   = NUM_PDSCH_SYMBOL;
2150
2151    /* Find total symbols occupied including DMRS */
2152    dmrsStartSymbol = findDmrsStartSymbol(4);
2153    /* If there are no DRMS symbols, findDmrsStartSymbol() returns MAX_SYMB_PER_SLOT,
2154     * in that case only PDSCH symbols are marked as occupied */
2155    if(dmrsStartSymbol == MAX_SYMB_PER_SLOT)
2156    {
2157       startSymbol = pageDlSch->timeAlloc.startSymb;
2158       numSymbol = pageDlSch->timeAlloc.numSymb;
2159    }
2160    /* If DMRS symbol is found, mark DMRS and PDSCH symbols as occupied */
2161    else
2162    {
2163       startSymbol = dmrsStartSymbol;
2164       numSymbol = pageDlSch->dmrs.nrOfDmrsSymbols + pageDlSch->timeAlloc.numSymb;
2165    }
2166
2167    /* Allocate the number of PRBs required for DL PDSCH */
2168    if((allocatePrbDl(cell, slotTime, startSymbol, numSymbol,\
2169                &pageDlSch->freqAlloc.startPrb, pageDlSch->freqAlloc.numPrb)) != ROK)
2170    {
2171       DU_LOG("\nERROR  --> SCH : allocatePrbDl() failed for DL MSG");
2172       return RFAILED;
2173    }
2174    return ROK;
2175 }
2176
2177 /**
2178  * @brief Handles retransmission for MSG3
2179  *
2180  * @details
2181  *
2182  *     Function : schMsg3RetxSchedulingForUe
2183  *      
2184  *      This function handles retransmission for MSG3
2185  *           
2186  *  @param[in]  SchRaCb *raCb, RA cb pointer
2187  *  @return  
2188  *      -# ROK
2189  *      -# RFAILED
2190  **/
2191 uint8_t schMsg3RetxSchedulingForUe(SchRaCb *raCb)
2192 {
2193    bool      k2Found = false;
2194    uint16_t             dciSlot = 0;
2195    SlotTimingInfo       dciTime, msg3Time;
2196    SchCellCb            *cell = NULLP;
2197    SlotTimingInfo       currTime;
2198    DciInfo  *dciInfo = NULLP;
2199    cell = raCb->cell;
2200    currTime = cell->slotInfo;
2201
2202    /* Calculating time frame to send DCI for MSG3 Retx*/
2203    ADD_DELTA_TO_TIME(currTime, dciTime, PHY_DELTA_DL + SCHED_DELTA, cell->numSlots);
2204 #ifdef NR_TDD
2205    /* Consider this slot for sending DCI, only if it is a DL slot */
2206    if(schGetSlotSymbFrmt(dciSlot, raCb->cell->slotFrmtBitMap) == DL_SLOT)
2207 #endif
2208    {
2209       /* If PDCCH is already scheduled on this slot, cannot schedule PDSCH for another UE here. */
2210       if(cell->schDlSlotInfo[dciSlot]->pdcchUe != 0)
2211          return false;
2212
2213       k2Found = schGetMsg3K2(cell, &raCb->msg3HqProc, dciTime.slot, &msg3Time, TRUE);
2214
2215       if (!k2Found)
2216       {
2217          return RFAILED;
2218       }
2219       SCH_ALLOC(dciInfo, sizeof(DciInfo));
2220       if(!dciInfo)
2221       {
2222          DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for dciInfo alloc");
2223          return RFAILED;
2224       }
2225       cell->schDlSlotInfo[msg3Time.slot]->ulGrant = dciInfo;
2226       SCH_ALLOC(cell->schUlSlotInfo[msg3Time.slot]->schPuschInfo, sizeof(SchPuschInfo));
2227       memset(dciInfo,0,sizeof(DciInfo));
2228       schFillUlDciForMsg3Retx(raCb, cell->schUlSlotInfo[msg3Time.slot]->schPuschInfo, dciInfo);
2229    }   
2230    raCb->retxMsg3HqProc = NULLP;
2231    return ROK;
2232 }
2233
2234 /**
2235  * @brief Get K2 value for MSG3
2236  *
2237  * @details
2238  *
2239  *     Function : schGetMsg3K2
2240  *      
2241  *      This function gets K2 for MSG3
2242  *           
2243  *  @param[in]  SchCellCb *cell, Cell cb struc pointer
2244  *  @param[in]  SchUlHqProcCb* msg3HqProc, msg3 harq proc pointer
2245  *  @param[in]  uint16_t dlTime, DL time of scheduling
2246  *  @param[in]  SlotTimingInfo *msg3Time, MSG3 timing info
2247  *  @param[in]  bool isRetx, indicates MSG3 retransmission
2248  *  @return  
2249  *      -# true
2250  *      -# false
2251  **/
2252 bool schGetMsg3K2(SchCellCb *cell, SchUlHqProcCb* msg3HqProc, uint16_t dlTime, SlotTimingInfo *msg3Time, bool isRetx)
2253 {
2254    bool      k2Found = false;
2255    uint8_t   k2TblIdx = 0;
2256    uint8_t   k2Index = 0;
2257    uint8_t   k2 = 0;
2258    uint8_t   numK2 = 0;
2259    uint8_t   puschMu = 0;
2260    uint8_t   msg3Delta = 0, msg3MinSchTime = 0;
2261 #ifdef NR_TDD
2262    uint8_t   totalCfgSlot = 0;
2263 #endif
2264    SchK2TimingInfoTbl   *msg3K2InfoTbl=NULLP;
2265    SlotTimingInfo       currTime, msg3TempTime;
2266    currTime = cell->slotInfo;
2267    puschMu = cell->numerology;
2268
2269    if (isRetx)
2270    {
2271       if(!msg3HqProc)
2272          return false;
2273
2274       numK2 = cell->k2InfoTbl.k2TimingInfo[dlTime].numK2;
2275       msg3K2InfoTbl = &cell->msg3K2InfoTbl;
2276       msg3MinSchTime = 0;
2277       msg3Delta = 0;
2278    }
2279    else
2280    {
2281       numK2 = cell->msg3K2InfoTbl.k2TimingInfo[dlTime].numK2;
2282       msg3K2InfoTbl = &cell->k2InfoTbl;
2283       msg3MinSchTime = minMsg3SchTime[cell->numerology];
2284       msg3Delta = puschDeltaTable[puschMu];
2285    }
2286
2287    for(k2TblIdx = 0; k2TblIdx < numK2; k2TblIdx++)
2288    {
2289       k2Index = msg3K2InfoTbl->k2TimingInfo[dlTime].k2Indexes[k2TblIdx];
2290
2291       k2 = cell->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList[k2Index].k2;
2292       if (isRetx)
2293       {
2294          if ((msg3HqProc->strtSymbl != cell->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList[k2Index].startSymbol) ||
2295             (msg3HqProc->numSymbl != cell->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList[k2Index].symbolLength))
2296          {
2297             continue;
2298          }
2299       }
2300       /* Delta is added to the slot allocation for msg3 based on 38.214 section 6.1.2.1 */
2301       k2 = k2 + msg3Delta;
2302       if(k2 >= msg3MinSchTime)
2303       {
2304          ADD_DELTA_TO_TIME(currTime, msg3TempTime, k2, cell->numSlots);
2305 #ifdef NR_TDD
2306          if(schGetSlotSymbFrmt(msg3TempTime.slot % totalCfgSlot, cell->slotFrmtBitMap) == DL_SLOT)
2307             continue;
2308 #endif
2309          /* If PUSCH is already scheduled on this slot, another PUSCH
2310           * pdu cannot be scheduled here */
2311          if(cell->schUlSlotInfo[msg3TempTime.slot]->puschUe != 0)
2312             continue;
2313          k2Found = true;
2314          break;
2315       }
2316    }
2317    if (k2Found == true)
2318    {
2319       msg3Time->slot = msg3TempTime.slot;
2320       msg3Time->sfn = msg3TempTime.sfn;
2321       msg3Time->slot = msg3TempTime.slot;
2322    }
2323    return k2Found;
2324 }
2325
2326 /*
2327  *  * @brief : This Function fills the Coreset and SS info based on PDCCH Cfg received for a UE
2328  *
2329  *     Function : fillUeCoresetAndSsInfo
2330  *
2331  * For a Coreset, capture the following details which will be used during pdcch allocation
2332  *   [Step 1]: Count number of RBG and calculate TotalPRBs which can be used 
2333  *   [Step 2]: Get the reference pointer for Coreset and Its SearchSpace.
2334  *   [Step 3]: A CCE will have 6 RBs in TOTAL. If duration increases, CCE will
2335  *             occupy less number of PRBs(1RB x 1 OFDM Symbol). Eg. If duration = 2, then
2336  *             instead of 6 PRBs, CCE will only occupy 3 PRBs and 2 OFDM symbols.
2337  *   [Step 4]: Based on CoresetSize, fill AggLvl-CQI mapping by calculating the dciSize.
2338  *   [Step 5]: Calculate Y value for this coreset and UE
2339  *
2340  *   @Params[in]: UeCb,
2341  *  [return]: ROK, RFAILED : Memory allocation failure.
2342  **/
2343 uint8_t fillUeCoresetAndSsInfo(SchUeCb *ue)
2344 {
2345    uint8_t  cRSetIdx = 0,ssIdx = 0; 
2346    uint16_t rbgCount = 0;
2347    SchPdcchConfig *pdcchCfg = NULLP;
2348
2349    pdcchCfg =  &ue->ueCfg.spCellCfg.servCellRecfg.initDlBwp.pdcchCfg;
2350    if(pdcchCfg == NULLP)
2351    {
2352      DU_LOG("\nERROR  --> SCH: PDCCH Cfg is not received thus skip filling of Coreset & SS info");
2353      return RFAILED;
2354    }
2355    for(cRSetIdx = 0; cRSetIdx < pdcchCfg->numCRsetToAddMod; cRSetIdx++ )
2356    {
2357       /*[Step 1]: *//*Size of coreset: Number of PRBs in a coreset*/
2358       rbgCount = countRBGFrmCoresetFreqRsrc(pdcchCfg->cRSetToAddModList[cRSetIdx].freqDomainRsrc);
2359       if(rbgCount)
2360       {
2361          ue->pdcchInfo[cRSetIdx].totalPrbs = ((rbgCount) * NUM_PRBS_PER_RBG);
2362       }
2363       else
2364       {
2365          DU_LOG("\nERROR  -->  SCH : CORESETSize is zero in fillCoresetAndSsConfg");
2366          continue;
2367       }
2368       /*[Step 2]:*/
2369       ue->pdcchInfo[cRSetIdx].cRSetRef = &pdcchCfg->cRSetToAddModList[cRSetIdx];
2370       for(ssIdx = 0; ssIdx < pdcchCfg->numSearchSpcToAddMod; ssIdx++)
2371       {
2372          if(pdcchCfg->searchSpcToAddModList[ssIdx].cRSetId == pdcchCfg->cRSetToAddModList[cRSetIdx].cRSetId)
2373          {
2374             ue->pdcchInfo[cRSetIdx].ssRef = &pdcchCfg->searchSpcToAddModList[ssIdx];
2375             break;
2376          }
2377       }
2378
2379       /*[Step 3]:*/
2380       /*nrOfPRBPerCce is Number of PRBs occupied by a CCE based on Duration*/
2381       ue->pdcchInfo[cRSetIdx].nrOfPRBPerCce = NUM_PRBS_PER_RBG/pdcchCfg->cRSetToAddModList[cRSetIdx].duration;
2382       ue->pdcchInfo[cRSetIdx].totalCceCount = rbgCount * pdcchCfg->cRSetToAddModList[cRSetIdx].duration;
2383
2384       /*[Step 4]:*/
2385       fillCqiAggLvlMapping(&ue->pdcchInfo[cRSetIdx]);
2386
2387       /*[Step 5]:*/
2388       if(RFAILED == schUpdValY(ue, &ue->pdcchInfo[cRSetIdx]))
2389       {
2390          return RFAILED;
2391       }
2392    }
2393    return ROK;
2394 }
2395
2396 /*
2397  *  @brief: Function will validate a slot for PDCCH allocation
2398  *
2399  *  Function: schPdcchSlotValidation
2400  *
2401  *  As per 3gpp Spec 38.331, SearchSpace parameter, Every SearchSpace will have
2402  *  details of which slot and after how many slot the UE will monitor for PDCCH.
2403  *  Thus, while PDCCH allocation we need to ensure the above validation passes.
2404  *
2405  *  @param [IN]: PDCCH time, SearchSpace Info, numSlots in Cell
2406  *         [RETURN]: Flag depicting the slot validation
2407  * */
2408 bool schPdcchSlotValidation(SlotTimingInfo pdcchTime, SchSearchSpace *searchSpace, uint16_t numSlots)
2409 {
2410     bool     isSlotValid = false;
2411     uint16_t slotNum = 0, mSlotPeriodicityVal = 0;
2412
2413     /*Converting the timing info in units of Slots*/
2414     slotNum = (pdcchTime.sfn * numSlots)+pdcchTime.slot;
2415
2416     mSlotPeriodicityVal = \
2417     schConvertSlotPeriodicityEnumToValue(searchSpace->mSlotPeriodicityAndOffset.mSlotPeriodicity);
2418
2419     if(!mSlotPeriodicityVal)
2420     {
2421        DU_LOG("\nERROR   --> SCH: Slot Periodicity is ZERO thus cant proceed with this SearchSpace");
2422        return false;
2423     }
2424     /*The Monitoring slot begins from offset thus skip the slots which are less
2425      * than offset value*/
2426     if((slotNum >= searchSpace->mSlotPeriodicityAndOffset.mSlotOffset))
2427     {
2428         /*A pdcch Slot will start after Slotoffset and will get repeated after every
2429          * SlotPeriodicity*/
2430         if(((slotNum - searchSpace->mSlotPeriodicityAndOffset.mSlotOffset) % mSlotPeriodicityVal) == 0) 
2431         {
2432            DU_LOG("\nINFO   --> SCH: SFN:%d/Slot:%d, is a Valid PDCCH slot",pdcchTime.sfn, pdcchTime.slot);
2433            isSlotValid = true;
2434         }
2435         else
2436         {
2437            DU_LOG("\nINFO   --> SCH: SFN:%d/Slot:%d, is InValid PDCCH slot",pdcchTime.sfn, pdcchTime.slot);
2438         }
2439     }
2440     return (isSlotValid); 
2441 }
2442
2443 /*
2444  *  @brief: Function to check if PDCCH is available for a cceIndex
2445  *
2446  *  Function: schCheckPdcchAvail
2447  *
2448  *   This function checks if the PRBs available for a particular CCE during
2449  *   PDCCH allocation
2450  *   [Step 1]: Calculate the rbgIndex from cceIndex which depends on Coreset symbol duration
2451  *   i.e. a) If symbolDuration = 1; numPrbs in RBG (6) = numPrbPerCCE thus one on
2452  *        one mapping between rbgIndex and cceIndex
2453  *        b) if SymbolDuration =2; NumPrbs in RBG(6) = numPrbPerCCE * duration
2454  *        as CCE needs 6 REG thus in 3 PRBs whole CCE can contain 
2455  *        c) and so on
2456  *
2457  *   [Step 2]: Again StartPRB for a rbgIndex may not be same for CCE Index which
2458  *             depends on duration. If duration=2, then two CCE can be occupied
2459  *             in one RBGIndex thus StarPrb for secondCCE will be
2460  *             numPrbsPerCCE(3) away.
2461  *
2462  *   @params[in]: CellCb, SlotTime, cceIndex, PDcchInfo, aggLvl
2463  * */
2464 bool schCheckPdcchAvail(SchCellCb *cellCb, SlotTimingInfo slotTime, uint8_t cceIndex,\
2465                     SchPdcchInfo *pdcchInfo, uint8_t aggLvl )
2466 {
2467     uint8_t rbgIndex = 0, ret = 0, startSymbol = 0;
2468     uint16_t startPrb = MAX_NUM_RB, numPrb = 0;
2469
2470     /*[Step 1]: rbgIndex to locate in FreqDomainResource parmaeter in
2471      * SearchSpace*/
2472     rbgIndex = cceIndex / (pdcchInfo->cRSetRef->duration);
2473    
2474     /*Extract StartPRB for that RBGIndex*/
2475     startPrb = extractStartPrbForRBG(pdcchInfo->cRSetRef->freqDomainRsrc, rbgIndex);
2476     if(startPrb == MAX_NUM_RB)
2477     {
2478        DU_LOG("\nERROR  -->  SCH: No RBG is allocated for PDCCH in this Coreset");
2479        return false;
2480     }
2481     /*[Step 2]: Adjust StartPrb based on CCEIndex and duration*/
2482     startPrb = startPrb + ((cceIndex % pdcchInfo->cRSetRef->duration) * (pdcchInfo->nrOfPRBPerCce));
2483     startSymbol = findSsStartSymbol(pdcchInfo->ssRef->mSymbolsWithinSlot);
2484
2485     /*numPrb will also get adjusted with duration*/
2486     numPrb = (NUM_PRBS_PER_RBG * aggLvl) / pdcchInfo->cRSetRef->duration;
2487     DU_LOG("\nDEBUG  -->  SCH: RBG found for cceIndex:%d, AggLvl:%d and SymbolDuration%d with StartPrb:%d, numPrb:%d",\
2488             cceIndex, aggLvl, pdcchInfo->cRSetRef->duration, startPrb, numPrb);
2489
2490     ret = allocatePrbDl(cellCb, slotTime, startSymbol,\
2491                          pdcchInfo->cRSetRef->duration, &startPrb, numPrb);
2492     
2493     if(ret == RFAILED)
2494     {
2495        DU_LOG("\nERROR -->  SCH: PRBs can't be allocated as they are unavailable");
2496        return false;
2497     }
2498     return true;
2499
2500 }
2501
2502 /*
2503  * @brief: Function to select particular UE based on validation of PDCCH allocation
2504  *
2505  *    Function: 
2506  *    This function will have multiple layers of validation for PDCCH allocation 
2507  *    based on CORESET and SearchSpace configuration and availability.
2508  *
2509  *    [Step 1]: Check if the slot is pdcch Slot or not based on SearchSpace's
2510  *    monitoringSlotInfo.
2511  *    [Step 2]: Check the CQI for this UE and decide upon which Agg Level has to
2512  *    be used for this PDCCH transmission
2513  *    [Step 3]: find the AggLevel for this CQI = base aggregation level
2514  *    [Step 4]: NextLowerAggLvl will be the next lower aggLevel when PDCCH
2515  *    allocation fails for base agg Level.
2516  *    [Step 5]: For each candidate , calculate the CCE Index as per TS
2517  *    38.213v15, Sec 10.1 and also check PRBs falling in that CCEIndex is free.
2518  *    [Step 6]: If Step 5 fails, move to next candidate and if Candidate gets
2519  *    exhausted then fallback to nextAggLevel. Because as we decrease aggLevel,
2520  *    numberOfCCEReq decreases so chances of PDCCH allocation increases even
2521  *    though lowerAggLevel will not guarantee transmission of PDCCH as per CQI
2522  *    reported.(CQI less, AggiLvlRequried is More)
2523  *
2524  *    @params[IN]: SchUeCb and PdcchTime
2525  *          [RETURN]: isPDCCHAllocted flag(true = UE can be selected as a
2526  *          candidate )
2527  * */
2528 bool schDlCandidateSelection(SchUeCb *ueCb, SlotTimingInfo pdcchTime)
2529 {
2530     uint8_t cRSetIdx = 0, cceIndex = 0;
2531     uint8_t cqi = 0, candIdx = 0;
2532     uint8_t baseAggLvl = 0, nextLowerAggLvl = 0, numCandidates = 0;
2533     SchPdcchInfo *pdcchInfo = NULLP;
2534     uint32_t a = 0, b = 0;
2535
2536     for(cRSetIdx = 0; cRSetIdx < MAX_NUM_CRSET; cRSetIdx++)
2537     {
2538        pdcchInfo = &ueCb->pdcchInfo[cRSetIdx];
2539        if(pdcchInfo->cRSetRef == NULLP)
2540        {
2541           DU_LOG("\nINFO   -->  SCH: Coreset is not availabe at Index:%d",cRSetIdx);
2542           continue;
2543        }
2544        /*[Step 1]:*/
2545        if(false == schPdcchSlotValidation(pdcchTime, pdcchInfo->ssRef, ueCb->cellCb->numSlots))
2546        {
2547           DU_LOG("\nINFO   -->  SCH: This slot is not valid for PDCCH in this CORESET:%d.",pdcchInfo->cRSetRef->cRSetId);
2548           break;
2549        }
2550        /*[Step 2]:*/
2551        /*TODO: CQI is reported in DL_CQI_IND which has to be processed and
2552         * report has to be stored in ueCb.For now, HardCoding the value*/
2553         cqi = 5;
2554
2555         /*[Step 3]: */
2556         baseAggLvl = pdcchInfo->cqiIndxAggLvlMap[cqi];
2557
2558         /*[Step 4]:*/
2559         nextLowerAggLvl = baseAggLvl;
2560
2561         /*Loop to traverse through each AggLvl from higher value of aggLevel to
2562          * 1 AggLvl*/
2563         do
2564         {
2565            /*Configured num of candidates for each Agg Level in search space */
2566            numCandidates = extractNumOfCandForAggLvl(pdcchInfo->ssRef, nextLowerAggLvl); 
2567            if(!numCandidates)
2568            {
2569              DU_LOG("\nINFO   --> SCH:  Num Of Candidates configured for this AggLvel:%d is ZERO",baseAggLvl);
2570            }
2571
2572            /*[Step 5]:*/
2573            for(candIdx= 0; candIdx < numCandidates; candIdx++)
2574            {
2575                /*Formula reference 3GPP TS 38.213v15, Sec 10.1, Variable 'a' and
2576                 * 'b' is used for segmenting the formulat for readability purpose
2577                 * */
2578                a = pdcchInfo->y[pdcchTime.slot] + \
2579                      ceil((candIdx * pdcchInfo->totalCceCount)/(baseAggLvl * numCandidates));
2580                b = ceil(pdcchInfo->totalCceCount * baseAggLvl);
2581                cceIndex = baseAggLvl * (a % b); 
2582                if(schCheckPdcchAvail(ueCb->cellCb, pdcchTime, cceIndex, pdcchInfo,nextLowerAggLvl) == true)
2583                {
2584                   DU_LOG("\nINFO   -->  SCH: PDCCH allocation is successful at cceIndex:%d",cceIndex);
2585                   return true;  
2586                }
2587            }
2588            nextLowerAggLvl = nextLowerAggLvl >> 1;
2589         }while(nextLowerAggLvl > 0 && nextLowerAggLvl <= 16);
2590     }
2591     return false;
2592 }
2593 /**********************************************************************
2594   End of file
2595  **********************************************************************/
2596