[Epic-ID: ODUHIGH-406][Task-ID: ODUHIGH-423]Fix for incorrect access of schCb instance
[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    lcId  = dlBoInfo->lcId;
966    CHECK_LCID(lcId, isLcIdValid);
967    if(isLcIdValid == FALSE)
968    {
969       DU_LOG("ERROR --> SCH: LCID:%d is not valid", lcId);
970       return RFAILED;
971    }
972
973    /*Expected when theres a case of Retransmission Failure or Resetablishment
974     *By Zero BO, the RLC is informing that previous data can be cleared out
975     *Thus clearing out the LC from the Lc priority list*/
976    if(dlBoInfo->dataVolume == 0)
977    {
978       /*Check the LC is Dedicated or default and accordingly LCList will
979        * be used*/
980       if(ueCb->dlInfo.dlLcCtxt[lcId].isDedicated)
981       {
982          lcLL = &(ueCb->dlLcPrbEst.dedLcInfo->dedLcList);
983       }
984       else
985       {
986          lcLL = &(ueCb->dlLcPrbEst.defLcList);
987       }
988       handleLcLList(lcLL, lcId, DELETE);
989       return ROK;
990    }
991
992    if(lcId == SRB0_LCID)
993    {
994       cell->raCb[ueId -1].msg4recvd = true;
995       cell->raCb[ueId -1].dlMsgPduLen = dlBoInfo->dataVolume;
996       
997    }
998    else
999    {
1000       /* TODO : These part of changes will be corrected during DL scheduling as
1001        * per K0 - K1 -K2 */
1002       SET_ONE_BIT(ueId, cell->boIndBitMap);
1003       if(ueCb->dlInfo.dlLcCtxt[lcId].lcId == lcId)
1004       {
1005          ueCb->dlInfo.dlLcCtxt[lcId].bo = dlBoInfo->dataVolume;
1006       }
1007       else
1008       {
1009          DU_LOG("ERROR --> SCH: LCID:%d is not configured in SCH Cb",lcId);
1010          return RFAILED;
1011       }
1012    }
1013    
1014    /* Adding UE Id to list of pending UEs to be scheduled */
1015    addUeToBeScheduled(cell, ueId);
1016    return ROK;
1017 }
1018
1019 /*******************************************************************
1020  *
1021  * @brief Processes BSR indiation from MAC
1022  *
1023  * @details
1024  *
1025  *    Function : MacSchBsr
1026  *
1027  *    Functionality:
1028  *       Processes DL BSR from MAC
1029  *
1030  * @params[in]    Pst pst
1031  *                UlBufferStatusRptInd bsrInd
1032  * @return ROK     - success
1033  *         RFAILED - failure
1034  *
1035  * ****************************************************************/
1036 uint8_t MacSchBsr(Pst *pst, UlBufferStatusRptInd *bsrInd)
1037 {
1038    Inst           schInst       = pst->dstInst-SCH_INST_START;
1039    SchCellCb      *cellCb       = NULLP;
1040    SchUeCb        *ueCb         = NULLP;
1041    uint8_t        lcgIdx = 0;
1042
1043 #ifdef CALL_FLOW_DEBUG_LOG
1044    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_SHORT_BSR\n");
1045 #endif
1046
1047    DU_LOG("\nDEBUG  -->  SCH : Received BSR");
1048    if(bsrInd == NULLP)
1049    {
1050       DU_LOG("\nERROR  -->  SCH : BSR Ind is empty");
1051       return RFAILED;
1052    }
1053    cellCb = schCb[schInst].cells[schInst];
1054    if(cellCb == NULLP)
1055    {
1056       DU_LOG("\nERROR  -->  SCH : CellCb is empty");
1057       return RFAILED;
1058    }
1059    ueCb = schGetUeCb(cellCb, bsrInd->crnti);
1060
1061    if(ueCb == NULLP)
1062    {
1063       DU_LOG("\nERROR  -->  SCH : UeCB is empty");
1064       return RFAILED;
1065    }
1066
1067    ueCb->bsrRcvd = true;
1068    /* store dataVolume per lcg in uecb */
1069    for(lcgIdx = 0; lcgIdx < bsrInd->numLcg; lcgIdx++)
1070    {
1071       ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].priority = 1; //TODO: determining LCG priority?
1072       ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].dataVol = bsrInd->dataVolInfo[lcgIdx].dataVol;
1073    }
1074    
1075    /* Adding UE Id to list of pending UEs to be scheduled */
1076    addUeToBeScheduled(cellCb, ueCb->ueId);
1077    return ROK;
1078 }
1079
1080 /*******************************************************************
1081  *
1082  * @brief Processes SR UCI indication from MAC 
1083  *
1084  * @details
1085  *
1086  *    Function : MacSchSrUciInd
1087  *
1088  *    Functionality:
1089  *      Processes SR UCI indication from MAC
1090  *
1091  * @params[in] Post structure
1092  *             UCI Indication
1093  * @return ROK     - success
1094  *         RFAILED - failure
1095  *
1096  * ****************************************************************/
1097 uint8_t MacSchSrUciInd(Pst *pst, SrUciIndInfo *uciInd)
1098 {
1099    Inst  inst = pst->dstInst-SCH_INST_START;
1100
1101    SchUeCb   *ueCb; 
1102    SchCellCb *cellCb = schCb[inst].cells[inst];
1103
1104 #ifdef CALL_FLOW_DEBUG_LOG
1105    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_UCI_IND_TO_SCH\n");
1106 #endif
1107
1108    DU_LOG("\nDEBUG  -->  SCH : Received SR");
1109
1110    ueCb = schGetUeCb(cellCb, uciInd->crnti);
1111    
1112    if(ueCb->state == SCH_UE_STATE_INACTIVE)
1113    {
1114       DU_LOG("\nERROR  -->  SCH : Crnti %d is inactive", uciInd->crnti);
1115       return ROK;  
1116    }
1117
1118    if(uciInd->numSrBits)
1119    {
1120       ueCb->srRcvd = true;
1121       
1122       /* Adding UE Id to list of pending UEs to be scheduled */
1123       addUeToBeScheduled(cellCb, ueCb->ueId);
1124    }
1125    return ROK;
1126 }
1127
1128 /*******************************************************************
1129  *
1130  * @brief Allocates requested PRBs for DL
1131  *
1132  * @details
1133  *
1134  *    Function : allocatePrbDl
1135  *
1136  *    Functionality:
1137  *      Allocates requested PRBs in DL
1138  *      Keeps track of allocated PRB (using bitmap) and remaining PRBs
1139  *
1140  * @params[in] prbAlloc table
1141  *             Start symbol
1142  *             Number of symbols
1143  *             Start PRB
1144  *             Number of PRBs
1145  *
1146  * @return ROK     - success
1147  *         RFAILED - failure
1148  *
1149  * ****************************************************************/
1150 uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
1151    uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1152 {
1153    uint8_t        symbol = 0;
1154    uint16_t       broadcastPrbStart=0, broadcastPrbEnd=0;
1155    FreePrbBlock   *freePrbBlock = NULLP;
1156    CmLList        *freePrbNode = NULLP;
1157    PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
1158    SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1159    SchPrbAlloc    *prbAlloc = &schDlSlotInfo->prbAlloc;
1160
1161    /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1162     * Search for an appropriate location in PRB grid and allocate requested resources */
1163    if(*startPrb == MAX_NUM_RB)
1164    {
1165       /* Check if SSB/SIB1 is also scheduled in this slot  */
1166       ssbOccasion = schCheckSsbOcc(cell, slotTime);
1167       sib1Occasion = schCheckSib1Occ(cell, slotTime);
1168
1169       if(ssbOccasion && sib1Occasion)
1170       {
1171          broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA; 
1172          broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1173       }
1174       else if(ssbOccasion)
1175       {
1176          broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
1177          broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB -1;
1178       }
1179       else if(sib1Occasion)
1180       {
1181          broadcastPrbStart = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.startPrb;
1182          broadcastPrbEnd = broadcastPrbStart + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1183       }
1184
1185       /* Iterate through all free PRB blocks */
1186       freePrbNode = prbAlloc->freePrbBlockList.first; 
1187       while(freePrbNode)
1188       {
1189          freePrbBlock = (FreePrbBlock *)freePrbNode->node; 
1190
1191          /* If broadcast message is scheduled in this slot, then check if its PRBs belong to the current free block.
1192           * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1193          if((ssbOccasion || sib1Occasion) && 
1194             ((broadcastPrbStart >= freePrbBlock->startPrb) && (broadcastPrbStart <= freePrbBlock->endPrb)) && \
1195             ((broadcastPrbEnd >= freePrbBlock->startPrb) && (broadcastPrbEnd <= freePrbBlock->endPrb)))
1196          {
1197             /* Implmentation is done such that highest-numbered free-RB is allocated first */ 
1198             if((freePrbBlock->endPrb > broadcastPrbEnd) && ((freePrbBlock->endPrb - broadcastPrbEnd) >= numPrb))
1199             {
1200                /* If sufficient free PRBs are available above bradcast message then,
1201                 * endPrb = freePrbBlock->endPrb
1202                 * startPrb = endPrb - numPrb +1;
1203                 */
1204                *startPrb = freePrbBlock->endPrb - numPrb +1;
1205                break;
1206             }
1207             else if((broadcastPrbStart > freePrbBlock->startPrb) && ((broadcastPrbStart - freePrbBlock->startPrb) >= numPrb))
1208             {
1209                /* If free PRBs are available below broadcast message then,
1210                 * endPrb = broadcastPrbStart - 1
1211                 * startPrb = endPrb - numPrb +1
1212                 */
1213                *startPrb = broadcastPrbStart - numPrb; 
1214                break;
1215             }
1216             else
1217             {
1218                freePrbNode = freePrbNode->next;
1219                continue;
1220             }
1221          }
1222          else
1223          {
1224             /* Check if requested number of blocks can be allocated from the current block */ 
1225             if (freePrbBlock->numFreePrb < numPrb)
1226             {
1227                freePrbNode = freePrbNode->next;
1228                continue;
1229             }
1230             *startPrb = freePrbBlock->endPrb - numPrb +1;
1231             break;  
1232          }
1233       }
1234
1235       /* If no free block can be used to allocated request number of RBs */
1236       if(*startPrb == MAX_NUM_RB)
1237          return RFAILED;
1238    }
1239
1240    /* If startPrb is known already, check if requested PRBs are available for allocation */
1241    else
1242    {
1243       freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1244       if(!freePrbNode)
1245       {
1246          DU_LOG("\nERROR  -->  SCH: Requested DL PRB unavailable");
1247          return RFAILED;
1248       }
1249    }
1250
1251    /* Update bitmap to allocate PRBs */
1252    for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1253    {
1254       if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1255       {
1256          DU_LOG("\nERROR  -->  SCH: fillPrbBitmap() failed for symbol [%d] in DL", symbol);
1257          return RFAILED;
1258       }
1259    }
1260
1261    /* Update the remaining number for free PRBs */
1262    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1263
1264    return ROK;
1265 }
1266
1267 /*******************************************************************
1268  *
1269  * @brief Allocates requested PRBs for UL
1270  *
1271  * @details
1272  *
1273  *    Function : allocatePrbUl
1274  *
1275  *    Functionality:
1276  *      Allocates requested PRBs in UL
1277  *      Keeps track of allocated PRB (using bitmap) and remaining PRBs
1278  *
1279  * @params[in] prbAlloc table
1280  *             Start symbol
1281  *             Number of symbols
1282  *             Start PRB
1283  *             Number of PRBs
1284  *
1285  * @return ROK     - success
1286  *         RFAILED - failure
1287  *
1288  * ****************************************************************/
1289 uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
1290    uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1291 {
1292    uint8_t        symbol = 0;
1293    uint16_t       prachStartPrb, prachNumPrb, prachEndPrb;
1294    bool           isPrachOccasion;
1295    FreePrbBlock   *freePrbBlock = NULLP;
1296    CmLList        *freePrbNode = NULLP;
1297    SchPrbAlloc    *prbAlloc = NULLP;
1298
1299    if(cell == NULLP)
1300    {
1301       DU_LOG("\nERROR  --> SCH : allocatePrbUl(): Received cellCb is null");
1302       return RFAILED;
1303    }
1304    
1305    prbAlloc =   &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1306    /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1307     * Search for an appropriate location in PRB grid and allocate requested resources */
1308    if(*startPrb == MAX_NUM_RB)
1309    {
1310       /* Check if PRACH is also scheduled in this slot */
1311       isPrachOccasion = schCheckPrachOcc(cell, slotTime);
1312       if(isPrachOccasion)
1313       {
1314          prachStartPrb =  cell->cellCfg.schRachCfg.msg1FreqStart;
1315          prachNumPrb = schCalcPrachNumRb(cell);
1316          prachEndPrb = prachStartPrb + prachNumPrb -1;
1317       }
1318
1319       /* Iterate through all free PRB blocks */
1320       freePrbNode = prbAlloc->freePrbBlockList.first; 
1321       while(freePrbNode)
1322       {
1323          freePrbBlock = (FreePrbBlock *)freePrbNode->node; 
1324
1325          /* If PRACH is scheduled in this slot, then check if its PRBs belong to the current free block.
1326           * PRBs required for PRACH cannot be allocated to any other message */
1327          if((isPrachOccasion) &&
1328             ((prachStartPrb >= freePrbBlock->startPrb) && (prachStartPrb <= freePrbBlock->endPrb)) &&
1329             ((prachEndPrb >= freePrbBlock->startPrb) && (prachEndPrb <= freePrbBlock->endPrb)))
1330          {
1331             /* Implmentation is done such that highest-numbered free-RB is allocated first */ 
1332             if((freePrbBlock->endPrb > prachEndPrb) && ((freePrbBlock->endPrb - prachEndPrb) >= numPrb))
1333             {
1334                /* If sufficient free PRBs are available above PRACH message then,
1335                 * endPrb = freePrbBlock->endPrb
1336                 * startPrb = endPrb - numPrb +1;
1337                 */
1338                *startPrb = freePrbBlock->endPrb - numPrb +1;
1339                break;
1340             }
1341             else if((prachStartPrb > freePrbBlock->startPrb) && ((prachStartPrb - freePrbBlock->startPrb) >= numPrb))
1342             {
1343                /* If free PRBs are available below PRACH message then,
1344                 * endPrb = prachStartPrb - 1
1345                 * startPrb = endPrb - numPrb +1
1346                 */
1347                *startPrb = prachStartPrb - numPrb; 
1348                break;
1349             }
1350             else
1351             {
1352                freePrbNode = freePrbNode->next;
1353                continue;
1354             } 
1355          }
1356          else
1357          {
1358             /* Check if requested number of PRBs can be allocated from currect block */
1359             if(freePrbBlock->numFreePrb < numPrb)
1360             {
1361                freePrbNode = freePrbNode->next;
1362                continue;
1363             }
1364             *startPrb = freePrbBlock->endPrb - numPrb +1;
1365             break;
1366          }
1367       }
1368
1369       /* If no free block can be used to allocated requested number of RBs */
1370       if(*startPrb == MAX_NUM_RB)
1371          return RFAILED;
1372    }
1373    else
1374    {
1375       /* If startPrb is known already, check if requested PRBs are available for allocation */
1376       freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1377       if(!freePrbNode)
1378       {
1379          DU_LOG("\nERROR  -->  SCH: Requested UL PRB unavailable");
1380          return RFAILED;
1381       }
1382    }
1383
1384    /* Update bitmap to allocate PRBs */
1385    for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1386    {
1387       if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1388       {
1389          DU_LOG("\nERROR  -->  SCH: fillPrbBitmap() failed for symbol [%d] in UL", symbol);
1390          return RFAILED;
1391       }
1392    }
1393
1394    /* Update the remaining number for free PRBs */
1395    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1396
1397    return ROK;
1398 }
1399
1400 /*******************************************************************
1401  *
1402  * @brief Add UE to ueToBeScheduled List
1403  *
1404  * @details
1405  *
1406  *    Function : addUeToBeScheduled
1407  *
1408  *    Functionality:
1409  *      Search if UE entry present in the list
1410  *      If yes, return.
1411  *      If no, add UE to the list
1412  *
1413  * @params[in] Cell control block
1414  *             Ue Idx to be added
1415  *
1416  * @return ROK     - success
1417  *         RFAILED - failure
1418  *
1419  * ****************************************************************/
1420 uint8_t addUeToBeScheduled(SchCellCb *cell, uint8_t ueIdToAdd)
1421 {
1422    uint8_t *ueId;
1423    CmLList *node;
1424
1425    /* Search if UE entry is already present in ueToBeScheduled list.
1426     * If yes, another entry for same UE not needed. Hence, return */
1427    node = cell->ueToBeScheduled.first;
1428    while(node)
1429    {
1430       ueId = (uint8_t *)node->node;
1431       if(*ueId == ueIdToAdd)
1432          return ROK;
1433       node = node->next;
1434    }
1435
1436    /* If UE entry not present already, add UE to the end of ueToBeScheduled list */
1437    SCH_ALLOC(ueId, sizeof(uint8_t));
1438    if(!ueId)
1439    {
1440       DU_LOG("\nERROR  -->  SCH : Memory allocation failure in addUeToBeScheduled");
1441       return RFAILED;
1442    }
1443    *ueId = ueIdToAdd;
1444    if(addNodeToLList(&cell->ueToBeScheduled, ueId, NULLP) != ROK)
1445    {
1446       DU_LOG("\nERROR  --> SCH : Failed to add ueId [%d] to cell->ueToBeScheduled list", *ueId);
1447       return RFAILED;
1448    }
1449    return ROK;
1450 }
1451  
1452 /*******************************************************************************
1453  *
1454  * @brief Try to find Best Free Block with Max Num PRB 
1455  *
1456  * @details
1457  *
1458  *    Function : searchLargestFreeBlock
1459  *
1460  *    Functionality:
1461  *     Finds the FreeBlock with MaxNum of FREE PRB considering SSB/SIB1 ocassions.
1462  *
1463  * @params[in] I/P > prbAlloc table (FreeBlock list)
1464  *             I/P > Slot timing Info
1465  *             O/P > Start PRB
1466  *             I/P > Direction (UL/DL)
1467  *       
1468  *
1469  * @return Max Number of Free PRB 
1470  *         If 0, then no Suitable Free Block
1471  *
1472  * ********************************************************************************/
1473
1474 uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_t *startPrb, Direction dir)
1475 {
1476    uint16_t       reservedPrbStart=0, reservedPrbEnd=0, maxFreePRB = 0;
1477    FreePrbBlock   *freePrbBlock = NULLP;
1478    CmLList        *freePrbNode = NULLP;
1479    SchPrbAlloc    *prbAlloc = NULLP;
1480    bool           checkOccasion = FALSE;
1481
1482    *startPrb = 0; /*Initialize the StartPRB to zero*/
1483
1484    /*Based on Direction, Reserved Messsages will differi.e.
1485     * DL >> SSB and SIB1 ocassions wheres for UL, PRACH ocassions to be checked
1486     * and reserved before allocation for dedicated DL/UL msg*/
1487    if(dir == DIR_DL)
1488    {
1489       SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1490       PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
1491
1492       prbAlloc = &schDlSlotInfo->prbAlloc;
1493
1494       ssbOccasion = schCheckSsbOcc(cell, slotTime);
1495       sib1Occasion = schCheckSib1Occ(cell, slotTime);
1496
1497       checkOccasion = TRUE;
1498       if(ssbOccasion && sib1Occasion)
1499       {
1500          reservedPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA; 
1501          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB + \
1502                           cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1503       }
1504       else if(ssbOccasion)
1505       {
1506          reservedPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
1507          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB -1;
1508       }
1509       else if(sib1Occasion)
1510       {
1511          reservedPrbStart = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.startPrb;
1512          reservedPrbEnd = reservedPrbStart + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1513       }
1514       else
1515       {
1516          checkOccasion = FALSE;  
1517       }
1518    }
1519    else if(dir == DIR_UL)
1520    {
1521       prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1522
1523       /* Check if PRACH is also scheduled in this slot */
1524       checkOccasion = schCheckPrachOcc(cell, slotTime);
1525       if(checkOccasion)
1526       {
1527          reservedPrbStart =  cell->cellCfg.schRachCfg.msg1FreqStart;
1528          reservedPrbEnd = reservedPrbStart + (schCalcPrachNumRb(cell)) -1;
1529       }
1530    }
1531    else
1532    {
1533       DU_LOG("\nERROR --> SCH: Invalid Direction!");
1534       return (maxFreePRB);
1535    }
1536
1537    freePrbNode = prbAlloc->freePrbBlockList.first; 
1538    while(freePrbNode)
1539    {
1540       freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1541
1542       /*For block with same numFreeBlocks, choose the one with HighestPRB range
1543        *Since FreeBLockList are arranged in Descending order of PRB range thus Skipping this block*/
1544       if(maxFreePRB >= freePrbBlock->numFreePrb) 
1545       {
1546          //skip this block
1547          freePrbNode = freePrbNode->next;
1548          continue;
1549       }
1550
1551       /* If Broadcast/Prach message is scheduled in this slot, then check if its PRBs belong to the current free block.
1552        * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1553       if(checkOccasion && 
1554             ((reservedPrbStart >= freePrbBlock->startPrb) && (reservedPrbStart <= freePrbBlock->endPrb)) && \
1555             ((reservedPrbEnd >= freePrbBlock->startPrb) && (reservedPrbEnd <= freePrbBlock->endPrb)))
1556       {
1557
1558          /* Implmentation is done such that highest-numbered free-RB is Checked first
1559             and freePRB in this block is greater than Max till now */
1560          if((freePrbBlock->endPrb > reservedPrbEnd) && ((freePrbBlock->endPrb - reservedPrbEnd) > maxFreePRB))
1561          {
1562             /* If sufficient free PRBs are available above reserved message*/
1563             *startPrb = reservedPrbEnd + 1;
1564             maxFreePRB = (freePrbBlock->endPrb - reservedPrbEnd);                
1565          }
1566          /*Also check the other freeBlock (i.e. Above the reserved message) for MAX FREE PRB*/
1567          if((reservedPrbStart > freePrbBlock->startPrb) && ((reservedPrbStart - freePrbBlock->startPrb) > maxFreePRB))
1568          {
1569             /* If free PRBs are available below reserved message*/
1570             *startPrb = freePrbBlock->startPrb;
1571             maxFreePRB = (reservedPrbStart - freePrbBlock->startPrb);
1572          }
1573       }
1574       else  //Best Block
1575       {
1576          if(maxFreePRB < freePrbBlock->numFreePrb)
1577          {
1578             *startPrb = freePrbBlock->startPrb;
1579             maxFreePRB = freePrbBlock->numFreePrb;
1580          }
1581
1582       }
1583       freePrbNode = freePrbNode->next;
1584    }  
1585    return(maxFreePRB);
1586 }
1587
1588 /*******************************************************************************
1589  *
1590  * @brief This function is used to send Slice Cfg rsp to MAC
1591  *
1592  * @details
1593  *
1594  *    Function : SchSendSliceCfgRspToMac
1595  *
1596  *    Functionality:
1597  *     function is used to send Slice Cfg rsp to MAC
1598  *
1599  * @params[in] Pst *pst, SchSliceCfgRsp sliceCfgRsp
1600  *
1601  * @return- void
1602  *
1603  * ********************************************************************************/
1604 void SchSendSliceCfgRspToMac(Inst inst, SchSliceCfgRsp sliceCfgRsp)
1605 {
1606    Pst rspPst;
1607    
1608    memset(&rspPst, 0, sizeof(Pst));
1609    FILL_PST_SCH_TO_MAC(rspPst, inst);
1610    rspPst.event = EVENT_SLICE_CFG_RSP_TO_MAC;
1611    
1612    SchSliceCfgRspOpts[rspPst.selector](&rspPst, &sliceCfgRsp);
1613
1614 }
1615 /*******************************************************************************
1616  *
1617  * @brief fill slice configuration response
1618  *
1619  * @details
1620  *
1621  *    Function : fillSliceCfgRsp
1622  *
1623  *    Functionality:
1624  *     fill slice configuration response
1625  *
1626  * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t  count
1627  *
1628  * @return
1629  *        ROK - Success
1630  *        RFAILED - Failure
1631  *
1632  * ********************************************************************************/
1633 uint8_t fillSliceCfgRsp(bool sliceReCfg, SchSliceCfg *storedSliceCfg, SchCellCb *cellCb, SchSliceCfgReq *schSliceCfgReq, SchSliceCfgRsp *schSliceCfgRsp, uint8_t *count)
1634 {
1635    bool sliceFound = false;
1636    uint8_t cfgIdx = 0, sliceIdx = 0;
1637
1638    schSliceCfgRsp->numSliceCfgRsp  = schSliceCfgReq->numOfConfiguredSlice;
1639    SCH_ALLOC(schSliceCfgRsp->listOfSliceCfgRsp, schSliceCfgRsp->numSliceCfgRsp * sizeof(SliceRsp*));
1640    if(schSliceCfgRsp->listOfSliceCfgRsp == NULLP)
1641    {
1642       DU_LOG("\nERROR  --> SCH : Memory allocation failed at fillSliceCfgRsp");
1643       return RFAILED;
1644    }
1645    
1646    for(cfgIdx = 0; cfgIdx<schSliceCfgRsp->numSliceCfgRsp ; cfgIdx++)
1647    {
1648       sliceFound = false;
1649       /* Here comparing the slice cfg request with the slice stored in cellCfg */
1650       if(sliceReCfg != true)
1651       {
1652          for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList.numSliceSupport; sliceIdx++)
1653          {
1654             if(!memcmp(&schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList.snssai[sliceIdx], sizeof(Snssai)))
1655             {
1656                (*count)++;
1657                sliceFound = true;
1658                break;
1659             }
1660          }
1661       }
1662       else
1663       {
1664          /* Here comparing the slice cfg request with the slice stored in SchDb */
1665          if(storedSliceCfg->listOfConfirguration)
1666          {
1667             for(sliceIdx = 0; sliceIdx<storedSliceCfg->numOfSliceConfigured; sliceIdx++)
1668             {
1669                if(!memcmp(&schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai, &storedSliceCfg->listOfConfirguration[sliceIdx]->snssai,\
1670                         sizeof(Snssai)))
1671                {
1672                   (*count)++;
1673                   sliceFound = true;
1674                   break;
1675                }
1676             }
1677          }
1678       }
1679
1680       SCH_ALLOC(schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx], sizeof(SliceRsp));
1681       if(schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx] == NULLP)
1682       {
1683          DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in fillSliceCfgRsp");
1684          return RFAILED;
1685       }
1686
1687       
1688       schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->snssai = schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai;
1689       if(sliceFound == true)
1690          schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->rsp    = RSP_OK;
1691       else
1692       {
1693          schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->rsp    = RSP_NOK;
1694          schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->cause  = SLICE_NOT_FOUND;
1695       }
1696    }
1697    return ROK;
1698 }
1699
1700 /*******************************************************************************
1701  *
1702  * @brief This function is used to store the slice configuration Sch DB
1703  *
1704  * @details
1705  *
1706  *    Function : addSliceCfgInSchDb 
1707  *
1708  *    Functionality:
1709  *     function is used to store the slice configuration Sch DB
1710  *
1711  * @params[in] SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq,
1712  * SchSliceCfgRsp cfgRsp, uint8_t count
1713  *
1714  * @return
1715  *        ROK - Success
1716  *        RFAILED - Failure
1717  *
1718  * ********************************************************************************/
1719 uint8_t addSliceCfgInSchDb(SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq, SchSliceCfgRsp cfgRsp, uint8_t count)
1720 {
1721    uint8_t cfgIdx = 0, sliceIdx = 0; 
1722    
1723    if(count)
1724    {
1725       storeSliceCfg->numOfSliceConfigured = count;
1726       SCH_ALLOC(storeSliceCfg->listOfConfirguration, storeSliceCfg->numOfSliceConfigured * sizeof(SchRrmPolicyOfSlice*));
1727       if(storeSliceCfg->listOfConfirguration == NULLP)
1728       {
1729          DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in addSliceCfgInSchDb");
1730          return RFAILED;
1731       }
1732
1733       for(cfgIdx = 0; cfgIdx<storeSliceCfg->numOfSliceConfigured; cfgIdx++)
1734       {
1735          if(cfgRsp.listOfSliceCfgRsp[cfgIdx]->rsp == RSP_OK)
1736          {
1737             SCH_ALLOC(storeSliceCfg->listOfConfirguration[sliceIdx], sizeof(SchRrmPolicyOfSlice));
1738             if(storeSliceCfg->listOfConfirguration[sliceIdx] == NULLP)
1739             {
1740                DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in addSliceCfgInSchDb");
1741                return RFAILED;
1742             }
1743
1744             SCH_ALLOC(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1745             if(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo == NULLP)
1746             {
1747                DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in addSliceCfgInSchDb");
1748                return RFAILED;
1749             }
1750
1751             memcpy(storeSliceCfg->listOfConfirguration[sliceIdx], cfgReq->listOfConfirguration[sliceIdx], sizeof(SchRrmPolicyOfSlice));
1752             sliceIdx++;
1753          }
1754       }
1755    }
1756    return ROK;
1757 }
1758
1759 /*******************************************************************************
1760  *
1761  * @brief This function is used to free the slice cfg and re cfg request pointer
1762  *
1763  * @details
1764  *
1765  *    Function : freeSchSliceCfgReq 
1766  *
1767  *    Functionality:
1768  *     function is used to free the slice cfg and re cfg request pointer
1769  *
1770  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1771  *
1772  * @return
1773  *        ROK - Success
1774  *        RFAILED - Failure
1775  * ********************************************************************************/
1776 void freeSchSliceCfgReq(SchSliceCfgReq *cfgReq)
1777 {
1778    uint8_t cfgIdx = 0;
1779    
1780    if(cfgReq)
1781    {
1782       if(cfgReq->numOfConfiguredSlice)
1783       {
1784          for(cfgIdx = 0; cfgIdx<cfgReq->numOfConfiguredSlice; cfgIdx++)
1785          {
1786             if(cfgReq->listOfConfirguration[cfgIdx])
1787             {
1788                SCH_FREE(cfgReq->listOfConfirguration[cfgIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1789                SCH_FREE(cfgReq->listOfConfirguration[cfgIdx], sizeof(SchRrmPolicyOfSlice));
1790             }
1791          }
1792          SCH_FREE(cfgReq->listOfConfirguration, cfgReq->numOfConfiguredSlice * sizeof(SchRrmPolicyOfSlice*));
1793       }
1794       SCH_FREE(cfgReq, sizeof(SchSliceCfgReq));
1795    }
1796 }
1797 /*******************************************************************************
1798  *
1799  * @brief This function is used to store the slice configuration Sch DB
1800  *
1801  * @details
1802  *
1803  *    Function : MacSchSliceCfgReq 
1804  *
1805  *    Functionality:
1806  *     function is used to store the slice configuration Sch DB
1807  *
1808  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1809  *
1810  * @return
1811  *        ROK - Success
1812  *        RFAILED - Failure
1813  *
1814  * ********************************************************************************/
1815 uint8_t MacSchSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
1816 {
1817    uint8_t count = 0;
1818    Inst   inst = pst->dstInst - SCH_INST_START;
1819    SchSliceCfgRsp sliceCfgRsp;
1820
1821    DU_LOG("\nINFO  -->  SCH : Received Slice Cfg request from MAC");
1822    if(schSliceCfgReq)
1823    {
1824       if(schSliceCfgReq->listOfConfirguration)
1825       {
1826          /* filling the slice configuration response of each slice */
1827          if(fillSliceCfgRsp(false, NULLP, schCb[inst].cells[0], schSliceCfgReq, &sliceCfgRsp, &count) != ROK)
1828          {
1829             DU_LOG("\nERROR  -->  SCH : Failed to fill the slice cfg rsp");
1830             return RFAILED;
1831          }
1832
1833          if(addSliceCfgInSchDb(&schCb[inst].sliceCfg, schSliceCfgReq, sliceCfgRsp, count) != ROK)
1834          {
1835             DU_LOG("\nERROR  -->  SCH : Failed to add slice cfg in sch database");
1836             return RFAILED;
1837          }
1838          freeSchSliceCfgReq(schSliceCfgReq);
1839          SchSendSliceCfgRspToMac(inst, sliceCfgRsp);
1840       }
1841    }
1842    else
1843    {
1844       DU_LOG("\nERROR  -->  SCH : Received SchSliceCfgReq is NULL");
1845    }
1846    return ROK;
1847 }
1848
1849 /*******************************************************************************
1850  *
1851  * @brief This function is used to store the slice reconfiguration Sch DB
1852  *
1853  * @details
1854  *
1855  *    Function : modifySliceCfgInSchDb 
1856  *
1857  *    Functionality:
1858  *     function is used to store the slice re configuration Sch DB
1859  *
1860  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1861  *
1862  * @return
1863  *        ROK - Success
1864  *        RFAILED - Failure
1865  *
1866  * ********************************************************************************/
1867 uint8_t modifySliceCfgInSchDb(SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq, SchSliceCfgRsp cfgRsp, uint8_t count)
1868 {
1869    uint8_t cfgIdx = 0, sliceIdx = 0; 
1870
1871    if(count)
1872    {
1873       if(storeSliceCfg->listOfConfirguration == NULLP)
1874       {
1875          DU_LOG("\nINFO  -->  SCH : Memory allocation failed in modifySliceCfgInSchDb");
1876          return RFAILED;
1877       }
1878
1879       for(cfgIdx = 0; cfgIdx<cfgReq->numOfConfiguredSlice; cfgIdx++)
1880       {
1881          if(cfgRsp.listOfSliceCfgRsp[cfgIdx]->rsp == RSP_OK)
1882          {
1883             for(sliceIdx = 0; sliceIdx<storeSliceCfg->numOfSliceConfigured; sliceIdx++)
1884             {
1885                if(!memcmp(&storeSliceCfg->listOfConfirguration[sliceIdx]->snssai, &cfgReq->listOfConfirguration[cfgIdx]->snssai, sizeof(Snssai)))
1886                {
1887                   storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo = cfgReq->listOfConfirguration[cfgIdx]->rrmPolicyRatioInfo;
1888                   break;
1889                }
1890             }
1891          }
1892       }
1893    }
1894    freeSchSliceCfgReq(cfgReq);
1895    return ROK;
1896 }
1897 /*******************************************************************************
1898  *
1899  * @brief This function is used to send Slice re Cfg rsp to MAC
1900  *
1901  * @details
1902  *
1903  *    Function : SchSendSliceCfgRspToMac
1904  *
1905  *    Functionality:
1906  *     function is used to send Slice re Cfg rsp to MAC
1907  *
1908  * @params[in] Pst *pst, SchSliceCfgRsp schSliceReCfgRsp
1909  *
1910  * @return- void
1911  *
1912  * ********************************************************************************/
1913 void SchSendSliceReCfgRspToMac(Inst inst, SchSliceCfgRsp schSliceReCfgRsp)
1914 {
1915    Pst rspPst;
1916    
1917    memset(&rspPst, 0, sizeof(Pst));
1918    FILL_PST_SCH_TO_MAC(rspPst, inst);
1919    rspPst.event = EVENT_SLICE_RECFG_RSP_TO_MAC;
1920    
1921    SchSliceReCfgRspOpts[rspPst.selector](&rspPst, &schSliceReCfgRsp);
1922 }
1923 /*******************************************************************************
1924  *
1925  * @brief This function is used to store the slice reconfiguration Sch DB
1926  *
1927  * @details
1928  *
1929  *    Function : MacSchSliceReCfgReq 
1930  *
1931  *    Functionality:
1932  *     function is used to store the slice re configuration Sch DB
1933  *
1934  * @params[in] Pst *pst, SchSliceCfgReq *schSliceReCfgReq
1935  *
1936  * @return
1937  *        ROK - Success
1938  *        RFAILED - Failure
1939  *
1940  * ********************************************************************************/
1941 uint8_t MacSchSliceReCfgReq(Pst *pst, SchSliceCfgReq *schSliceReCfgReq)
1942 {
1943    uint8_t count = 0;
1944    Inst   inst = pst->dstInst - SCH_INST_START;
1945    SchSliceCfgRsp schSliceReCfgRsp;
1946
1947    DU_LOG("\nINFO  -->  SCH : Received Slice ReCfg request from MAC");
1948    if(schSliceReCfgReq)
1949    {
1950       if(schSliceReCfgReq->listOfConfirguration)
1951       {
1952          /* filling the slice configuration response of each slice */
1953          if(fillSliceCfgRsp(true, &schCb[inst].sliceCfg, NULLP, schSliceReCfgReq, &schSliceReCfgRsp, &count) != ROK)
1954          {
1955             DU_LOG("\nERROR  -->  SCH : Failed to fill sch slice cfg response");
1956             return RFAILED;
1957          }
1958          
1959          /* Modify the slice configuration stored in schCb */
1960          if(modifySliceCfgInSchDb(&schCb[inst].sliceCfg, schSliceReCfgReq, schSliceReCfgRsp, count) != ROK)
1961          {
1962             DU_LOG("\nERROR  -->  SCH : Failed to modify slice cfg of SchDb");
1963             return RFAILED;
1964          }
1965          SchSendSliceReCfgRspToMac(inst, schSliceReCfgRsp);
1966       }
1967    }
1968    else
1969    {
1970       DU_LOG("\nERROR  -->  SCH : Received SchSliceCfgReq is NULL");
1971    }
1972    return ROK;
1973 }
1974
1975 /****************************************************************************
1976  *
1977  * @brief Stores the Paging Configuration from DU APP in CellCb 
1978  *
1979  * @details
1980  *
1981  *    Function : schProcPagingParam
1982  *
1983  *    Functionality:
1984  *          Process the Paging Configuration when FirstPDCCHMonitoring for
1985  *          Paging Ocassion is not present.
1986  *
1987  *          As per 38.304 Sec 7.1,
1988  *          "When firstPDCCH-MonitoringOccasionOfPO is present, the
1989  *          starting PDCCH monitoring occasion number of (i_s + 1)th PO is the
1990  *          (i_s + 1)th value of the firstPDCCHMonitoringOccasionOfPO
1991  *          parameter; otherwise, it is equal to i_s * S."
1992  *          "S = number of actual transmitted SSBs determined according 
1993  *              to ssb-PositionsInBurst in SIB1"
1994  *
1995  * @params[in] SchCellCb *cell 
1996  *       
1997  * @return void 
1998  *        
1999  *************************************************************************/
2000 void schProcPagingCfg(SchCellCb *cell)
2001 {
2002    PageCfg *pageCfgRcvd = NULL;
2003    uint8_t i_sIdx = 0;
2004
2005    pageCfgRcvd = &(cell->cellCfg.sib1SchCfg.pageCfg);
2006
2007    if(pageCfgRcvd->poPresent == TRUE)
2008    {
2009       /*Fetching first Pdcch Monitoring Occasion for SFN (i_s + 1)th*/
2010       for(i_sIdx = 0; i_sIdx < pageCfgRcvd->numPO; i_sIdx++)
2011       {
2012          cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pageCfgRcvd->pagingOcc[i_sIdx] / MAX_SYMB_PER_SLOT ;
2013          if ((pageCfgRcvd->pagingOcc[i_sIdx] % MAX_SYMB_PER_SLOT) != 0 )
2014          {
2015             cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot++;
2016          }
2017
2018          cell->pageCb.pagMonOcc[i_sIdx].frameOffset = 0;
2019
2020       }
2021    }
2022    else
2023    {
2024       schCfgPdcchMonOccOfPO(cell);                  
2025    }
2026 }
2027
2028 /****************************************************************************
2029  *
2030  * @brief Calculate PO if not present in Configuration 
2031  *
2032  * @details
2033  *
2034  *    Function : schCfgPdcchMonOccOfPO
2035  *
2036  *    Functionality: In this function, PO are calculated i_s * S because
2037  *    FirstPDCCHMonitoring_ForPO is not present.
2038  *
2039  * @params[in] SchCellCb *cellCb
2040  *       
2041  * @return void 
2042  *        
2043  *************************************************************************/
2044 void schCfgPdcchMonOccOfPO(SchCellCb *cell)
2045 {
2046    uint8_t         cnt = 0, incr = 1, i_sIdx = 0, frameOffSet = 0;
2047    uint8_t         nsValue = cell->cellCfg.sib1SchCfg.pageCfg.numPO;
2048    uint8_t         totalNumSsb = cell->cellCfg.ssbSchCfg.totNumSsb;
2049    SlotTimingInfo  tmpTimingInfo, pdcchTime; 
2050
2051    /*Starting with First Sfn and slot*/
2052    tmpTimingInfo.sfn = 0;
2053    tmpTimingInfo.slot = 0;
2054
2055    pdcchTime = tmpTimingInfo;
2056
2057    while(i_sIdx < nsValue)
2058    {
2059       /*Increment frame Offset if PO falls on next SFN*/
2060       if(pdcchTime.sfn != tmpTimingInfo.sfn)
2061       {
2062          frameOffSet++;
2063       }
2064       pdcchTime = tmpTimingInfo;
2065       schIncrSlot(&(tmpTimingInfo), incr, cell->numSlots);
2066
2067       if (i_sIdx == 0)
2068       {
2069          cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2070          cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2071          i_sIdx++;
2072       }
2073       else
2074       {
2075          cnt++;
2076          if((cnt == totalNumSsb) && (i_sIdx < MAX_PO_PER_PF)) 
2077          {
2078             cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2079             cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2080             cnt = 0;
2081             i_sIdx++;
2082          }
2083       }
2084    }
2085 }
2086
2087 /**********************************************************************
2088   End of file
2089  **********************************************************************/