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