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