<[Epic-ID: ODUHIGH-406][Task-ID: ODUHIGH-421]Paging Message: CU_STUB Trigger and...
[o-du/l2.git] / src / 5gnrsch / sch.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:     sch.c
22   
23      Type:     C source file
24   
25      Desc:     C source code for scheduler fucntions
26   
27      File:     sch.c
28   
29 **********************************************************************/
30
31 /** @file sch.c
32 @brief This file implements the schedulers main access to MAC layer code.
33 */
34 #include "common_def.h" 
35 #include "du_app_mac_inf.h"
36 #include "lrg.h"
37 #include "tfu.h"
38 #include "du_log.h"
39 #include "rgr.h"
40 #include "rg_sch_inf.h"
41 #include "rg_sch.h"
42
43 #include "tfu.x"           /* TFU types */
44 #include "lrg.x"           /* layer management typedefs for MAC */
45 #include "rgr.x"           /* layer management typedefs for MAC */
46 #include "rg_sch_inf.x"         /* typedefs for Scheduler */
47 #include "mac_sch_interface.h"
48 #include "sch.h"
49 #include "sch_utils.h"
50
51 void SchFillCfmPst(Pst *reqPst,Pst *cfmPst,RgMngmt *cfm);
52
53 /* local defines */
54 SchCellCfgCfmFunc SchCellCfgCfmOpts[] = 
55 {
56    packSchCellCfgCfm,     /* LC */
57    MacProcSchCellCfgCfm,  /* TC */
58    packSchCellCfgCfm      /* LWLC */
59 };
60
61 SchSliceCfgRspFunc SchSliceCfgRspOpts[] =
62 {
63    packSchSliceCfgRsp,     /* LC */
64    MacProcSchSliceCfgRsp,  /* TC */
65    packSchSliceCfgRsp      /* LWLC */
66
67 };
68
69 SchSliceReCfgRspFunc SchSliceReCfgRspOpts[] =
70 {
71    packSchSliceReCfgRsp,     /* LC */
72    MacProcSchSliceReCfgRsp,  /* TC */
73    packSchSliceReCfgRsp      /* LWLC */
74 };
75 /**
76  * @brief Task Initiation function. 
77  *
78  * @details
79  *
80  *     Function : schActvInit
81  *     
82  *     This function is supplied as one of parameters during MAC's 
83  *     task registration. MAC will invoke this function once, after
84  *     it creates and attaches this TAPA Task to a system task.
85  *     
86  *  @param[in]  Ent Entity, the entity ID of this task.     
87  *  @param[in]  Inst Inst, the instance ID of this task.
88  *  @param[in]  Region Region, the region ID registered for memory 
89  *              usage of this task.
90  *  @param[in]  Reason Reason.
91  *  @return  int
92  *      -# ROK
93  **/
94 uint8_t schActvInit(Ent entity, Inst instId, Region region, Reason reason)
95 {
96    Inst inst = (instId  - SCH_INST_START);
97
98    /* Initialize the MAC TskInit structure to zero */
99    memset ((uint8_t *)&schCb[inst], 0, sizeof(schCb));
100
101    /* Initialize the MAC TskInit with received values */
102    schCb[inst].schInit.ent = entity;
103    schCb[inst].schInit.inst = inst;
104    schCb[inst].schInit.region = region;
105    schCb[inst].schInit.pool = 0;
106    schCb[inst].schInit.reason = reason;
107    schCb[inst].schInit.cfgDone = FALSE;
108    schCb[inst].schInit.acnt = FALSE;
109    schCb[inst].schInit.usta = FALSE;
110    schCb[inst].schInit.trc = FALSE;
111    schCb[inst].schInit.procId = ODU_GET_PROCID();
112
113    return ROK;
114 } /* schActvInit */
115
116 /**
117  * @brief Scheduler instance Configuration Handler. 
118  *
119  * @details
120  *
121  *     Function : SchInstCfg
122  *     
123  *     This function in called by SchProcGenCfgReq(). It handles the
124  *     general configurations of the scheduler instance. Returns
125  *     reason for success/failure of this function.
126  *     
127  *  @param[in]  RgCfg *cfg, the Configuaration information 
128  *  @return  uint16_t
129  *      -# LCM_REASON_NOT_APPL 
130  *      -# LCM_REASON_INVALID_MSGTYPE
131  *      -# LCM_REASON_MEM_NOAVAIL
132  **/
133 uint8_t SchInstCfg(RgCfg *cfg, Inst  dInst)
134 {
135    uint16_t ret = LCM_REASON_NOT_APPL;
136    Inst     inst = (dInst - SCH_INST_START);
137
138    DU_LOG("\nDEBUG  -->  SCH : Entered SchInstCfg()");
139    /* Check if Instance Configuration is done already */
140    if (schCb[inst].schInit.cfgDone == TRUE)
141    {
142       return LCM_REASON_INVALID_MSGTYPE;
143    }
144    /* Update the Pst structure for LM interface */
145    memcpy(&schCb[inst].schInit.lmPst, &cfg->s.schInstCfg.genCfg.lmPst, sizeof(Pst));
146
147    schCb[inst].schInit.inst = inst;
148    schCb[inst].schInit.lmPst.srcProcId = schCb[inst].schInit.procId;
149    schCb[inst].schInit.lmPst.srcEnt = schCb[inst].schInit.ent;
150    schCb[inst].schInit.lmPst.srcInst = schCb[inst].schInit.inst +
151       SCH_INST_START;
152    schCb[inst].schInit.lmPst.event = EVTNONE;
153
154    schCb[inst].schInit.region = cfg->s.schInstCfg.genCfg.mem.region;
155    schCb[inst].schInit.pool = cfg->s.schInstCfg.genCfg.mem.pool;
156    schCb[inst].genCfg.tmrRes = cfg->s.schInstCfg.genCfg.tmrRes;
157 #ifdef LTE_ADV
158    schCb[inst].genCfg.forceCntrlSrbBoOnPCel =  cfg->s.schInstCfg.genCfg.forceCntrlSrbBoOnPCel;
159    schCb[inst].genCfg.isSCellActDeactAlgoEnable =  cfg->s.schInstCfg.genCfg.isSCellActDeactAlgoEnable;
160 #endif
161    schCb[inst].genCfg.startCellId    = cfg->s.schInstCfg.genCfg.startCellId;
162
163    /* Initialzie the timer queue */   
164    memset(&schCb[inst].tmrTq, 0, sizeof(CmTqType) * SCH_TQ_SIZE);
165    /* Initialize the timer control point */
166    memset(&schCb[inst].tmrTqCp, 0, sizeof(CmTqCp));
167    schCb[inst].tmrTqCp.tmrLen = RGSCH_TQ_SIZE;
168
169    /* SS_MT_TMR needs to be enabled as schActvTmr needs instance information */
170    /* Timer Registration request to system services */
171    if (ODU_REG_TMR_MT(schCb[inst].schInit.ent, dInst, (int)schCb[inst].genCfg.tmrRes, schActvTmr) != ROK)
172    {
173       DU_LOG("\nERROR  -->  SCH : SchInstCfg(): Failed to "
174             "register timer.");
175       return (LCM_REASON_MEM_NOAVAIL);
176    }   
177               
178    /* Set Config done in TskInit */
179    schCb[inst].schInit.cfgDone = TRUE;
180    DU_LOG("\nINFO   -->  SCH : Scheduler gen config done");
181
182    return ret;
183 }
184
185 /**
186  * @brief Layer Manager Configuration request handler. 
187  *
188  * @details
189  *
190  *     Function : SchProcGenCfgReq
191  *     
192  *     This function handles the configuration
193  *     request received at scheduler instance from the Layer Manager.
194  *     -# Based on the cfg->hdr.elmId.elmnt value it invokes one of the
195  *        functions rgHdlGenCfg() or rgHdlSapCfg().
196  *     -# Invokes RgMiLrgSchCfgCfm() to send back the confirmation to the LM.
197  *     
198  *  @param[in]  Pst *pst, the post structure     
199  *  @param[in]  RgMngmt *cfg, the configuration parameter's structure
200  *  @return  S16
201  *      -# ROK
202  **/
203 uint8_t SchProcGenCfgReq(Pst *pst, RgMngmt *cfg)
204 {
205    uint8_t   ret = LCM_PRIM_OK;
206    uint16_t  reason = LCM_REASON_NOT_APPL;
207    RgMngmt   cfm;
208    Pst       cfmPst;
209
210 #ifdef CALL_FLOW_DEBUG_LOG
211    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : GENERAL_CFG_REQ\n");
212 #endif
213
214    if(pst->dstInst < SCH_INST_START)
215    {
216       DU_LOG("\nERROR  -->  SCH : Invalid inst ID");
217       DU_LOG("\nERROR  -->  SCH : SchProcGenCfgReq(): "
218             "pst->dstInst=%d SCH_INST_START=%d", pst->dstInst,SCH_INST_START); 
219       return ROK;
220    }
221    DU_LOG("\nINFO   -->  SCH : Received scheduler gen config");
222    /* Fill the post structure for sending the confirmation */
223    memset(&cfmPst, 0 , sizeof(Pst));
224    SchFillCfmPst(pst, &cfmPst, cfg);
225
226    memset(&cfm, 0, sizeof(RgMngmt));
227
228 #ifdef LMINT3
229    cfm.hdr.transId =
230       cfg->hdr.transId;
231 #endif
232
233    cfm.hdr.elmId.elmnt = cfg->hdr.elmId.elmnt;
234    switch(cfg->hdr.elmId.elmnt)
235    {
236       case STSCHINST:
237          reason = SchInstCfg(&cfg->t.cfg,pst->dstInst );
238          break;
239       default:
240          ret = LCM_PRIM_NOK;
241          reason = LCM_REASON_INVALID_ELMNT;
242          DU_LOG("\nERROR  -->  SCH : Invalid Elmnt=%d", cfg->hdr.elmId.elmnt);
243          break;
244    }
245
246    if (reason != LCM_REASON_NOT_APPL)
247    {
248       ret = LCM_PRIM_NOK;
249    }
250
251    cfm.cfm.status = ret;
252    cfm.cfm.reason = reason;
253
254    SchSendCfgCfm(&cfmPst, &cfm);
255    /*   SCH_FREE(pst->region, pst->pool, (Data *)cfg, sizeof(RgMngmt)); */
256
257    return ROK;
258 }/*-- SchProcGenCfgReq --*/
259
260 /**
261  * @brief slot indication from MAC to SCH.
262  *
263  * @details
264  *
265  *     Function : MacSchSlotInd 
266  *      
267  *      This API is invoked by PHY to indicate slot indication to Scheduler for
268  *      a cell.
269  *           
270  *  @param[in]  Pst            *pst
271  *  @param[in]  SlotTimingInfo    *slotInd
272  *  @return  S16
273  *      -# ROK 
274  *      -# RFAILED 
275  **/
276 uint8_t MacSchSlotInd(Pst *pst, SlotTimingInfo *slotInd)
277 {
278    Inst  inst = pst->dstInst-SCH_INST_START;
279
280 #ifdef CALL_FLOW_DEBUG_LOG
281    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_SLOT_IND_TO_SCH\n");
282 #endif
283
284    schProcessSlotInd(slotInd, inst);
285
286    return ROK;
287 }  /* MacSchSlotInd */
288
289 /*******************************************************************
290  *
291  * @brief Processes Rach indication from MAC 
292  *
293  * @details
294  *
295  *    Function : MacSchRachInd
296  *
297  *    Functionality:
298  *      Processes Rach indication from MAC
299  *
300  * @params[in] 
301  * @return ROK     - success
302  *         RFAILED - failure
303  *
304  * ****************************************************************/
305 uint8_t MacSchRachInd(Pst *pst, RachIndInfo *rachInd)
306 {
307    Inst  inst = pst->dstInst-SCH_INST_START;
308
309 #ifdef CALL_FLOW_DEBUG_LOG
310    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_RACH_IND_TO_SCH\n");
311 #endif
312
313    DU_LOG("\nINFO  -->  SCH : Received Rach indication");
314    schProcessRachInd(rachInd, inst);
315    return ROK;
316 }
317
318 /*******************************************************************
319  *
320  * @brief Processes CRC indication from MAC 
321  *
322  * @details
323  *
324  *    Function : MacSchCrcInd
325  *
326  *    Functionality:
327  *      Processes CRC indication from MAC
328  *
329  * @params[in] Post structure
330  *             Crc Indication
331  * @return ROK     - success
332  *         RFAILED - failure
333  *
334  * ****************************************************************/
335 uint8_t MacSchCrcInd(Pst *pst, CrcIndInfo *crcInd)
336 {
337 #ifdef CALL_FLOW_DEBUG_LOG
338    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_CRC_IND_TO_SCH\n");
339 #endif
340
341    switch(crcInd->crcInd[0])
342    {
343       case CRC_FAILED:
344          DU_LOG("\nDEBUG  -->  SCH : Received CRC indication. CRC Status [FAILURE]");
345          break;
346       case CRC_PASSED:
347          DU_LOG("\nDEBUG  -->  SCH : Received CRC indication. CRC Status [PASS]");
348          break;
349       default:
350          DU_LOG("\nDEBUG  -->  SCH : Invalid CRC state %d", crcInd->crcInd[0]);
351          return RFAILED;
352    }
353    return ROK;
354 }
355
356 #ifdef NR_TDD
357 /**
358  *@brief Returns TDD periodicity in micro seconds
359  *
360  * @details
361  * 
362  * Function : schGetPeriodicityInMsec 
363  * 
364  * This API retunrs TDD periodicity in micro seconds
365  * 
366  * @param[in] DlUlTxPeriodicity 
367  * @return  periodicityInMsec
368  * **/
369
370 uint16_t schGetPeriodicityInMsec(DlUlTxPeriodicity tddPeriod)
371 {
372    uint16_t  periodicityInMsec = 0;
373    switch(tddPeriod)
374    {
375       case TX_PRDCTY_MS_0P5:
376       {
377          periodicityInMsec = 500;
378          break;
379       }
380       case TX_PRDCTY_MS_0P625:
381       {
382          periodicityInMsec = 625;
383          break;
384       }
385       case TX_PRDCTY_MS_1:
386       {
387          periodicityInMsec = 1000;
388          break;
389       }
390       case TX_PRDCTY_MS_1P25:
391       {
392          periodicityInMsec = 1250;
393          break;
394       }
395       case TX_PRDCTY_MS_2:
396       {
397          periodicityInMsec = 2000;
398          break;
399       }
400       case TX_PRDCTY_MS_2P5:
401       {
402          periodicityInMsec = 2500;
403          break;
404       }
405       case TX_PRDCTY_MS_5:
406       {
407          periodicityInMsec = 5000;
408          break;
409       }
410       case TX_PRDCTY_MS_10:
411       {
412          periodicityInMsec = 10000;
413          break;
414       }
415       default:
416       {
417          DU_LOG("\nERROR  -->  SCH : Invalid DlUlTxPeriodicity:%d", tddPeriod);
418       }
419    }
420
421    return periodicityInMsec;
422 }
423
424
425 /**
426  * @brief init TDD slot config 
427  *
428  * @details
429  *
430  *     Function : schInitTddSlotCfg 
431  *      
432  *      This API is invoked after receiving schCellCfg
433  *           
434  *  @param[in]  schCellCb *cell
435  *  @param[in]  SchCellCfg *schCellCfg
436  *  @return  void
437  **/
438 void schInitTddSlotCfg(SchCellCb *cell, SchCellCfg *schCellCfg)
439 {
440    uint16_t periodicityInMicroSec = 0;
441    int8_t slotIdx, symbIdx;
442
443    periodicityInMicroSec = schGetPeriodicityInMsec(schCellCfg->tddCfg.tddPeriod);
444    cell->numSlotsInPeriodicity = (periodicityInMicroSec * pow(2, schCellCfg->numerology))/1000;
445    cell->slotFrmtBitMap = 0;
446    cell->symbFrmtBitMap = 0;
447    for(slotIdx = cell->numSlotsInPeriodicity-1; slotIdx >= 0; slotIdx--)
448    {
449       symbIdx = 0;
450       /* If the first and last symbol are the same, the entire slot is the same type */
451       if((schCellCfg->tddCfg.slotCfg[slotIdx][symbIdx] == schCellCfg->tddCfg.slotCfg[slotIdx][MAX_SYMB_PER_SLOT-1]) &&
452               schCellCfg->tddCfg.slotCfg[slotIdx][symbIdx] != FLEXI_SLOT)
453       {
454          switch(schCellCfg->tddCfg.slotCfg[slotIdx][symbIdx])
455          {
456             case DL_SLOT:
457             {
458                /*BitMap to be set to 00 */
459                cell->slotFrmtBitMap = (cell->slotFrmtBitMap<<2);
460                break;
461             }
462             case UL_SLOT:
463             {
464                /*BitMap to be set to 01 */
465                cell->slotFrmtBitMap = ((cell->slotFrmtBitMap<<2) | (UL_SLOT));
466                break;
467             }
468             default:
469                DU_LOG("\nERROR  -->  SCH : Invalid slot Config in schInitTddSlotCfg");
470            }
471          continue;
472       }
473       /* slot config is flexible. First set slotBitMap to 10 */
474       cell->slotFrmtBitMap = ((cell->slotFrmtBitMap<<2) | (FLEXI_SLOT));
475
476       /* Now set symbol bitmap */ 
477       for(symbIdx = MAX_SYMB_PER_SLOT-1; symbIdx >= 0; symbIdx--)
478       {
479          switch(schCellCfg->tddCfg.slotCfg[slotIdx][symbIdx])
480          {
481             case DL_SLOT:
482             {
483                /*symbol BitMap to be set to 00 */
484                cell->symbFrmtBitMap = (cell->symbFrmtBitMap<<2);
485                break;
486             }
487             case UL_SLOT:
488             {
489                /*symbol BitMap to be set to 01 */
490                cell->symbFrmtBitMap = ((cell->symbFrmtBitMap<<2) | (UL_SLOT));
491                break;
492             }
493             case FLEXI_SLOT:
494             {
495                /*symbol BitMap to be set to 10 */
496                cell->symbFrmtBitMap = ((cell->symbFrmtBitMap<<2) | (FLEXI_SLOT));
497                break;
498             }
499             default:
500                DU_LOG("\nERROR  -->  SCH : Invalid slot Config in schInitTddSlotCfg");
501          }
502       }
503    }
504 }
505 #endif
506
507 /**
508  * @brief Fill SSB start symbol
509  *
510  * @details
511  *
512  *     Function : fillSsbStartSymb 
513  *      
514  *      This API stores SSB start index per beam
515  *           
516  *  @param[in]  SchCellCb     *cellCb
517  *  @return  int
518  *      -# ROK 
519  *      -# RFAILED 
520  **/
521 void fillSsbStartSymb(SchCellCb *cellCb)
522 {
523    uint8_t cnt, scs, symbIdx, ssbStartSymbArr[SCH_MAX_SSB_BEAM];
524
525    scs = cellCb->cellCfg.ssbSchCfg.scsCommon;
526
527    memset(ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
528    symbIdx = 0;
529    /* Determine value of "n" based on Section 4.1 of 3GPP TS 38.213 */
530    switch(scs)
531    {
532       case SCS_15KHZ:
533          {
534             if(cellCb->cellCfg.dlFreq <= 300000)
535                cnt = 2;/* n = 0, 1 */
536             else
537                cnt = 4; /* n = 0, 1, 2, 3 */
538             for(uint8_t idx=0; idx<cnt; idx++)
539             {
540                /* start symbol determined using {2, 8} + 14n */
541                ssbStartSymbArr[symbIdx++] = 2 +  MAX_SYMB_PER_SLOT*idx;
542                ssbStartSymbArr[symbIdx++] = 8 +  MAX_SYMB_PER_SLOT*idx;
543             }
544          }
545          break;
546       case SCS_30KHZ:
547          {
548             if(cellCb->cellCfg.dlFreq <= 300000)
549                cnt = 1;/* n = 0 */
550             else
551                cnt = 2; /* n = 0, 1 */
552             for(uint8_t idx=0; idx<cnt; idx++)
553             {
554                /* start symbol determined using {4, 8, 16, 20} + 28n */
555                ssbStartSymbArr[symbIdx++] = 4 +  MAX_SYMB_PER_SLOT*idx;
556                ssbStartSymbArr[symbIdx++] = 8 +  MAX_SYMB_PER_SLOT*idx;
557                ssbStartSymbArr[symbIdx++] = 16 +  MAX_SYMB_PER_SLOT*idx;
558                ssbStartSymbArr[symbIdx++] = 20 +  MAX_SYMB_PER_SLOT*idx;
559             }
560          }
561          break;
562       default:
563          DU_LOG("\nERROR  -->  SCH : SCS %d is currently not supported", scs);
564    }
565    memset(cellCb->ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
566    memcpy(cellCb->ssbStartSymbArr, ssbStartSymbArr, SCH_MAX_SSB_BEAM);
567
568 }
569
570
571 /**
572  * @brief init cellCb based on cellCfg
573  *
574  * @details
575  *
576  *     Function : schInitCellCb 
577  *      
578  *      This API is invoked after receiving schCellCfg
579  *           
580  *  @param[in]  schCellCb *cell
581  *  @param[in]  SchCellCfg *schCellCfg
582  *  @return  int
583  *      -# ROK 
584  *      -# RFAILED 
585  **/
586 uint8_t schInitCellCb(Inst inst, SchCellCfg *schCellCfg)
587 {
588    SchCellCb *cell= NULLP;
589    SCH_ALLOC(cell, sizeof(SchCellCb));
590    if(!cell)
591    {
592       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb");
593       return RFAILED;
594    }
595
596    cell->cellId = schCellCfg->cellId; 
597    cell->instIdx = inst;
598    switch(schCellCfg->numerology)
599    {
600       case SCH_NUMEROLOGY_0:
601          {
602             cell->numSlots = SCH_MU0_NUM_SLOTS;
603          }
604          break;
605       case SCH_NUMEROLOGY_1:
606          {
607             cell->numSlots = SCH_MU1_NUM_SLOTS;
608          }
609          break;
610       case SCH_NUMEROLOGY_2:
611          {
612             cell->numSlots = SCH_MU2_NUM_SLOTS;
613          }
614          break;
615       case SCH_NUMEROLOGY_3:
616          {
617             cell->numSlots = SCH_MU3_NUM_SLOTS;
618          }
619          break;
620       case SCH_NUMEROLOGY_4:
621          {
622             cell->numSlots = SCH_MU4_NUM_SLOTS;
623          }
624          break;
625       default:
626          DU_LOG("\nERROR  -->  SCH : Numerology %d not supported", schCellCfg->numerology);
627    }
628 #ifdef NR_TDD
629    schInitTddSlotCfg(cell, schCellCfg);   
630 #endif
631
632    SCH_ALLOC(cell->schDlSlotInfo, cell->numSlots * sizeof(SchDlSlotInfo*));
633    if(!cell->schDlSlotInfo)
634    {
635       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb for schDlSlotInfo");
636       return RFAILED;
637    }
638
639    SCH_ALLOC(cell->schUlSlotInfo, cell->numSlots * sizeof(SchUlSlotInfo*));
640    if(!cell->schUlSlotInfo)
641    {
642       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb for schUlSlotInfo");
643       return RFAILED;
644    }
645
646    for(uint8_t idx=0; idx<cell->numSlots; idx++)
647    {
648       SchDlSlotInfo *schDlSlotInfo;
649       SchUlSlotInfo *schUlSlotInfo;
650
651       /* DL Alloc */
652       SCH_ALLOC(schDlSlotInfo, sizeof(SchDlSlotInfo));
653       if(!schDlSlotInfo)
654       {
655          DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb");
656          return RFAILED;
657       }
658
659       /* UL Alloc */
660       SCH_ALLOC(schUlSlotInfo, sizeof(SchUlSlotInfo));
661       if(!schUlSlotInfo)
662       {
663          DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb");
664          return RFAILED;
665       }
666
667       schInitDlSlot(schDlSlotInfo);
668       schInitUlSlot(schUlSlotInfo);
669
670       cell->schDlSlotInfo[idx] = schDlSlotInfo;
671       cell->schUlSlotInfo[idx] = schUlSlotInfo;
672
673    }
674    cell->firstSsbTransmitted = false;
675    cell->firstSib1Transmitted = false;
676    fillSsbStartSymb(cell);
677    cmLListInit(&cell->ueToBeScheduled);
678    schCb[inst].cells[inst] = cell;
679
680    DU_LOG("\nINFO  -->  SCH : Cell init completed for cellId:%d", cell->cellId);
681
682    return ROK;   
683 }
684
685 /**
686  * @brief Fill SIB1 configuration
687  *
688  * @details
689  *
690  *     Function : fillSchSib1Cfg
691  *
692  *     Fill SIB1 configuration
693  *
694  *  @param[in]  uint8_t bandwidth : total available bandwidth
695  *              uint8_t numSlots : total slots per SFN
696  *              SchSib1Cfg *sib1SchCfg : cfg to be filled
697  *              uint16_t pci : physical cell Id
698  *              uint8_t offsetPointA : offset
699  *  @return  void
700  **/
701 void fillSchSib1Cfg(uint8_t mu, uint8_t bandwidth, uint8_t numSlots, SchSib1Cfg *sib1SchCfg, uint16_t pci, uint8_t offsetPointA)
702 {
703    uint8_t coreset0Idx = 0;
704    uint8_t searchSpace0Idx = 0;
705    //uint8_t ssbMuxPattern = 0;
706    uint8_t numRbs = 0;
707    uint8_t numSymbols = 0;
708    uint8_t offset = 0;
709    uint8_t oValue = 0;
710    //uint8_t numSearchSpacePerSlot = 0;
711    uint8_t mValue = 0;
712    uint8_t firstSymbol = 0; /* need to calculate using formula mentioned in 38.213 */
713    uint8_t slotIndex = 0;
714    uint8_t FreqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
715    uint16_t tbSize = 0;
716    uint8_t ssbIdx = 0;
717
718    PdcchCfg *pdcch = &(sib1SchCfg->sib1PdcchCfg);
719    PdschCfg *pdsch = &(sib1SchCfg->sib1PdschCfg);
720    BwpCfg *bwp = &(sib1SchCfg->bwp);
721
722    coreset0Idx     = sib1SchCfg->coresetZeroIndex;
723    searchSpace0Idx = sib1SchCfg->searchSpaceZeroIndex;
724
725    /* derive the sib1 coreset0 params from table 13-1 spec 38.213 */
726    //ssbMuxPattern = coresetIdxTable[coreset0Idx][0];
727    numRbs        = coresetIdxTable[coreset0Idx][1];
728    numSymbols    = coresetIdxTable[coreset0Idx][2];
729    offset        = coresetIdxTable[coreset0Idx][3];
730
731    /* derive the search space params from table 13-11 spec 38.213 */
732    oValue                = searchSpaceIdxTable[searchSpace0Idx][0];
733    //numSearchSpacePerSlot = searchSpaceIdxTable[searchSpace0Idx][1];
734    mValue                = searchSpaceIdxTable[searchSpace0Idx][2];
735    firstSymbol           = searchSpaceIdxTable[searchSpace0Idx][3];
736
737    /* calculate the n0, need to add the formulae, as of now the value is 0 
738     * Need to add the even and odd values of i during configuration 
739     * [(O . 2^u + i . M )  ] mod numSlotsPerSubframe 
740     * assuming u = 0, i = 0, numSlotsPerSubframe = 10
741     * Also, from this configuration, coreset0 is only on even subframe */
742    slotIndex = (int)((oValue*pow(2, mu)) + floor(ssbIdx*mValue))%numSlots;
743    sib1SchCfg->n0 = slotIndex;
744
745    /* fill BWP */
746    switch(bandwidth)
747    {
748       case BANDWIDTH_20MHZ:
749          {
750             bwp->freqAlloc.numPrb = TOTAL_PRB_20MHZ_MU0;
751          }
752          break;
753       case BANDWIDTH_100MHZ:
754          {
755             bwp->freqAlloc.numPrb = TOTAL_PRB_100MHZ_MU1;
756          }
757          break;
758       default:
759          DU_LOG("\nERROR  -->  SCH : Bandwidth %d not supported", bandwidth);
760
761    }
762    bwp->freqAlloc.startPrb = 0;
763    bwp->subcarrierSpacing  = 0;         /* 15Khz */
764    bwp->cyclicPrefix       = 0;              /* normal */
765
766    /* fill the PDCCH PDU */
767    pdcch->coresetCfg.coreSetSize = numRbs;
768    pdcch->coresetCfg.startSymbolIndex = firstSymbol;
769    pdcch->coresetCfg.durationSymbols = numSymbols;
770    
771    /* Fill Bitmap for PRBs in coreset */
772    fillCoresetFeqDomAllocMap(((offsetPointA-offset)/6), (numRbs/6), FreqDomainResource);
773    covertFreqDomRsrcMapToIAPIFormat(FreqDomainResource, pdcch->coresetCfg.freqDomainResource);
774
775    pdcch->coresetCfg.cceRegMappingType = 1; /* coreset0 is always interleaved */
776    pdcch->coresetCfg.regBundleSize = 6;    /* spec-38.211 sec 7.3.2.2 */
777    pdcch->coresetCfg.interleaverSize = 2;  /* spec-38.211 sec 7.3.2.2 */
778    pdcch->coresetCfg.coreSetType = 0;
779    pdcch->coresetCfg.shiftIndex = pci;
780    pdcch->coresetCfg.precoderGranularity = 0; /* sameAsRegBundle */
781    pdcch->numDlDci = 1;
782    pdcch->dci.rnti = SI_RNTI;
783    pdcch->dci.scramblingId = pci;
784    pdcch->dci.scramblingRnti = 0;
785    pdcch->dci.cceIndex = 0;
786    pdcch->dci.aggregLevel = 4;
787    pdcch->dci.beamPdcchInfo.numPrgs = 1;
788    pdcch->dci.beamPdcchInfo.prgSize = 1;
789    pdcch->dci.beamPdcchInfo.digBfInterfaces = 0;
790    pdcch->dci.beamPdcchInfo.prg[0].pmIdx = 0;
791    pdcch->dci.beamPdcchInfo.prg[0].beamIdx[0] = 0;
792    pdcch->dci.txPdcchPower.powerValue = 0;
793    pdcch->dci.txPdcchPower.powerControlOffsetSS = 0;
794    /* Storing pdschCfg pointer here. Required to access pdsch config while
795       fillig up pdcch pdu */
796    pdcch->dci.pdschCfg = pdsch; 
797
798    /* fill the PDSCH PDU */
799    uint8_t cwCount = 0;
800    pdsch->pduBitmap = 0; /* PTRS and CBG params are excluded */
801    pdsch->rnti = 0xFFFF; /* SI-RNTI */
802    pdsch->pduIndex = 0;
803    pdsch->numCodewords = 1;
804    for(cwCount = 0; cwCount < pdsch->numCodewords; cwCount++)
805    {
806       pdsch->codeword[cwCount].targetCodeRate = 308;
807       pdsch->codeword[cwCount].qamModOrder = 2;
808       pdsch->codeword[cwCount].mcsIndex = sib1SchCfg->sib1Mcs;
809       pdsch->codeword[cwCount].mcsTable = 0; /* notqam256 */
810       pdsch->codeword[cwCount].rvIndex = 0;
811       tbSize = schCalcTbSize(sib1SchCfg->sib1PduLen + TX_PAYLOAD_HDR_LEN);
812       pdsch->codeword[cwCount].tbSize = tbSize;
813    }
814    pdsch->dataScramblingId                   = pci;
815    pdsch->numLayers                          = 1;
816    pdsch->transmissionScheme                 = 0;
817    pdsch->refPoint                           = 0;
818    pdsch->dmrs.dlDmrsSymbPos                 = 4; /* Bitmap value 00000000000100 i.e. using 3rd symbol for PDSCH DMRS */
819    pdsch->dmrs.dmrsConfigType                = 0; /* type-1 */
820    pdsch->dmrs.dlDmrsScramblingId            = pci;
821    pdsch->dmrs.scid                          = 0;
822    pdsch->dmrs.numDmrsCdmGrpsNoData          = 1;
823    pdsch->dmrs.dmrsPorts                     = 0x0001;
824    pdsch->dmrs.mappingType                   = DMRS_MAP_TYPE_A; /* Type-A */
825    pdsch->dmrs.nrOfDmrsSymbols               = NUM_DMRS_SYMBOLS;
826    pdsch->dmrs.dmrsAddPos                    = DMRS_ADDITIONAL_POS;
827
828    pdsch->pdschFreqAlloc.resourceAllocType   = 1; /* RAT type-1 RIV format */
829    /* the RB numbering starts from coreset0, and PDSCH is always above SSB */
830    pdsch->pdschFreqAlloc.freqAlloc.startPrb  = offsetPointA + SCH_SSB_NUM_PRB;
831    pdsch->pdschFreqAlloc.freqAlloc.numPrb    = schCalcNumPrb(tbSize,sib1SchCfg->sib1Mcs, NUM_PDSCH_SYMBOL);
832    pdsch->pdschFreqAlloc.vrbPrbMapping       = 0; /* non-interleaved */
833    pdsch->pdschTimeAlloc.rowIndex            = 1;
834    /* This is Intel's requirement. PDSCH should start after PDSCH DRMS symbol */
835    pdsch->pdschTimeAlloc.timeAlloc.startSymb = 3; /* spec-38.214, Table 5.1.2.1-1 */
836    pdsch->pdschTimeAlloc.timeAlloc.numSymb   = NUM_PDSCH_SYMBOL;
837    pdsch->beamPdschInfo.numPrgs              = 1;
838    pdsch->beamPdschInfo.prgSize              = 1;
839    pdsch->beamPdschInfo.digBfInterfaces      = 0;
840    pdsch->beamPdschInfo.prg[0].pmIdx         = 0;
841    pdsch->beamPdschInfo.prg[0].beamIdx[0]    = 0;
842    pdsch->txPdschPower.powerControlOffset    = 0;
843    pdsch->txPdschPower.powerControlOffsetSS  = 0;
844
845 }
846
847 /**
848  * @brief cell config from MAC to SCH.
849  *
850  * @details
851  *
852  *     Function : macSchCellCfgReq
853  *      
854  *      This API is invoked by MAC to send cell config to SCH
855  *           
856  *  @param[in]  Pst            *pst
857  *  @param[in]  SchCellCfg     *schCellCfg
858  *  @return  int
859  *      -# ROK 
860  *      -# RFAILED 
861  **/
862 uint8_t SchHdlCellCfgReq(Pst *pst, SchCellCfg *schCellCfg)
863 {
864    uint8_t ret = ROK;
865    SchCellCb *cellCb;
866    SchCellCfgCfm schCellCfgCfm;
867    Pst rspPst;
868    Inst inst = pst->dstInst - SCH_INST_START; 
869    uint8_t coreset0Idx = 0;
870    uint8_t numRbs = 0;
871    uint8_t offset = 0;
872    uint8_t freqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
873    SchPdschConfig pdschCfg;
874
875 #ifdef CALL_FLOW_DEBUG_LOG
876    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_SCH_CELL_CFG\n");
877 #endif 
878
879    schInitCellCb(inst, schCellCfg);
880    cellCb = schCb[inst].cells[inst]; //cells is of MAX_CELLS, why inst
881    cellCb->macInst = pst->srcInst;
882
883    /* derive the SIB1 config parameters */
884    fillSchSib1Cfg(schCellCfg->numerology, schCellCfg->bandwidth, cellCb->numSlots,
885          &(schCellCfg->sib1SchCfg), schCellCfg->phyCellId,
886          schCellCfg->ssbSchCfg.ssbOffsetPointA);
887    
888    
889    memcpy(&cellCb->cellCfg, schCellCfg, sizeof(SchCellCfg));
890    schProcPagingCfg(cellCb);
891
892    /* Fill coreset frequencyDomainResource bitmap */
893    coreset0Idx = cellCb->cellCfg.schInitialDlBwp.pdcchCommon.commonSearchSpace.coresetId;
894    numRbs = coresetIdxTable[coreset0Idx][1];
895    offset = coresetIdxTable[coreset0Idx][3];
896    fillCoresetFeqDomAllocMap(((cellCb->cellCfg.ssbSchCfg.ssbOffsetPointA - offset)/6), (numRbs/6), freqDomainResource);
897    covertFreqDomRsrcMapToIAPIFormat(freqDomainResource, \
898       cellCb->cellCfg.schInitialDlBwp.pdcchCommon.commonSearchSpace.freqDomainRsrc);
899
900    /* Fill K0 - K1 table for common cfg*/ 
901    BuildK0K1Table(cellCb, &cellCb->cellCfg.schInitialDlBwp.k0K1InfoTbl, true, cellCb->cellCfg.schInitialDlBwp.pdschCommon,
902    pdschCfg, DEFAULT_UL_ACK_LIST_COUNT, defaultUlAckTbl);
903    
904    BuildK2InfoTable(cellCb, cellCb->cellCfg.schInitialUlBwp.puschCommon.timeDomRsrcAllocList,\
905    cellCb->cellCfg.schInitialUlBwp.puschCommon.numTimeDomRsrcAlloc, &cellCb->cellCfg.schInitialUlBwp.msg3K2InfoTbl, \
906    &cellCb->cellCfg.schInitialUlBwp.k2InfoTbl);
907    /* Initializing global variables */
908    cellCb->actvUeBitMap = 0;
909    cellCb->boIndBitMap = 0;
910
911    /* Fill and send Cell config confirm */
912    memset(&rspPst, 0, sizeof(Pst));
913    FILL_PST_SCH_TO_MAC(rspPst, pst->dstInst);
914    rspPst.event = EVENT_SCH_CELL_CFG_CFM;
915
916    schCellCfgCfm.cellId = schCellCfg->cellId; 
917    schCellCfgCfm.rsp = RSP_OK;
918
919    ret = (*SchCellCfgCfmOpts[rspPst.selector])(&rspPst, &schCellCfgCfm);
920    return ret;
921
922 }
923
924 /*******************************************************************
925  *
926  * @brief Processes DL RLC BO info from MAC
927  *
928  * @details
929  *
930  *    Function : MacSchDlRlcBoInfo
931  *
932  *    Functionality:
933  *       Processes DL RLC BO info from MAC
934  *
935  * @params[in] 
936  * @return ROK     - success
937  *         RFAILED - failure
938  *
939  * ****************************************************************/
940 uint8_t MacSchDlRlcBoInfo(Pst *pst, DlRlcBoInfo *dlBoInfo)
941 {
942    uint8_t  lcId = 0;
943    uint16_t ueId = 0;
944    bool isLcIdValid = false;
945    SchUeCb *ueCb = NULLP;
946    SchCellCb *cell = NULLP;
947    Inst  inst = pst->dstInst-SCH_INST_START;
948    CmLListCp *lcLL = NULLP;
949
950 #ifdef CALL_FLOW_DEBUG_LOG
951    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_DL_RLC_BO_INFO_TO_SCH\n");
952 #endif
953
954    DU_LOG("\nDEBUG  -->  SCH : Received RLC BO Status indication LCId [%d] BO [%d]", dlBoInfo->lcId, dlBoInfo->dataVolume);
955    cell = schCb[inst].cells[inst];
956
957    if(cell == NULLP)
958    {
959       DU_LOG("\nERROR  -->  SCH : MacSchDlRlcBoInfo(): Cell does not exists");
960       return RFAILED;
961    }
962
963    GET_UE_ID(dlBoInfo->crnti, ueId);
964    ueCb = &cell->ueCb[ueId-1];
965    if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
966    {
967       DU_LOG("INFO  --> SCH : DL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
968       return ROK;
969    }
970    
971    lcId  = dlBoInfo->lcId;
972    CHECK_LCID(lcId, isLcIdValid);
973    if(isLcIdValid == FALSE)
974    {
975       DU_LOG("ERROR --> SCH: LCID:%d is not valid", lcId);
976       return RFAILED;
977    }
978
979    /*Expected when theres a case of Retransmission Failure or Resetablishment
980     *By Zero BO, the RLC is informing that previous data can be cleared out
981     *Thus clearing out the LC from the Lc priority list*/
982    if(dlBoInfo->dataVolume == 0)
983    {
984       /*Check the LC is Dedicated or default and accordingly LCList will
985        * be used*/
986       if(ueCb->dlInfo.dlLcCtxt[lcId].isDedicated)
987       {
988          lcLL = &(ueCb->dlLcPrbEst.dedLcInfo->dedLcList);
989       }
990       else
991       {
992          lcLL = &(ueCb->dlLcPrbEst.defLcList);
993       }
994       handleLcLList(lcLL, lcId, DELETE);
995       return ROK;
996    }
997
998    if(lcId == SRB0_LCID)
999    {
1000       cell->raCb[ueId -1].msg4recvd = true;
1001       cell->raCb[ueId -1].dlMsgPduLen = dlBoInfo->dataVolume;
1002       
1003    }
1004    else
1005    {
1006       SET_ONE_BIT(ueId, cell->boIndBitMap);
1007       if(ueCb->dlInfo.dlLcCtxt[lcId].lcId == lcId)
1008       {
1009          ueCb->dlInfo.dlLcCtxt[lcId].bo = dlBoInfo->dataVolume;
1010       }
1011       else
1012       {
1013          DU_LOG("ERROR --> SCH: LCID:%d is not configured in SCH Cb",lcId);
1014          return RFAILED;
1015       }
1016    }
1017    
1018    /* Adding UE Id to list of pending UEs to be scheduled */
1019    addUeToBeScheduled(cell, ueId);
1020    return ROK;
1021 }
1022
1023 /*******************************************************************
1024  *
1025  * @brief Processes BSR indiation from MAC
1026  *
1027  * @details
1028  *
1029  *    Function : MacSchBsr
1030  *
1031  *    Functionality:
1032  *       Processes DL BSR from MAC
1033  *
1034  * @params[in]    Pst pst
1035  *                UlBufferStatusRptInd bsrInd
1036  * @return ROK     - success
1037  *         RFAILED - failure
1038  *
1039  * ****************************************************************/
1040 uint8_t MacSchBsr(Pst *pst, UlBufferStatusRptInd *bsrInd)
1041 {
1042    Inst           schInst       = pst->dstInst-SCH_INST_START;
1043    SchCellCb      *cellCb       = NULLP;
1044    SchUeCb        *ueCb         = NULLP;
1045    uint8_t        lcgIdx = 0;
1046
1047 #ifdef CALL_FLOW_DEBUG_LOG
1048    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_SHORT_BSR\n");
1049 #endif
1050
1051    DU_LOG("\nDEBUG  -->  SCH : Received BSR");
1052    if(bsrInd == NULLP)
1053    {
1054       DU_LOG("\nERROR  -->  SCH : BSR Ind is empty");
1055       return RFAILED;
1056    }
1057    cellCb = schCb[schInst].cells[schInst];
1058    if(cellCb == NULLP)
1059    {
1060       DU_LOG("\nERROR  -->  SCH : CellCb is empty");
1061       return RFAILED;
1062    }
1063    ueCb = schGetUeCb(cellCb, bsrInd->crnti);
1064
1065    if(ueCb == NULLP)
1066    {
1067       DU_LOG("\nERROR  -->  SCH : UeCB is empty");
1068       return RFAILED;
1069    }
1070
1071    if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1072    {
1073       DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1074       return ROK;
1075    }
1076    
1077    ueCb->bsrRcvd = true;
1078    /* store dataVolume per lcg in uecb */
1079    for(lcgIdx = 0; lcgIdx < bsrInd->numLcg; lcgIdx++)
1080    {
1081       ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].priority = 1; //TODO: determining LCG priority?
1082       ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].dataVol = bsrInd->dataVolInfo[lcgIdx].dataVol;
1083    }
1084    
1085    /* Adding UE Id to list of pending UEs to be scheduled */
1086    addUeToBeScheduled(cellCb, ueCb->ueId);
1087    return ROK;
1088 }
1089
1090 /*******************************************************************
1091  *
1092  * @brief Processes SR UCI indication from MAC 
1093  *
1094  * @details
1095  *
1096  *    Function : MacSchSrUciInd
1097  *
1098  *    Functionality:
1099  *      Processes SR UCI indication from MAC
1100  *
1101  * @params[in] Post structure
1102  *             UCI Indication
1103  * @return ROK     - success
1104  *         RFAILED - failure
1105  *
1106  * ****************************************************************/
1107 uint8_t MacSchSrUciInd(Pst *pst, SrUciIndInfo *uciInd)
1108 {
1109    Inst  inst = pst->dstInst-SCH_INST_START;
1110
1111    SchUeCb   *ueCb; 
1112    SchCellCb *cellCb = schCb[inst].cells[inst];
1113
1114 #ifdef CALL_FLOW_DEBUG_LOG
1115    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_UCI_IND_TO_SCH\n");
1116 #endif
1117
1118    DU_LOG("\nDEBUG  -->  SCH : Received SR");
1119
1120    ueCb = schGetUeCb(cellCb, uciInd->crnti);
1121    
1122    if(ueCb->state == SCH_UE_STATE_INACTIVE)
1123    {
1124       DU_LOG("\nERROR  -->  SCH : Crnti %d is inactive", uciInd->crnti);
1125       return ROK;  
1126    }
1127    if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1128    {
1129       DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1130       return ROK;
1131    }
1132    if(uciInd->numSrBits)
1133    {
1134       ueCb->srRcvd = true;
1135       
1136       /* Adding UE Id to list of pending UEs to be scheduled */
1137       addUeToBeScheduled(cellCb, ueCb->ueId);
1138    }
1139    return ROK;
1140 }
1141
1142 /*******************************************************************
1143  *
1144  * @brief Allocates requested PRBs for DL
1145  *
1146  * @details
1147  *
1148  *    Function : allocatePrbDl
1149  *
1150  *    Functionality:
1151  *      Allocates requested PRBs in DL
1152  *      Keeps track of allocated PRB (using bitmap) and remaining PRBs
1153  *
1154  * @params[in] prbAlloc table
1155  *             Start symbol
1156  *             Number of symbols
1157  *             Start PRB
1158  *             Number of PRBs
1159  *
1160  * @return ROK     - success
1161  *         RFAILED - failure
1162  *
1163  * ****************************************************************/
1164 uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
1165    uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1166 {
1167    uint8_t        symbol = 0;
1168    uint16_t       broadcastPrbStart=0, broadcastPrbEnd=0;
1169    FreePrbBlock   *freePrbBlock = NULLP;
1170    CmLList        *freePrbNode = NULLP;
1171    PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
1172    SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1173    SchPrbAlloc    *prbAlloc = &schDlSlotInfo->prbAlloc;
1174
1175    /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1176     * Search for an appropriate location in PRB grid and allocate requested resources */
1177    if(*startPrb == MAX_NUM_RB)
1178    {
1179       /* Check if SSB/SIB1 is also scheduled in this slot  */
1180       ssbOccasion = schCheckSsbOcc(cell, slotTime);
1181       sib1Occasion = schCheckSib1Occ(cell, slotTime);
1182
1183       if(ssbOccasion && sib1Occasion)
1184       {
1185          broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA; 
1186          broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1187       }
1188       else if(ssbOccasion)
1189       {
1190          broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
1191          broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB -1;
1192       }
1193       else if(sib1Occasion)
1194       {
1195          broadcastPrbStart = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.startPrb;
1196          broadcastPrbEnd = broadcastPrbStart + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1197       }
1198
1199       /* Iterate through all free PRB blocks */
1200       freePrbNode = prbAlloc->freePrbBlockList.first; 
1201       while(freePrbNode)
1202       {
1203          freePrbBlock = (FreePrbBlock *)freePrbNode->node; 
1204
1205          /* If broadcast message is scheduled in this slot, then check if its PRBs belong to the current free block.
1206           * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1207          if((ssbOccasion || sib1Occasion) && 
1208             ((broadcastPrbStart >= freePrbBlock->startPrb) && (broadcastPrbStart <= freePrbBlock->endPrb)) && \
1209             ((broadcastPrbEnd >= freePrbBlock->startPrb) && (broadcastPrbEnd <= freePrbBlock->endPrb)))
1210          {
1211             /* Implmentation is done such that highest-numbered free-RB is allocated first */ 
1212             if((freePrbBlock->endPrb > broadcastPrbEnd) && ((freePrbBlock->endPrb - broadcastPrbEnd) >= numPrb))
1213             {
1214                /* If sufficient free PRBs are available above bradcast message then,
1215                 * endPrb = freePrbBlock->endPrb
1216                 * startPrb = endPrb - numPrb +1;
1217                 */
1218                *startPrb = freePrbBlock->endPrb - numPrb +1;
1219                break;
1220             }
1221             else if((broadcastPrbStart > freePrbBlock->startPrb) && ((broadcastPrbStart - freePrbBlock->startPrb) >= numPrb))
1222             {
1223                /* If free PRBs are available below broadcast message then,
1224                 * endPrb = broadcastPrbStart - 1
1225                 * startPrb = endPrb - numPrb +1
1226                 */
1227                *startPrb = broadcastPrbStart - numPrb; 
1228                break;
1229             }
1230             else
1231             {
1232                freePrbNode = freePrbNode->next;
1233                continue;
1234             }
1235          }
1236          else
1237          {
1238             /* Check if requested number of blocks can be allocated from the current block */ 
1239             if (freePrbBlock->numFreePrb < numPrb)
1240             {
1241                freePrbNode = freePrbNode->next;
1242                continue;
1243             }
1244             *startPrb = freePrbBlock->endPrb - numPrb +1;
1245             break;  
1246          }
1247       }
1248
1249       /* If no free block can be used to allocated request number of RBs */
1250       if(*startPrb == MAX_NUM_RB)
1251          return RFAILED;
1252    }
1253
1254    /* If startPrb is known already, check if requested PRBs are available for allocation */
1255    else
1256    {
1257       freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1258       if(!freePrbNode)
1259       {
1260          DU_LOG("\nERROR  -->  SCH: Requested DL PRB unavailable");
1261          return RFAILED;
1262       }
1263    }
1264
1265    /* Update bitmap to allocate PRBs */
1266    for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1267    {
1268       if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1269       {
1270          DU_LOG("\nERROR  -->  SCH: fillPrbBitmap() failed for symbol [%d] in DL", symbol);
1271          return RFAILED;
1272       }
1273    }
1274
1275    /* Update the remaining number for free PRBs */
1276    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1277
1278    return ROK;
1279 }
1280
1281 /*******************************************************************
1282  *
1283  * @brief Allocates requested PRBs for UL
1284  *
1285  * @details
1286  *
1287  *    Function : allocatePrbUl
1288  *
1289  *    Functionality:
1290  *      Allocates requested PRBs in UL
1291  *      Keeps track of allocated PRB (using bitmap) and remaining PRBs
1292  *
1293  * @params[in] prbAlloc table
1294  *             Start symbol
1295  *             Number of symbols
1296  *             Start PRB
1297  *             Number of PRBs
1298  *
1299  * @return ROK     - success
1300  *         RFAILED - failure
1301  *
1302  * ****************************************************************/
1303 uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
1304    uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1305 {
1306    uint8_t        symbol = 0;
1307    uint16_t       prachStartPrb, prachNumPrb, prachEndPrb;
1308    bool           isPrachOccasion;
1309    FreePrbBlock   *freePrbBlock = NULLP;
1310    CmLList        *freePrbNode = NULLP;
1311    SchPrbAlloc    *prbAlloc = NULLP;
1312
1313    if(cell == NULLP)
1314    {
1315       DU_LOG("\nERROR  --> SCH : allocatePrbUl(): Received cellCb is null");
1316       return RFAILED;
1317    }
1318    
1319    prbAlloc =   &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1320    /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1321     * Search for an appropriate location in PRB grid and allocate requested resources */
1322    if(*startPrb == MAX_NUM_RB)
1323    {
1324       /* Check if PRACH is also scheduled in this slot */
1325       isPrachOccasion = schCheckPrachOcc(cell, slotTime);
1326       if(isPrachOccasion)
1327       {
1328          prachStartPrb =  cell->cellCfg.schRachCfg.msg1FreqStart;
1329          prachNumPrb = schCalcPrachNumRb(cell);
1330          prachEndPrb = prachStartPrb + prachNumPrb -1;
1331       }
1332
1333       /* Iterate through all free PRB blocks */
1334       freePrbNode = prbAlloc->freePrbBlockList.first; 
1335       while(freePrbNode)
1336       {
1337          freePrbBlock = (FreePrbBlock *)freePrbNode->node; 
1338
1339          /* If PRACH is scheduled in this slot, then check if its PRBs belong to the current free block.
1340           * PRBs required for PRACH cannot be allocated to any other message */
1341          if((isPrachOccasion) &&
1342             ((prachStartPrb >= freePrbBlock->startPrb) && (prachStartPrb <= freePrbBlock->endPrb)) &&
1343             ((prachEndPrb >= freePrbBlock->startPrb) && (prachEndPrb <= freePrbBlock->endPrb)))
1344          {
1345             /* Implmentation is done such that highest-numbered free-RB is allocated first */ 
1346             if((freePrbBlock->endPrb > prachEndPrb) && ((freePrbBlock->endPrb - prachEndPrb) >= numPrb))
1347             {
1348                /* If sufficient free PRBs are available above PRACH message then,
1349                 * endPrb = freePrbBlock->endPrb
1350                 * startPrb = endPrb - numPrb +1;
1351                 */
1352                *startPrb = freePrbBlock->endPrb - numPrb +1;
1353                break;
1354             }
1355             else if((prachStartPrb > freePrbBlock->startPrb) && ((prachStartPrb - freePrbBlock->startPrb) >= numPrb))
1356             {
1357                /* If free PRBs are available below PRACH message then,
1358                 * endPrb = prachStartPrb - 1
1359                 * startPrb = endPrb - numPrb +1
1360                 */
1361                *startPrb = prachStartPrb - numPrb; 
1362                break;
1363             }
1364             else
1365             {
1366                freePrbNode = freePrbNode->next;
1367                continue;
1368             } 
1369          }
1370          else
1371          {
1372             /* Check if requested number of PRBs can be allocated from currect block */
1373             if(freePrbBlock->numFreePrb < numPrb)
1374             {
1375                freePrbNode = freePrbNode->next;
1376                continue;
1377             }
1378             *startPrb = freePrbBlock->endPrb - numPrb +1;
1379             break;
1380          }
1381       }
1382
1383       /* If no free block can be used to allocated requested number of RBs */
1384       if(*startPrb == MAX_NUM_RB)
1385          return RFAILED;
1386    }
1387    else
1388    {
1389       /* If startPrb is known already, check if requested PRBs are available for allocation */
1390       freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1391       if(!freePrbNode)
1392       {
1393          DU_LOG("\nERROR  -->  SCH: Requested UL PRB unavailable");
1394          return RFAILED;
1395       }
1396    }
1397
1398    /* Update bitmap to allocate PRBs */
1399    for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1400    {
1401       if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1402       {
1403          DU_LOG("\nERROR  -->  SCH: fillPrbBitmap() failed for symbol [%d] in UL", symbol);
1404          return RFAILED;
1405       }
1406    }
1407
1408    /* Update the remaining number for free PRBs */
1409    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1410
1411    return ROK;
1412 }
1413
1414 /*******************************************************************
1415  *
1416  * @brief Add UE to ueToBeScheduled List
1417  *
1418  * @details
1419  *
1420  *    Function : addUeToBeScheduled
1421  *
1422  *    Functionality:
1423  *      Search if UE entry present in the list
1424  *      If yes, return.
1425  *      If no, add UE to the list
1426  *
1427  * @params[in] Cell control block
1428  *             Ue Idx to be added
1429  *
1430  * @return ROK     - success
1431  *         RFAILED - failure
1432  *
1433  * ****************************************************************/
1434 uint8_t addUeToBeScheduled(SchCellCb *cell, uint8_t ueIdToAdd)
1435 {
1436    uint8_t *ueId;
1437    CmLList *node;
1438
1439    /* Search if UE entry is already present in ueToBeScheduled list.
1440     * If yes, another entry for same UE not needed. Hence, return */
1441    node = cell->ueToBeScheduled.first;
1442    while(node)
1443    {
1444       ueId = (uint8_t *)node->node;
1445       if(*ueId == ueIdToAdd)
1446          return ROK;
1447       node = node->next;
1448    }
1449
1450    /* If UE entry not present already, add UE to the end of ueToBeScheduled list */
1451    SCH_ALLOC(ueId, sizeof(uint8_t));
1452    if(!ueId)
1453    {
1454       DU_LOG("\nERROR  -->  SCH : Memory allocation failure in addUeToBeScheduled");
1455       return RFAILED;
1456    }
1457    *ueId = ueIdToAdd;
1458    if(addNodeToLList(&cell->ueToBeScheduled, ueId, NULLP) != ROK)
1459    {
1460       DU_LOG("\nERROR  --> SCH : Failed to add ueId [%d] to cell->ueToBeScheduled list", *ueId);
1461       return RFAILED;
1462    }
1463    return ROK;
1464 }
1465  
1466 /*******************************************************************************
1467  *
1468  * @brief Try to find Best Free Block with Max Num PRB 
1469  *
1470  * @details
1471  *
1472  *    Function : searchLargestFreeBlock
1473  *
1474  *    Functionality:
1475  *     Finds the FreeBlock with MaxNum of FREE PRB considering SSB/SIB1 ocassions.
1476  *
1477  * @params[in] I/P > prbAlloc table (FreeBlock list)
1478  *             I/P > Slot timing Info
1479  *             O/P > Start PRB
1480  *             I/P > Direction (UL/DL)
1481  *       
1482  *
1483  * @return Max Number of Free PRB 
1484  *         If 0, then no Suitable Free Block
1485  *
1486  * ********************************************************************************/
1487
1488 uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_t *startPrb, Direction dir)
1489 {
1490    uint16_t       reservedPrbStart=0, reservedPrbEnd=0, maxFreePRB = 0;
1491    FreePrbBlock   *freePrbBlock = NULLP;
1492    CmLList        *freePrbNode = NULLP;
1493    SchPrbAlloc    *prbAlloc = NULLP;
1494    bool           checkOccasion = FALSE;
1495
1496    *startPrb = 0; /*Initialize the StartPRB to zero*/
1497
1498    /*Based on Direction, Reserved Messsages will differi.e.
1499     * DL >> SSB and SIB1 ocassions wheres for UL, PRACH ocassions to be checked
1500     * and reserved before allocation for dedicated DL/UL msg*/
1501    if(dir == DIR_DL)
1502    {
1503       SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1504       PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
1505
1506       prbAlloc = &schDlSlotInfo->prbAlloc;
1507
1508       ssbOccasion = schCheckSsbOcc(cell, slotTime);
1509       sib1Occasion = schCheckSib1Occ(cell, slotTime);
1510
1511       checkOccasion = TRUE;
1512       if(ssbOccasion && sib1Occasion)
1513       {
1514          reservedPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA; 
1515          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB + \
1516                           cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1517       }
1518       else if(ssbOccasion)
1519       {
1520          reservedPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
1521          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB -1;
1522       }
1523       else if(sib1Occasion)
1524       {
1525          reservedPrbStart = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.startPrb;
1526          reservedPrbEnd = reservedPrbStart + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1527       }
1528       else
1529       {
1530          checkOccasion = FALSE;  
1531       }
1532    }
1533    else if(dir == DIR_UL)
1534    {
1535       prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1536
1537       /* Check if PRACH is also scheduled in this slot */
1538       checkOccasion = schCheckPrachOcc(cell, slotTime);
1539       if(checkOccasion)
1540       {
1541          reservedPrbStart =  cell->cellCfg.schRachCfg.msg1FreqStart;
1542          reservedPrbEnd = reservedPrbStart + (schCalcPrachNumRb(cell)) -1;
1543       }
1544    }
1545    else
1546    {
1547       DU_LOG("\nERROR --> SCH: Invalid Direction!");
1548       return (maxFreePRB);
1549    }
1550
1551    freePrbNode = prbAlloc->freePrbBlockList.first; 
1552    while(freePrbNode)
1553    {
1554       freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1555
1556       /*For block with same numFreeBlocks, choose the one with HighestPRB range
1557        *Since FreeBLockList are arranged in Descending order of PRB range thus Skipping this block*/
1558       if(maxFreePRB >= freePrbBlock->numFreePrb) 
1559       {
1560          //skip this block
1561          freePrbNode = freePrbNode->next;
1562          continue;
1563       }
1564
1565       /* If Broadcast/Prach message is scheduled in this slot, then check if its PRBs belong to the current free block.
1566        * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1567       if(checkOccasion && 
1568             ((reservedPrbStart >= freePrbBlock->startPrb) && (reservedPrbStart <= freePrbBlock->endPrb)) && \
1569             ((reservedPrbEnd >= freePrbBlock->startPrb) && (reservedPrbEnd <= freePrbBlock->endPrb)))
1570       {
1571
1572          /* Implmentation is done such that highest-numbered free-RB is Checked first
1573             and freePRB in this block is greater than Max till now */
1574          if((freePrbBlock->endPrb > reservedPrbEnd) && ((freePrbBlock->endPrb - reservedPrbEnd) > maxFreePRB))
1575          {
1576             /* If sufficient free PRBs are available above reserved message*/
1577             *startPrb = reservedPrbEnd + 1;
1578             maxFreePRB = (freePrbBlock->endPrb - reservedPrbEnd);                
1579          }
1580          /*Also check the other freeBlock (i.e. Above the reserved message) for MAX FREE PRB*/
1581          if((reservedPrbStart > freePrbBlock->startPrb) && ((reservedPrbStart - freePrbBlock->startPrb) > maxFreePRB))
1582          {
1583             /* If free PRBs are available below reserved message*/
1584             *startPrb = freePrbBlock->startPrb;
1585             maxFreePRB = (reservedPrbStart - freePrbBlock->startPrb);
1586          }
1587       }
1588       else  //Best Block
1589       {
1590          if(maxFreePRB < freePrbBlock->numFreePrb)
1591          {
1592             *startPrb = freePrbBlock->startPrb;
1593             maxFreePRB = freePrbBlock->numFreePrb;
1594          }
1595
1596       }
1597       freePrbNode = freePrbNode->next;
1598    }  
1599    return(maxFreePRB);
1600 }
1601
1602 /*******************************************************************************
1603  *
1604  * @brief This function is used to send Slice Cfg rsp to MAC
1605  *
1606  * @details
1607  *
1608  *    Function : SchSendSliceCfgRspToMac
1609  *
1610  *    Functionality:
1611  *     function is used to send Slice Cfg rsp to MAC
1612  *
1613  * @params[in] Pst *pst, SchSliceCfgRsp sliceCfgRsp
1614  *
1615  * @return- void
1616  *
1617  * ********************************************************************************/
1618 void SchSendSliceCfgRspToMac(Inst inst, SchSliceCfgRsp sliceCfgRsp)
1619 {
1620    Pst rspPst;
1621    
1622    memset(&rspPst, 0, sizeof(Pst));
1623    FILL_PST_SCH_TO_MAC(rspPst, inst);
1624    rspPst.event = EVENT_SLICE_CFG_RSP_TO_MAC;
1625    
1626    SchSliceCfgRspOpts[rspPst.selector](&rspPst, &sliceCfgRsp);
1627
1628 }
1629 /*******************************************************************************
1630  *
1631  * @brief fill slice configuration response
1632  *
1633  * @details
1634  *
1635  *    Function : fillSliceCfgRsp
1636  *
1637  *    Functionality:
1638  *     fill slice configuration response
1639  *
1640  * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t  count
1641  *
1642  * @return
1643  *        ROK - Success
1644  *        RFAILED - Failure
1645  *
1646  * ********************************************************************************/
1647 uint8_t fillSliceCfgRsp(bool sliceReCfg, SchSliceCfg *storedSliceCfg, SchCellCb *cellCb, SchSliceCfgReq *schSliceCfgReq, SchSliceCfgRsp *schSliceCfgRsp, uint8_t *count)
1648 {
1649    bool sliceFound = false;
1650    uint8_t cfgIdx = 0, sliceIdx = 0;
1651
1652    schSliceCfgRsp->numSliceCfgRsp  = schSliceCfgReq->numOfConfiguredSlice;
1653    SCH_ALLOC(schSliceCfgRsp->listOfSliceCfgRsp, schSliceCfgRsp->numSliceCfgRsp * sizeof(SliceRsp*));
1654    if(schSliceCfgRsp->listOfSliceCfgRsp == NULLP)
1655    {
1656       DU_LOG("\nERROR  --> SCH : Memory allocation failed at fillSliceCfgRsp");
1657       return RFAILED;
1658    }
1659    
1660    for(cfgIdx = 0; cfgIdx<schSliceCfgRsp->numSliceCfgRsp ; cfgIdx++)
1661    {
1662       sliceFound = false;
1663       /* Here comparing the slice cfg request with the slice stored in cellCfg */
1664       if(sliceReCfg != true)
1665       {
1666          for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList.numSliceSupport; sliceIdx++)
1667          {
1668             if(!memcmp(&schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList.snssai[sliceIdx], sizeof(Snssai)))
1669             {
1670                (*count)++;
1671                sliceFound = true;
1672                break;
1673             }
1674          }
1675       }
1676       else
1677       {
1678          /* Here comparing the slice cfg request with the slice stored in SchDb */
1679          if(storedSliceCfg->listOfConfirguration)
1680          {
1681             for(sliceIdx = 0; sliceIdx<storedSliceCfg->numOfSliceConfigured; sliceIdx++)
1682             {
1683                if(!memcmp(&schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai, &storedSliceCfg->listOfConfirguration[sliceIdx]->snssai,\
1684                         sizeof(Snssai)))
1685                {
1686                   (*count)++;
1687                   sliceFound = true;
1688                   break;
1689                }
1690             }
1691          }
1692       }
1693
1694       SCH_ALLOC(schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx], sizeof(SliceRsp));
1695       if(schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx] == NULLP)
1696       {
1697          DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in fillSliceCfgRsp");
1698          return RFAILED;
1699       }
1700
1701       
1702       schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->snssai = schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai;
1703       if(sliceFound == true)
1704          schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->rsp    = RSP_OK;
1705       else
1706       {
1707          schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->rsp    = RSP_NOK;
1708          schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->cause  = SLICE_NOT_FOUND;
1709       }
1710    }
1711    return ROK;
1712 }
1713
1714 /*******************************************************************************
1715  *
1716  * @brief This function is used to store the slice configuration Sch DB
1717  *
1718  * @details
1719  *
1720  *    Function : addSliceCfgInSchDb 
1721  *
1722  *    Functionality:
1723  *     function is used to store the slice configuration Sch DB
1724  *
1725  * @params[in] SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq,
1726  * SchSliceCfgRsp cfgRsp, uint8_t count
1727  *
1728  * @return
1729  *        ROK - Success
1730  *        RFAILED - Failure
1731  *
1732  * ********************************************************************************/
1733 uint8_t addSliceCfgInSchDb(SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq, SchSliceCfgRsp cfgRsp, uint8_t count)
1734 {
1735    uint8_t cfgIdx = 0, sliceIdx = 0; 
1736    
1737    if(count)
1738    {
1739       storeSliceCfg->numOfSliceConfigured = count;
1740       SCH_ALLOC(storeSliceCfg->listOfConfirguration, storeSliceCfg->numOfSliceConfigured * sizeof(SchRrmPolicyOfSlice*));
1741       if(storeSliceCfg->listOfConfirguration == NULLP)
1742       {
1743          DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in addSliceCfgInSchDb");
1744          return RFAILED;
1745       }
1746
1747       for(cfgIdx = 0; cfgIdx<storeSliceCfg->numOfSliceConfigured; cfgIdx++)
1748       {
1749          if(cfgRsp.listOfSliceCfgRsp[cfgIdx]->rsp == RSP_OK)
1750          {
1751             SCH_ALLOC(storeSliceCfg->listOfConfirguration[sliceIdx], sizeof(SchRrmPolicyOfSlice));
1752             if(storeSliceCfg->listOfConfirguration[sliceIdx] == NULLP)
1753             {
1754                DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in addSliceCfgInSchDb");
1755                return RFAILED;
1756             }
1757
1758             SCH_ALLOC(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1759             if(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo == NULLP)
1760             {
1761                DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in addSliceCfgInSchDb");
1762                return RFAILED;
1763             }
1764
1765             memcpy(&storeSliceCfg->listOfConfirguration[sliceIdx]->snssai, &cfgReq->listOfConfirguration[sliceIdx]->snssai, sizeof(Snssai));
1766             memcpy(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo, cfgReq->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo,
1767                       sizeof(SchRrmPolicyRatio));
1768             sliceIdx++;
1769          }
1770       }
1771    }
1772    return ROK;
1773 }
1774
1775 /*******************************************************************************
1776  *
1777  * @brief This function is used to free the slice cfg and re cfg request pointer
1778  *
1779  * @details
1780  *
1781  *    Function : freeSchSliceCfgReq 
1782  *
1783  *    Functionality:
1784  *     function is used to free the slice cfg and re cfg request pointer
1785  *
1786  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1787  *
1788  * @return
1789  *        ROK - Success
1790  *        RFAILED - Failure
1791  * ********************************************************************************/
1792 void freeSchSliceCfgReq(SchSliceCfgReq *cfgReq)
1793 {
1794    uint8_t cfgIdx = 0;
1795    
1796    if(cfgReq)
1797    {
1798       if(cfgReq->numOfConfiguredSlice)
1799       {
1800          for(cfgIdx = 0; cfgIdx<cfgReq->numOfConfiguredSlice; cfgIdx++)
1801          {
1802             if(cfgReq->listOfConfirguration[cfgIdx])
1803             {
1804                SCH_FREE(cfgReq->listOfConfirguration[cfgIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1805                SCH_FREE(cfgReq->listOfConfirguration[cfgIdx], sizeof(SchRrmPolicyOfSlice));
1806             }
1807          }
1808          SCH_FREE(cfgReq->listOfConfirguration, cfgReq->numOfConfiguredSlice * sizeof(SchRrmPolicyOfSlice*));
1809       }
1810       SCH_FREE(cfgReq, sizeof(SchSliceCfgReq));
1811    }
1812 }
1813 /*******************************************************************************
1814  *
1815  * @brief This function is used to store the slice configuration Sch DB
1816  *
1817  * @details
1818  *
1819  *    Function : MacSchSliceCfgReq 
1820  *
1821  *    Functionality:
1822  *     function is used to store the slice configuration Sch DB
1823  *
1824  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1825  *
1826  * @return
1827  *        ROK - Success
1828  *        RFAILED - Failure
1829  *
1830  * ********************************************************************************/
1831 uint8_t MacSchSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
1832 {
1833    uint8_t count = 0;
1834    Inst   inst = pst->dstInst - SCH_INST_START;
1835    SchSliceCfgRsp sliceCfgRsp;
1836
1837    DU_LOG("\nINFO  -->  SCH : Received Slice Cfg request from MAC");
1838    if(schSliceCfgReq)
1839    {
1840       if(schSliceCfgReq->listOfConfirguration)
1841       {
1842          /* filling the slice configuration response of each slice */
1843          if(fillSliceCfgRsp(false, NULLP, schCb[inst].cells[0], schSliceCfgReq, &sliceCfgRsp, &count) != ROK)
1844          {
1845             DU_LOG("\nERROR  -->  SCH : Failed to fill the slice cfg rsp");
1846             return RFAILED;
1847          }
1848
1849          if(addSliceCfgInSchDb(&schCb[inst].sliceCfg, schSliceCfgReq, sliceCfgRsp, count) != ROK)
1850          {
1851             DU_LOG("\nERROR  -->  SCH : Failed to add slice cfg in sch database");
1852             return RFAILED;
1853          }
1854          freeSchSliceCfgReq(schSliceCfgReq);
1855          SchSendSliceCfgRspToMac(inst, sliceCfgRsp);
1856       }
1857    }
1858    else
1859    {
1860       DU_LOG("\nERROR  -->  SCH : Received SchSliceCfgReq is NULL");
1861    }
1862    return ROK;
1863 }
1864
1865 /*******************************************************************************
1866  *
1867  * @brief This function is used to store the slice reconfiguration Sch DB
1868  *
1869  * @details
1870  *
1871  *    Function : modifySliceCfgInSchDb 
1872  *
1873  *    Functionality:
1874  *     function is used to store the slice re configuration Sch DB
1875  *
1876  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1877  *
1878  * @return
1879  *        ROK - Success
1880  *        RFAILED - Failure
1881  *
1882  * ********************************************************************************/
1883 uint8_t modifySliceCfgInSchDb(SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq, SchSliceCfgRsp cfgRsp, uint8_t count)
1884 {
1885    uint8_t cfgIdx = 0, sliceIdx = 0; 
1886
1887    if(count)
1888    {
1889       if(storeSliceCfg->listOfConfirguration == NULLP)
1890       {
1891          DU_LOG("\nINFO  -->  SCH : Memory allocation failed in modifySliceCfgInSchDb");
1892          return RFAILED;
1893       }
1894
1895       for(cfgIdx = 0; cfgIdx<cfgReq->numOfConfiguredSlice; cfgIdx++)
1896       {
1897          if(cfgRsp.listOfSliceCfgRsp[cfgIdx]->rsp == RSP_OK)
1898          {
1899             for(sliceIdx = 0; sliceIdx<storeSliceCfg->numOfSliceConfigured; sliceIdx++)
1900             {
1901                if(!memcmp(&storeSliceCfg->listOfConfirguration[sliceIdx]->snssai, &cfgReq->listOfConfirguration[cfgIdx]->snssai, sizeof(Snssai)))
1902                {
1903                   memcpy(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo, cfgReq->listOfConfirguration[cfgIdx]->rrmPolicyRatioInfo,
1904                            sizeof(SchRrmPolicyRatio));
1905                   break;
1906                }
1907             }
1908          }
1909       }
1910    }
1911    freeSchSliceCfgReq(cfgReq);
1912    return ROK;
1913 }
1914 /*******************************************************************************
1915  *
1916  * @brief This function is used to send Slice re Cfg rsp to MAC
1917  *
1918  * @details
1919  *
1920  *    Function : SchSendSliceCfgRspToMac
1921  *
1922  *    Functionality:
1923  *     function is used to send Slice re Cfg rsp to MAC
1924  *
1925  * @params[in] Pst *pst, SchSliceCfgRsp schSliceReCfgRsp
1926  *
1927  * @return- void
1928  *
1929  * ********************************************************************************/
1930 void SchSendSliceReCfgRspToMac(Inst inst, SchSliceCfgRsp schSliceReCfgRsp)
1931 {
1932    Pst rspPst;
1933    
1934    memset(&rspPst, 0, sizeof(Pst));
1935    FILL_PST_SCH_TO_MAC(rspPst, inst);
1936    rspPst.event = EVENT_SLICE_RECFG_RSP_TO_MAC;
1937    
1938    SchSliceReCfgRspOpts[rspPst.selector](&rspPst, &schSliceReCfgRsp);
1939 }
1940 /*******************************************************************************
1941  *
1942  * @brief This function is used to store the slice reconfiguration Sch DB
1943  *
1944  * @details
1945  *
1946  *    Function : MacSchSliceReCfgReq 
1947  *
1948  *    Functionality:
1949  *     function is used to store the slice re configuration Sch DB
1950  *
1951  * @params[in] Pst *pst, SchSliceCfgReq *schSliceReCfgReq
1952  *
1953  * @return
1954  *        ROK - Success
1955  *        RFAILED - Failure
1956  *
1957  * ********************************************************************************/
1958 uint8_t MacSchSliceReCfgReq(Pst *pst, SchSliceCfgReq *schSliceReCfgReq)
1959 {
1960    uint8_t count = 0;
1961    Inst   inst = pst->dstInst - SCH_INST_START;
1962    SchSliceCfgRsp schSliceReCfgRsp;
1963
1964    DU_LOG("\nINFO  -->  SCH : Received Slice ReCfg request from MAC");
1965    if(schSliceReCfgReq)
1966    {
1967       if(schSliceReCfgReq->listOfConfirguration)
1968       {
1969          /* filling the slice configuration response of each slice */
1970          if(fillSliceCfgRsp(true, &schCb[inst].sliceCfg, NULLP, schSliceReCfgReq, &schSliceReCfgRsp, &count) != ROK)
1971          {
1972             DU_LOG("\nERROR  -->  SCH : Failed to fill sch slice cfg response");
1973             return RFAILED;
1974          }
1975          
1976          /* Modify the slice configuration stored in schCb */
1977          if(modifySliceCfgInSchDb(&schCb[inst].sliceCfg, schSliceReCfgReq, schSliceReCfgRsp, count) != ROK)
1978          {
1979             DU_LOG("\nERROR  -->  SCH : Failed to modify slice cfg of SchDb");
1980             return RFAILED;
1981          }
1982          SchSendSliceReCfgRspToMac(inst, schSliceReCfgRsp);
1983       }
1984    }
1985    else
1986    {
1987       DU_LOG("\nERROR  -->  SCH : Received SchSliceCfgReq is NULL");
1988    }
1989    return ROK;
1990 }
1991
1992 /****************************************************************************
1993  *
1994  * @brief Stores the Paging Configuration from DU APP in CellCb 
1995  *
1996  * @details
1997  *
1998  *    Function : schProcPagingParam
1999  *
2000  *    Functionality:
2001  *          Process the Paging Configuration when FirstPDCCHMonitoring for
2002  *          Paging Ocassion is not present.
2003  *
2004  *          As per 38.304 Sec 7.1,
2005  *          "When firstPDCCH-MonitoringOccasionOfPO is present, the
2006  *          starting PDCCH monitoring occasion number of (i_s + 1)th PO is the
2007  *          (i_s + 1)th value of the firstPDCCHMonitoringOccasionOfPO
2008  *          parameter; otherwise, it is equal to i_s * S."
2009  *          "S = number of actual transmitted SSBs determined according 
2010  *              to ssb-PositionsInBurst in SIB1"
2011  *
2012  * @params[in] SchCellCb *cell 
2013  *       
2014  * @return void 
2015  *        
2016  *************************************************************************/
2017 void schProcPagingCfg(SchCellCb *cell)
2018 {
2019    PageCfg *pageCfgRcvd = NULL;
2020    uint8_t i_sIdx = 0;
2021
2022    pageCfgRcvd = &(cell->cellCfg.sib1SchCfg.pageCfg);
2023
2024    if(pageCfgRcvd->poPresent == TRUE)
2025    {
2026       /*Fetching first Pdcch Monitoring Occasion for SFN (i_s + 1)th*/
2027       for(i_sIdx = 0; i_sIdx < pageCfgRcvd->numPO; i_sIdx++)
2028       {
2029          cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pageCfgRcvd->pagingOcc[i_sIdx] / MAX_SYMB_PER_SLOT ;
2030          if ((pageCfgRcvd->pagingOcc[i_sIdx] % MAX_SYMB_PER_SLOT) != 0 )
2031          {
2032             cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot++;
2033          }
2034
2035          cell->pageCb.pagMonOcc[i_sIdx].frameOffset = 0;
2036
2037       }
2038    }
2039    else
2040    {
2041       schCfgPdcchMonOccOfPO(cell);                  
2042    }
2043 }
2044
2045 /****************************************************************************
2046  *
2047  * @brief Calculate PO if not present in Configuration 
2048  *
2049  * @details
2050  *
2051  *    Function : schCfgPdcchMonOccOfPO
2052  *
2053  *    Functionality: In this function, PO are calculated i_s * S because
2054  *    FirstPDCCHMonitoring_ForPO is not present.
2055  *
2056  * @params[in] SchCellCb *cellCb
2057  *       
2058  * @return void 
2059  *        
2060  *************************************************************************/
2061 void schCfgPdcchMonOccOfPO(SchCellCb *cell)
2062 {
2063    uint8_t         cnt = 0, incr = 1, i_sIdx = 0, frameOffSet = 0;
2064    uint8_t         nsValue = cell->cellCfg.sib1SchCfg.pageCfg.numPO;
2065    uint8_t         totalNumSsb = cell->cellCfg.ssbSchCfg.totNumSsb;
2066    SlotTimingInfo  tmpTimingInfo, pdcchTime; 
2067
2068    /*Starting with First Sfn and slot*/
2069    tmpTimingInfo.sfn = 0;
2070    tmpTimingInfo.slot = 0;
2071
2072    pdcchTime = tmpTimingInfo;
2073
2074    while(i_sIdx < nsValue)
2075    {
2076       /*Increment frame Offset if PO falls on next SFN*/
2077       if(pdcchTime.sfn != tmpTimingInfo.sfn)
2078       {
2079          frameOffSet++;
2080       }
2081       pdcchTime = tmpTimingInfo;
2082       schIncrSlot(&(tmpTimingInfo), incr, cell->numSlots);
2083
2084       if (i_sIdx == 0)
2085       {
2086          cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2087          cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2088          i_sIdx++;
2089       }
2090       else
2091       {
2092          cnt++;
2093          if((cnt == totalNumSsb) && (i_sIdx < MAX_PO_PER_PF)) 
2094          {
2095             cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2096             cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2097             cnt = 0;
2098             i_sIdx++;
2099          }
2100       }
2101    }
2102 }
2103
2104 /**********************************************************************
2105   End of file
2106  **********************************************************************/