[Epic-ID: ODUHIGH-462][Task-ID: ODUHIGH-472] Implementation of drx timer
[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 #ifdef NR_DRX
1122    if(ueCb->ueDrxInfoPres)
1123    {
1124       if(!ueCb->drxUeCb.drxUlUeActiveStatus)
1125          ueCb->drxUeCb.drxUlUeActiveStatus = true;
1126    }
1127 #endif
1128    if(uciInd->numSrBits)
1129    {
1130       ueCb->srRcvd = true;      
1131       /* Adding UE Id to list of pending UEs to be scheduled */
1132       addUeToBeScheduled(cellCb, ueCb->ueId);
1133    }
1134    return ROK;
1135 }
1136
1137 /*******************************************************************
1138  *
1139  * @brief Processes HARQ UCI indication from MAC 
1140  *
1141  * @details
1142  *
1143  *    Function : MacSchHarqUciInd
1144  *
1145  *    Functionality:
1146  *      Processes HARQ UCI indication from MAC
1147  *
1148  * @params[in] Post structure
1149  *             UCI Indication
1150  * @return ROK     - success
1151  *         RFAILED - failure
1152  *
1153  * ****************************************************************/
1154 uint8_t MacSchHarqUciInd(Pst *pst, HarqUciIndInfo *uciInd)
1155 {
1156    Inst  inst = pst->dstInst-SCH_INST_START;
1157    SchUeCb   *ueCb;
1158    SchCellCb *cellCb = schCb[inst].cells[inst];
1159
1160 #ifdef CALL_FLOW_DEBUG_LOG
1161    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_UCI_IND_TO_SCH\n");
1162 #endif
1163
1164    DU_LOG("\nDEBUG  -->  SCH : Received HARQ");
1165
1166    ueCb = schGetUeCb(cellCb, uciInd->crnti);
1167
1168    if(ueCb->state == SCH_UE_STATE_INACTIVE)
1169    {
1170       DU_LOG("\nERROR  -->  SCH : Crnti %d is inactive", uciInd->crnti);
1171       return ROK;
1172    }
1173
1174    schUpdateHarqFdbk(ueCb, uciInd->numHarq, uciInd->harqPayload, &uciInd->slotInd);
1175
1176    return ROK;
1177 }
1178
1179 /*******************************************************************
1180  *
1181  * @brief Allocates requested PRBs for DL
1182  *
1183  * @details
1184  *
1185  *    Function : allocatePrbDl
1186  *
1187  *    Functionality:
1188  *      Allocates requested PRBs in DL
1189  *      Keeps track of allocated PRB (using bitmap) and remaining PRBs
1190  *
1191  * @params[in] prbAlloc table
1192  *             Start symbol
1193  *             Number of symbols
1194  *             Start PRB
1195  *             Number of PRBs
1196  *
1197  * @return ROK     - success
1198  *         RFAILED - failure
1199  *
1200  * ****************************************************************/
1201 uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
1202    uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1203 {
1204    uint8_t        symbol = 0;
1205    uint16_t       broadcastPrbStart=0, broadcastPrbEnd=0;
1206    FreePrbBlock   *freePrbBlock = NULLP;
1207    CmLList        *freePrbNode = NULLP;
1208    PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
1209    SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1210    SchPrbAlloc    *prbAlloc = &schDlSlotInfo->prbAlloc;
1211
1212    /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1213     * Search for an appropriate location in PRB grid and allocate requested resources */
1214    if(*startPrb == MAX_NUM_RB)
1215    {
1216       /* Check if SSB/SIB1 is also scheduled in this slot  */
1217       ssbOccasion = schCheckSsbOcc(cell, slotTime);
1218       sib1Occasion = schCheckSib1Occ(cell, slotTime);
1219
1220       if(ssbOccasion && sib1Occasion)
1221       {
1222          broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA; 
1223          broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1224       }
1225       else if(ssbOccasion)
1226       {
1227          broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
1228          broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB -1;
1229       }
1230       else if(sib1Occasion)
1231       {
1232          broadcastPrbStart = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.startPrb;
1233          broadcastPrbEnd = broadcastPrbStart + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1234       }
1235
1236       /* Iterate through all free PRB blocks */
1237       freePrbNode = prbAlloc->freePrbBlockList.first; 
1238       while(freePrbNode)
1239       {
1240          freePrbBlock = (FreePrbBlock *)freePrbNode->node; 
1241
1242          /* If broadcast message is scheduled in this slot, then check if its PRBs belong to the current free block.
1243           * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1244          if((ssbOccasion || sib1Occasion) && 
1245             ((broadcastPrbStart >= freePrbBlock->startPrb) && (broadcastPrbStart <= freePrbBlock->endPrb)) && \
1246             ((broadcastPrbEnd >= freePrbBlock->startPrb) && (broadcastPrbEnd <= freePrbBlock->endPrb)))
1247          {
1248             /* Implmentation is done such that highest-numbered free-RB is allocated first */ 
1249             if((freePrbBlock->endPrb > broadcastPrbEnd) && ((freePrbBlock->endPrb - broadcastPrbEnd) >= numPrb))
1250             {
1251                /* If sufficient free PRBs are available above bradcast message then,
1252                 * endPrb = freePrbBlock->endPrb
1253                 * startPrb = endPrb - numPrb +1;
1254                 */
1255                *startPrb = freePrbBlock->endPrb - numPrb +1;
1256                break;
1257             }
1258             else if((broadcastPrbStart > freePrbBlock->startPrb) && ((broadcastPrbStart - freePrbBlock->startPrb) >= numPrb))
1259             {
1260                /* If free PRBs are available below broadcast message then,
1261                 * endPrb = broadcastPrbStart - 1
1262                 * startPrb = endPrb - numPrb +1
1263                 */
1264                *startPrb = broadcastPrbStart - numPrb; 
1265                break;
1266             }
1267             else
1268             {
1269                freePrbNode = freePrbNode->next;
1270                continue;
1271             }
1272          }
1273          else
1274          {
1275             /* Check if requested number of blocks can be allocated from the current block */ 
1276             if (freePrbBlock->numFreePrb < numPrb)
1277             {
1278                freePrbNode = freePrbNode->next;
1279                continue;
1280             }
1281             *startPrb = freePrbBlock->endPrb - numPrb +1;
1282             break;  
1283          }
1284       }
1285
1286       /* If no free block can be used to allocated request number of RBs */
1287       if(*startPrb == MAX_NUM_RB)
1288          return RFAILED;
1289    }
1290
1291    /* If startPrb is known already, check if requested PRBs are available for allocation */
1292    else
1293    {
1294       freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1295       if(!freePrbNode)
1296       {
1297          DU_LOG("\nERROR  -->  SCH: Requested DL PRB unavailable");
1298          return RFAILED;
1299       }
1300    }
1301
1302    /* Update bitmap to allocate PRBs */
1303    for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1304    {
1305       if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1306       {
1307          DU_LOG("\nERROR  -->  SCH: fillPrbBitmap() failed for symbol [%d] in DL", symbol);
1308          return RFAILED;
1309       }
1310    }
1311
1312    /* Update the remaining number for free PRBs */
1313    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1314
1315    return ROK;
1316 }
1317
1318 /*******************************************************************
1319  *
1320  * @brief Allocates requested PRBs for UL
1321  *
1322  * @details
1323  *
1324  *    Function : allocatePrbUl
1325  *
1326  *    Functionality:
1327  *      Allocates requested PRBs in UL
1328  *      Keeps track of allocated PRB (using bitmap) and remaining PRBs
1329  *
1330  * @params[in] prbAlloc table
1331  *             Start symbol
1332  *             Number of symbols
1333  *             Start PRB
1334  *             Number of PRBs
1335  *
1336  * @return ROK     - success
1337  *         RFAILED - failure
1338  *
1339  * ****************************************************************/
1340 uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
1341    uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1342 {
1343    uint8_t        symbol = 0;
1344    uint16_t       prachStartPrb, prachNumPrb, prachEndPrb;
1345    bool           isPrachOccasion;
1346    FreePrbBlock   *freePrbBlock = NULLP;
1347    CmLList        *freePrbNode = NULLP;
1348    SchPrbAlloc    *prbAlloc = NULLP;
1349
1350    if(cell == NULLP)
1351    {
1352       DU_LOG("\nERROR  --> SCH : allocatePrbUl(): Received cellCb is null");
1353       return RFAILED;
1354    }
1355    
1356    prbAlloc =   &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1357    /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1358     * Search for an appropriate location in PRB grid and allocate requested resources */
1359    if(*startPrb == MAX_NUM_RB)
1360    {
1361       /* Check if PRACH is also scheduled in this slot */
1362       isPrachOccasion = schCheckPrachOcc(cell, slotTime);
1363       if(isPrachOccasion)
1364       {
1365          prachStartPrb =  cell->cellCfg.schRachCfg.msg1FreqStart;
1366          prachNumPrb = schCalcPrachNumRb(cell);
1367          prachEndPrb = prachStartPrb + prachNumPrb -1;
1368       }
1369
1370       /* Iterate through all free PRB blocks */
1371       freePrbNode = prbAlloc->freePrbBlockList.first; 
1372       while(freePrbNode)
1373       {
1374          freePrbBlock = (FreePrbBlock *)freePrbNode->node; 
1375
1376          /* If PRACH is scheduled in this slot, then check if its PRBs belong to the current free block.
1377           * PRBs required for PRACH cannot be allocated to any other message */
1378          if((isPrachOccasion) &&
1379             ((prachStartPrb >= freePrbBlock->startPrb) && (prachStartPrb <= freePrbBlock->endPrb)) &&
1380             ((prachEndPrb >= freePrbBlock->startPrb) && (prachEndPrb <= freePrbBlock->endPrb)))
1381          {
1382             /* Implmentation is done such that highest-numbered free-RB is allocated first */ 
1383             if((freePrbBlock->endPrb > prachEndPrb) && ((freePrbBlock->endPrb - prachEndPrb) >= numPrb))
1384             {
1385                /* If sufficient free PRBs are available above PRACH message then,
1386                 * endPrb = freePrbBlock->endPrb
1387                 * startPrb = endPrb - numPrb +1;
1388                 */
1389                *startPrb = freePrbBlock->endPrb - numPrb +1;
1390                break;
1391             }
1392             else if((prachStartPrb > freePrbBlock->startPrb) && ((prachStartPrb - freePrbBlock->startPrb) >= numPrb))
1393             {
1394                /* If free PRBs are available below PRACH message then,
1395                 * endPrb = prachStartPrb - 1
1396                 * startPrb = endPrb - numPrb +1
1397                 */
1398                *startPrb = prachStartPrb - numPrb; 
1399                break;
1400             }
1401             else
1402             {
1403                freePrbNode = freePrbNode->next;
1404                continue;
1405             } 
1406          }
1407          else
1408          {
1409             /* Check if requested number of PRBs can be allocated from currect block */
1410             if(freePrbBlock->numFreePrb < numPrb)
1411             {
1412                freePrbNode = freePrbNode->next;
1413                continue;
1414             }
1415             *startPrb = freePrbBlock->endPrb - numPrb +1;
1416             break;
1417          }
1418       }
1419
1420       /* If no free block can be used to allocated requested number of RBs */
1421       if(*startPrb == MAX_NUM_RB)
1422          return RFAILED;
1423    }
1424    else
1425    {
1426       /* If startPrb is known already, check if requested PRBs are available for allocation */
1427       freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1428       if(!freePrbNode)
1429       {
1430          DU_LOG("\nERROR  -->  SCH: Requested UL PRB unavailable");
1431          return RFAILED;
1432       }
1433    }
1434
1435    /* Update bitmap to allocate PRBs */
1436    for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1437    {
1438       if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1439       {
1440          DU_LOG("\nERROR  -->  SCH: fillPrbBitmap() failed for symbol [%d] in UL", symbol);
1441          return RFAILED;
1442       }
1443    }
1444
1445    /* Update the remaining number for free PRBs */
1446    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1447
1448    return ROK;
1449 }
1450
1451 /*******************************************************************
1452  *
1453  * @brief Add UE to ueToBeScheduled List
1454  *
1455  * @details
1456  *
1457  *    Function : addUeToBeScheduled
1458  *
1459  *    Functionality:
1460  *      Search if UE entry present in the list
1461  *      If yes, return.
1462  *      If no, add UE to the list
1463  *
1464  * @params[in] Cell control block
1465  *             Ue Idx to be added
1466  *
1467  * @return ROK     - success
1468  *         RFAILED - failure
1469  *
1470  * ****************************************************************/
1471 uint8_t addUeToBeScheduled(SchCellCb *cell, uint8_t ueIdToAdd)
1472 {
1473    uint8_t *ueId;
1474    CmLList *node;
1475
1476    /* Search if UE entry is already present in ueToBeScheduled list.
1477     * If yes, another entry for same UE not needed. Hence, return */
1478    node = cell->ueToBeScheduled.first;
1479    while(node)
1480    {
1481       ueId = (uint8_t *)node->node;
1482       if(*ueId == ueIdToAdd)
1483          return ROK;
1484       node = node->next;
1485    }
1486
1487    /* If UE entry not present already, add UE to the end of ueToBeScheduled list */
1488    SCH_ALLOC(ueId, sizeof(uint8_t));
1489    if(!ueId)
1490    {
1491       DU_LOG("\nERROR  -->  SCH : Memory allocation failure in addUeToBeScheduled");
1492       return RFAILED;
1493    }
1494    *ueId = ueIdToAdd;
1495    if(addNodeToLList(&cell->ueToBeScheduled, ueId, NULLP) != ROK)
1496    {
1497       DU_LOG("\nERROR  --> SCH : Failed to add ueId [%d] to cell->ueToBeScheduled list", *ueId);
1498       return RFAILED;
1499    }
1500    return ROK;
1501 }
1502  
1503 /*******************************************************************************
1504  *
1505  * @brief Try to find Best Free Block with Max Num PRB 
1506  *
1507  * @details
1508  *
1509  *    Function : searchLargestFreeBlock
1510  *
1511  *    Functionality:
1512  *     Finds the FreeBlock with MaxNum of FREE PRB considering SSB/SIB1 ocassions.
1513  *
1514  * @params[in] I/P > prbAlloc table (FreeBlock list)
1515  *             I/P > Slot timing Info
1516  *             O/P > Start PRB
1517  *             I/P > Direction (UL/DL)
1518  *       
1519  *
1520  * @return Max Number of Free PRB 
1521  *         If 0, then no Suitable Free Block
1522  *
1523  * ********************************************************************************/
1524
1525 uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_t *startPrb, Direction dir)
1526 {
1527    uint16_t       reservedPrbStart=0, reservedPrbEnd=0, maxFreePRB = 0;
1528    FreePrbBlock   *freePrbBlock = NULLP;
1529    CmLList        *freePrbNode = NULLP;
1530    SchPrbAlloc    *prbAlloc = NULLP;
1531    bool           checkOccasion = FALSE;
1532
1533    *startPrb = 0; /*Initialize the StartPRB to zero*/
1534
1535    /*Based on Direction, Reserved Messsages will differi.e.
1536     * DL >> SSB and SIB1 ocassions wheres for UL, PRACH ocassions to be checked
1537     * and reserved before allocation for dedicated DL/UL msg*/
1538    if(dir == DIR_DL)
1539    {
1540       SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1541       PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
1542
1543       prbAlloc = &schDlSlotInfo->prbAlloc;
1544
1545       ssbOccasion = schCheckSsbOcc(cell, slotTime);
1546       sib1Occasion = schCheckSib1Occ(cell, slotTime);
1547
1548       checkOccasion = TRUE;
1549       if(ssbOccasion && sib1Occasion)
1550       {
1551          reservedPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA; 
1552          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB + \
1553                           cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1554       }
1555       else if(ssbOccasion)
1556       {
1557          reservedPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
1558          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB -1;
1559       }
1560       else if(sib1Occasion)
1561       {
1562          reservedPrbStart = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.startPrb;
1563          reservedPrbEnd = reservedPrbStart + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1564       }
1565       else
1566       {
1567          checkOccasion = FALSE;  
1568       }
1569    }
1570    else if(dir == DIR_UL)
1571    {
1572       prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1573
1574       /* Check if PRACH is also scheduled in this slot */
1575       checkOccasion = schCheckPrachOcc(cell, slotTime);
1576       if(checkOccasion)
1577       {
1578          reservedPrbStart =  cell->cellCfg.schRachCfg.msg1FreqStart;
1579          reservedPrbEnd = reservedPrbStart + (schCalcPrachNumRb(cell)) -1;
1580       }
1581    }
1582    else
1583    {
1584       DU_LOG("\nERROR --> SCH: Invalid Direction!");
1585       return (maxFreePRB);
1586    }
1587
1588    freePrbNode = prbAlloc->freePrbBlockList.first; 
1589    while(freePrbNode)
1590    {
1591       freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1592
1593       /*For block with same numFreeBlocks, choose the one with HighestPRB range
1594        *Since FreeBLockList are arranged in Descending order of PRB range thus Skipping this block*/
1595       if(maxFreePRB >= freePrbBlock->numFreePrb) 
1596       {
1597          //skip this block
1598          freePrbNode = freePrbNode->next;
1599          continue;
1600       }
1601
1602       /* If Broadcast/Prach message is scheduled in this slot, then check if its PRBs belong to the current free block.
1603        * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1604       if(checkOccasion && 
1605             ((reservedPrbStart >= freePrbBlock->startPrb) && (reservedPrbStart <= freePrbBlock->endPrb)) && \
1606             ((reservedPrbEnd >= freePrbBlock->startPrb) && (reservedPrbEnd <= freePrbBlock->endPrb)))
1607       {
1608
1609          /* Implmentation is done such that highest-numbered free-RB is Checked first
1610             and freePRB in this block is greater than Max till now */
1611          if((freePrbBlock->endPrb > reservedPrbEnd) && ((freePrbBlock->endPrb - reservedPrbEnd) > maxFreePRB))
1612          {
1613             /* If sufficient free PRBs are available above reserved message*/
1614             *startPrb = reservedPrbEnd + 1;
1615             maxFreePRB = (freePrbBlock->endPrb - reservedPrbEnd);                
1616          }
1617          /*Also check the other freeBlock (i.e. Above the reserved message) for MAX FREE PRB*/
1618          if((reservedPrbStart > freePrbBlock->startPrb) && ((reservedPrbStart - freePrbBlock->startPrb) > maxFreePRB))
1619          {
1620             /* If free PRBs are available below reserved message*/
1621             *startPrb = freePrbBlock->startPrb;
1622             maxFreePRB = (reservedPrbStart - freePrbBlock->startPrb);
1623          }
1624       }
1625       else  //Best Block
1626       {
1627          if(maxFreePRB < freePrbBlock->numFreePrb)
1628          {
1629             *startPrb = freePrbBlock->startPrb;
1630             maxFreePRB = freePrbBlock->numFreePrb;
1631          }
1632
1633       }
1634       freePrbNode = freePrbNode->next;
1635    }  
1636    return(maxFreePRB);
1637 }
1638
1639 /*******************************************************************************
1640  *
1641  * @brief This function is used to send Slice Cfg rsp to MAC
1642  *
1643  * @details
1644  *
1645  *    Function : SchSendSliceCfgRspToMac
1646  *
1647  *    Functionality:
1648  *     function is used to send Slice Cfg rsp to MAC
1649  *
1650  * @params[in] Pst *pst, SchSliceCfgRsp sliceCfgRsp
1651  *
1652  * @return- void
1653  *
1654  * ********************************************************************************/
1655 void SchSendSliceCfgRspToMac(Inst inst, SchSliceCfgRsp sliceCfgRsp)
1656 {
1657    Pst rspPst;
1658    
1659    memset(&rspPst, 0, sizeof(Pst));
1660    FILL_PST_SCH_TO_MAC(rspPst, inst);
1661    rspPst.event = EVENT_SLICE_CFG_RSP_TO_MAC;
1662    
1663    SchSliceCfgRspOpts[rspPst.selector](&rspPst, &sliceCfgRsp);
1664
1665 }
1666 /*******************************************************************************
1667  *
1668  * @brief fill slice configuration response
1669  *
1670  * @details
1671  *
1672  *    Function : fillSliceCfgRsp
1673  *
1674  *    Functionality:
1675  *     fill slice configuration response
1676  *
1677  * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t  count
1678  *
1679  * @return
1680  *        ROK - Success
1681  *        RFAILED - Failure
1682  *
1683  * ********************************************************************************/
1684 uint8_t fillSliceCfgRsp(bool sliceReCfg, SchSliceCfg *storedSliceCfg, SchCellCb *cellCb, SchSliceCfgReq *schSliceCfgReq, SchSliceCfgRsp *schSliceCfgRsp, uint8_t *count)
1685 {
1686    bool sliceFound = false;
1687    uint8_t cfgIdx = 0, sliceIdx = 0;
1688
1689    schSliceCfgRsp->numSliceCfgRsp  = schSliceCfgReq->numOfConfiguredSlice;
1690    SCH_ALLOC(schSliceCfgRsp->listOfSliceCfgRsp, schSliceCfgRsp->numSliceCfgRsp * sizeof(SliceRsp*));
1691    if(schSliceCfgRsp->listOfSliceCfgRsp == NULLP)
1692    {
1693       DU_LOG("\nERROR  --> SCH : Memory allocation failed at fillSliceCfgRsp");
1694       return RFAILED;
1695    }
1696    
1697    for(cfgIdx = 0; cfgIdx<schSliceCfgRsp->numSliceCfgRsp ; cfgIdx++)
1698    {
1699       sliceFound = false;
1700       /* Here comparing the slice cfg request with the slice stored in cellCfg */
1701       if(sliceReCfg != true)
1702       {
1703          for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList.numSliceSupport; sliceIdx++)
1704          {
1705             if(!memcmp(&schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList.snssai[sliceIdx], sizeof(Snssai)))
1706             {
1707                (*count)++;
1708                sliceFound = true;
1709                break;
1710             }
1711          }
1712       }
1713       else
1714       {
1715          /* Here comparing the slice cfg request with the slice stored in SchDb */
1716          if(storedSliceCfg->listOfConfirguration)
1717          {
1718             for(sliceIdx = 0; sliceIdx<storedSliceCfg->numOfSliceConfigured; sliceIdx++)
1719             {
1720                if(!memcmp(&schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai, &storedSliceCfg->listOfConfirguration[sliceIdx]->snssai,\
1721                         sizeof(Snssai)))
1722                {
1723                   (*count)++;
1724                   sliceFound = true;
1725                   break;
1726                }
1727             }
1728          }
1729       }
1730
1731       SCH_ALLOC(schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx], sizeof(SliceRsp));
1732       if(schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx] == NULLP)
1733       {
1734          DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in fillSliceCfgRsp");
1735          return RFAILED;
1736       }
1737
1738       
1739       schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->snssai = schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai;
1740       if(sliceFound == true)
1741          schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->rsp    = RSP_OK;
1742       else
1743       {
1744          schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->rsp    = RSP_NOK;
1745          schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->cause  = SLICE_NOT_FOUND;
1746       }
1747    }
1748    return ROK;
1749 }
1750
1751 /*******************************************************************************
1752  *
1753  * @brief This function is used to store the slice configuration Sch DB
1754  *
1755  * @details
1756  *
1757  *    Function : addSliceCfgInSchDb 
1758  *
1759  *    Functionality:
1760  *     function is used to store the slice configuration Sch DB
1761  *
1762  * @params[in] SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq,
1763  * SchSliceCfgRsp cfgRsp, uint8_t count
1764  *
1765  * @return
1766  *        ROK - Success
1767  *        RFAILED - Failure
1768  *
1769  * ********************************************************************************/
1770 uint8_t addSliceCfgInSchDb(SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq, SchSliceCfgRsp cfgRsp, uint8_t count)
1771 {
1772    uint8_t cfgIdx = 0, sliceIdx = 0; 
1773    
1774    if(count)
1775    {
1776       storeSliceCfg->numOfSliceConfigured = count;
1777       SCH_ALLOC(storeSliceCfg->listOfConfirguration, storeSliceCfg->numOfSliceConfigured * sizeof(SchRrmPolicyOfSlice*));
1778       if(storeSliceCfg->listOfConfirguration == NULLP)
1779       {
1780          DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in addSliceCfgInSchDb");
1781          return RFAILED;
1782       }
1783
1784       for(cfgIdx = 0; cfgIdx<storeSliceCfg->numOfSliceConfigured; cfgIdx++)
1785       {
1786          if(cfgRsp.listOfSliceCfgRsp[cfgIdx]->rsp == RSP_OK)
1787          {
1788             SCH_ALLOC(storeSliceCfg->listOfConfirguration[sliceIdx], sizeof(SchRrmPolicyOfSlice));
1789             if(storeSliceCfg->listOfConfirguration[sliceIdx] == NULLP)
1790             {
1791                DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in addSliceCfgInSchDb");
1792                return RFAILED;
1793             }
1794
1795             SCH_ALLOC(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1796             if(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo == NULLP)
1797             {
1798                DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in addSliceCfgInSchDb");
1799                return RFAILED;
1800             }
1801
1802             memcpy(&storeSliceCfg->listOfConfirguration[sliceIdx]->snssai, &cfgReq->listOfConfirguration[sliceIdx]->snssai, sizeof(Snssai));
1803             memcpy(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo, cfgReq->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo,
1804                       sizeof(SchRrmPolicyRatio));
1805             sliceIdx++;
1806          }
1807       }
1808    }
1809    return ROK;
1810 }
1811
1812 /*******************************************************************************
1813  *
1814  * @brief This function is used to free the slice cfg and re cfg request pointer
1815  *
1816  * @details
1817  *
1818  *    Function : freeSchSliceCfgReq 
1819  *
1820  *    Functionality:
1821  *     function is used to free the slice cfg and re cfg request pointer
1822  *
1823  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1824  *
1825  * @return
1826  *        ROK - Success
1827  *        RFAILED - Failure
1828  * ********************************************************************************/
1829 void freeSchSliceCfgReq(SchSliceCfgReq *cfgReq)
1830 {
1831    uint8_t cfgIdx = 0;
1832    
1833    if(cfgReq)
1834    {
1835       if(cfgReq->numOfConfiguredSlice)
1836       {
1837          for(cfgIdx = 0; cfgIdx<cfgReq->numOfConfiguredSlice; cfgIdx++)
1838          {
1839             if(cfgReq->listOfConfirguration[cfgIdx])
1840             {
1841                SCH_FREE(cfgReq->listOfConfirguration[cfgIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1842                SCH_FREE(cfgReq->listOfConfirguration[cfgIdx], sizeof(SchRrmPolicyOfSlice));
1843             }
1844          }
1845          SCH_FREE(cfgReq->listOfConfirguration, cfgReq->numOfConfiguredSlice * sizeof(SchRrmPolicyOfSlice*));
1846       }
1847       SCH_FREE(cfgReq, sizeof(SchSliceCfgReq));
1848    }
1849 }
1850 /*******************************************************************************
1851  *
1852  * @brief This function is used to store the slice configuration Sch DB
1853  *
1854  * @details
1855  *
1856  *    Function : MacSchSliceCfgReq 
1857  *
1858  *    Functionality:
1859  *     function is used to store the slice configuration Sch DB
1860  *
1861  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1862  *
1863  * @return
1864  *        ROK - Success
1865  *        RFAILED - Failure
1866  *
1867  * ********************************************************************************/
1868 uint8_t MacSchSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
1869 {
1870    uint8_t count = 0;
1871    Inst   inst = pst->dstInst - SCH_INST_START;
1872    SchSliceCfgRsp sliceCfgRsp;
1873
1874    DU_LOG("\nINFO  -->  SCH : Received Slice Cfg request from MAC");
1875    if(schSliceCfgReq)
1876    {
1877       if(schSliceCfgReq->listOfConfirguration)
1878       {
1879          /* filling the slice configuration response of each slice */
1880          if(fillSliceCfgRsp(false, NULLP, schCb[inst].cells[0], schSliceCfgReq, &sliceCfgRsp, &count) != ROK)
1881          {
1882             DU_LOG("\nERROR  -->  SCH : Failed to fill the slice cfg rsp");
1883             return RFAILED;
1884          }
1885
1886          if(addSliceCfgInSchDb(&schCb[inst].sliceCfg, schSliceCfgReq, sliceCfgRsp, count) != ROK)
1887          {
1888             DU_LOG("\nERROR  -->  SCH : Failed to add slice cfg in sch database");
1889             return RFAILED;
1890          }
1891          freeSchSliceCfgReq(schSliceCfgReq);
1892          SchSendSliceCfgRspToMac(inst, sliceCfgRsp);
1893       }
1894    }
1895    else
1896    {
1897       DU_LOG("\nERROR  -->  SCH : Received SchSliceCfgReq is NULL");
1898    }
1899    return ROK;
1900 }
1901
1902 /*******************************************************************************
1903  *
1904  * @brief This function is used to store the slice reconfiguration Sch DB
1905  *
1906  * @details
1907  *
1908  *    Function : modifySliceCfgInSchDb 
1909  *
1910  *    Functionality:
1911  *     function is used to store the slice re configuration Sch DB
1912  *
1913  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1914  *
1915  * @return
1916  *        ROK - Success
1917  *        RFAILED - Failure
1918  *
1919  * ********************************************************************************/
1920 uint8_t modifySliceCfgInSchDb(SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq, SchSliceCfgRsp cfgRsp, uint8_t count)
1921 {
1922    uint8_t cfgIdx = 0, sliceIdx = 0; 
1923
1924    if(count)
1925    {
1926       if(storeSliceCfg->listOfConfirguration == NULLP)
1927       {
1928          DU_LOG("\nINFO  -->  SCH : Memory allocation failed in modifySliceCfgInSchDb");
1929          return RFAILED;
1930       }
1931
1932       for(cfgIdx = 0; cfgIdx<cfgReq->numOfConfiguredSlice; cfgIdx++)
1933       {
1934          if(cfgRsp.listOfSliceCfgRsp[cfgIdx]->rsp == RSP_OK)
1935          {
1936             for(sliceIdx = 0; sliceIdx<storeSliceCfg->numOfSliceConfigured; sliceIdx++)
1937             {
1938                if(!memcmp(&storeSliceCfg->listOfConfirguration[sliceIdx]->snssai, &cfgReq->listOfConfirguration[cfgIdx]->snssai, sizeof(Snssai)))
1939                {
1940                   memcpy(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo, cfgReq->listOfConfirguration[cfgIdx]->rrmPolicyRatioInfo,
1941                            sizeof(SchRrmPolicyRatio));
1942                   break;
1943                }
1944             }
1945          }
1946       }
1947    }
1948    freeSchSliceCfgReq(cfgReq);
1949    return ROK;
1950 }
1951 /*******************************************************************************
1952  *
1953  * @brief This function is used to send Slice re Cfg rsp to MAC
1954  *
1955  * @details
1956  *
1957  *    Function : SchSendSliceCfgRspToMac
1958  *
1959  *    Functionality:
1960  *     function is used to send Slice re Cfg rsp to MAC
1961  *
1962  * @params[in] Pst *pst, SchSliceCfgRsp schSliceReCfgRsp
1963  *
1964  * @return- void
1965  *
1966  * ********************************************************************************/
1967 void SchSendSliceReCfgRspToMac(Inst inst, SchSliceCfgRsp schSliceReCfgRsp)
1968 {
1969    Pst rspPst;
1970    
1971    memset(&rspPst, 0, sizeof(Pst));
1972    FILL_PST_SCH_TO_MAC(rspPst, inst);
1973    rspPst.event = EVENT_SLICE_RECFG_RSP_TO_MAC;
1974    
1975    SchSliceReCfgRspOpts[rspPst.selector](&rspPst, &schSliceReCfgRsp);
1976 }
1977 /*******************************************************************************
1978  *
1979  * @brief This function is used to store the slice reconfiguration Sch DB
1980  *
1981  * @details
1982  *
1983  *    Function : MacSchSliceReCfgReq 
1984  *
1985  *    Functionality:
1986  *     function is used to store the slice re configuration Sch DB
1987  *
1988  * @params[in] Pst *pst, SchSliceCfgReq *schSliceReCfgReq
1989  *
1990  * @return
1991  *        ROK - Success
1992  *        RFAILED - Failure
1993  *
1994  * ********************************************************************************/
1995 uint8_t MacSchSliceReCfgReq(Pst *pst, SchSliceCfgReq *schSliceReCfgReq)
1996 {
1997    uint8_t count = 0;
1998    Inst   inst = pst->dstInst - SCH_INST_START;
1999    SchSliceCfgRsp schSliceReCfgRsp;
2000
2001    DU_LOG("\nINFO  -->  SCH : Received Slice ReCfg request from MAC");
2002    if(schSliceReCfgReq)
2003    {
2004       if(schSliceReCfgReq->listOfConfirguration)
2005       {
2006          /* filling the slice configuration response of each slice */
2007          if(fillSliceCfgRsp(true, &schCb[inst].sliceCfg, NULLP, schSliceReCfgReq, &schSliceReCfgRsp, &count) != ROK)
2008          {
2009             DU_LOG("\nERROR  -->  SCH : Failed to fill sch slice cfg response");
2010             return RFAILED;
2011          }
2012          
2013          /* Modify the slice configuration stored in schCb */
2014          if(modifySliceCfgInSchDb(&schCb[inst].sliceCfg, schSliceReCfgReq, schSliceReCfgRsp, count) != ROK)
2015          {
2016             DU_LOG("\nERROR  -->  SCH : Failed to modify slice cfg of SchDb");
2017             return RFAILED;
2018          }
2019          SchSendSliceReCfgRspToMac(inst, schSliceReCfgRsp);
2020       }
2021    }
2022    else
2023    {
2024       DU_LOG("\nERROR  -->  SCH : Received SchSliceCfgReq is NULL");
2025    }
2026    return ROK;
2027 }
2028
2029 /****************************************************************************
2030  *
2031  * @brief Stores the Paging Configuration from DU APP in CellCb 
2032  *
2033  * @details
2034  *
2035  *    Function : schProcPagingParam
2036  *
2037  *    Functionality:
2038  *          Process the Paging Configuration when FirstPDCCHMonitoring for
2039  *          Paging Ocassion is not present.
2040  *
2041  *          As per 38.304 Sec 7.1,
2042  *          "When firstPDCCH-MonitoringOccasionOfPO is present, the
2043  *          starting PDCCH monitoring occasion number of (i_s + 1)th PO is the
2044  *          (i_s + 1)th value of the firstPDCCHMonitoringOccasionOfPO
2045  *          parameter; otherwise, it is equal to i_s * S."
2046  *          "S = number of actual transmitted SSBs determined according 
2047  *              to ssb-PositionsInBurst in SIB1"
2048  *
2049  * @params[in] SchCellCb *cell 
2050  *       
2051  * @return void 
2052  *        
2053  *************************************************************************/
2054 void schProcPagingCfg(SchCellCb *cell)
2055 {
2056    PageCfg *pageCfgRcvd = NULL;
2057    uint8_t i_sIdx = 0;
2058
2059    pageCfgRcvd = &(cell->cellCfg.sib1SchCfg.pageCfg);
2060
2061    if(pageCfgRcvd->poPresent == TRUE)
2062    {
2063       /*Fetching first Pdcch Monitoring Occasion for SFN (i_s + 1)th*/
2064       for(i_sIdx = 0; i_sIdx < pageCfgRcvd->numPO; i_sIdx++)
2065       {
2066          cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pageCfgRcvd->pagingOcc[i_sIdx] / MAX_SYMB_PER_SLOT ;
2067          if ((pageCfgRcvd->pagingOcc[i_sIdx] % MAX_SYMB_PER_SLOT) != 0 )
2068          {
2069             cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot++;
2070          }
2071
2072          cell->pageCb.pagMonOcc[i_sIdx].frameOffset = 0;
2073
2074       }
2075    }
2076    else
2077    {
2078       schCfgPdcchMonOccOfPO(cell);                  
2079    }
2080 }
2081
2082 /****************************************************************************
2083  *
2084  * @brief Calculate PO if not present in Configuration 
2085  *
2086  * @details
2087  *
2088  *    Function : schCfgPdcchMonOccOfPO
2089  *
2090  *    Functionality: In this function, PO are calculated i_s * S because
2091  *    FirstPDCCHMonitoring_ForPO is not present.
2092  *
2093  * @params[in] SchCellCb *cellCb
2094  *       
2095  * @return void 
2096  *        
2097  *************************************************************************/
2098 void schCfgPdcchMonOccOfPO(SchCellCb *cell)
2099 {
2100    uint8_t         cnt = 0, incr = 1, i_sIdx = 0, frameOffSet = 0;
2101    uint8_t         nsValue = cell->cellCfg.sib1SchCfg.pageCfg.numPO;
2102    uint8_t         totalNumSsb = cell->cellCfg.ssbSchCfg.totNumSsb;
2103    SlotTimingInfo  tmpTimingInfo, pdcchTime; 
2104
2105    /*Starting with First Sfn and slot*/
2106    tmpTimingInfo.sfn = 0;
2107    tmpTimingInfo.slot = 0;
2108
2109    pdcchTime = tmpTimingInfo;
2110
2111    while(i_sIdx < nsValue)
2112    {
2113       /*Increment frame Offset if PO falls on next SFN*/
2114       if(pdcchTime.sfn != tmpTimingInfo.sfn)
2115       {
2116          frameOffSet++;
2117       }
2118       pdcchTime = tmpTimingInfo;
2119       schIncrSlot(&(tmpTimingInfo), incr, cell->numSlots);
2120
2121       if (i_sIdx == 0)
2122       {
2123          cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2124          cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2125          i_sIdx++;
2126       }
2127       else
2128       {
2129          cnt++;
2130          if((cnt == totalNumSsb) && (i_sIdx < MAX_PO_PER_PF)) 
2131          {
2132             cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2133             cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2134             cnt = 0;
2135             i_sIdx++;
2136          }
2137       }
2138    }
2139 }
2140
2141 /****************************************************************************
2142  *
2143  * @brief Storing the paging information in SCH database 
2144  *
2145  * @details
2146  *
2147  *    Function : schAddPagingIndtoList
2148  *
2149  *    Functionality: Storing the paging information in SCH database
2150  *
2151  * @params[in] CmLListCp *storedPageList, CmLList *pageIndInfo
2152  *       
2153  * @return ROK - sucess
2154  *         RFAILED - failure
2155  *        
2156  *************************************************************************/
2157 uint8_t schAddPagingIndtoList(CmLListCp *storedPageList,void * pageIndInfo)
2158 {
2159    CmLList  *firstNodeOfList = NULLP;
2160    CmLList  *currentNodeInfo = NULLP;
2161    SchPageInfo *tempNode = NULLP, *recvdNode = NULLP;
2162    
2163    recvdNode = (SchPageInfo*) pageIndInfo;
2164    CM_LLIST_FIRST_NODE(storedPageList,firstNodeOfList);
2165    
2166    SCH_ALLOC(currentNodeInfo, sizeof(CmLList));
2167    if(!currentNodeInfo)
2168    {  
2169       DU_LOG("\nERROR  --> SCH : schAddPagingIndtoList() : Memory allocation failed");
2170       return RFAILED;
2171    }
2172    
2173    currentNodeInfo->node = (PTR)pageIndInfo;
2174    while(firstNodeOfList)
2175    {
2176       tempNode = (SchPageInfo*)(firstNodeOfList->node);
2177       if ((recvdNode->pageTxTime.slot < tempNode->pageTxTime.slot))
2178       {
2179          cmLListInsCrnt(storedPageList, currentNodeInfo);
2180          break;
2181       }
2182       else if ((recvdNode->pageTxTime.slot == tempNode->pageTxTime.slot))
2183       {
2184          DU_LOG("\nERROR  --> SCH : schAddPagingIndtoList() : Slot[%d] is already present in the list", recvdNode->pageTxTime.slot);
2185          return RFAILED;
2186       }
2187       else
2188       {
2189          CM_LLIST_NEXT_NODE(storedPageList, firstNodeOfList);
2190       }
2191    } 
2192    
2193    if(!firstNodeOfList)
2194    {
2195       cmLListAdd2Tail(storedPageList, currentNodeInfo);
2196    }
2197    DU_LOG("\nDEBUG   -->  SCH : Paging information is stored successfully for PF:%d, Slot:%d",\
2198               recvdNode->pageTxTime.sfn, recvdNode->pageTxTime.slot);
2199    return ROK;
2200 }
2201
2202 /****************************************************************************
2203  *
2204  * @brief Process paging indication at  SCH recevied form MAC 
2205  *
2206  * @details
2207  *
2208  *    Function : MacSchPagingInd
2209  *
2210  *    Functionality: Process paging indication at SCH recevied form MAC 
2211  *
2212  * @params[in] Pst *pst,  SchPageInd *pageInd 
2213  *       
2214  * @return void 
2215  *        
2216  *************************************************************************/
2217 uint8_t MacSchPagingInd(Pst *pst,  SchPageInd *pageInd)
2218 {
2219    uint8_t ret = RFAILED;
2220    uint16_t cellIdx = 0;
2221    Inst  inst = pst->dstInst - SCH_INST_START;
2222    SchCellCb *cellCb = NULLP;
2223    SchPageInfo *pageInfo = NULLP;
2224
2225    if(pageInd)
2226    {
2227       DU_LOG("\nDEBUG   -->  SCH : Received paging indication from MAC for cellId[%d]",\
2228                   pageInd->cellId);
2229
2230       /* Fetch Cell CB */
2231       for(cellIdx = 0; cellIdx < MAX_NUM_CELL; cellIdx++)
2232       {
2233          if((schCb[inst].cells[cellIdx]) && (schCb[inst].cells[cellIdx]->cellId == pageInd->cellId))
2234          {
2235             cellCb = schCb[inst].cells[cellIdx];
2236             break;
2237          }
2238       }
2239       if(cellCb)
2240       {
2241          if(pageInd->i_s > cellCb->cellCfg.sib1SchCfg.pageCfg.numPO)
2242          {
2243             DU_LOG("\nERROR --> SCH : MacSchPagingInd(): i_s should not be greater than number of paging occasion");
2244          }
2245          else
2246          {
2247             SCH_ALLOC(pageInfo, sizeof(SchPageInfo));
2248             if(pageInfo)
2249             {
2250                pageInfo->pf = pageInd->pf; 
2251                pageInfo->i_s = pageInd->i_s;
2252                pageInfo->pageTxTime.cellId = pageInd->cellId;
2253                pageInfo->pageTxTime.sfn = (pageInd->pf +  cellCb->pageCb.pagMonOcc[pageInd->i_s].frameOffset) % MAX_SFN;
2254                pageInfo->pageTxTime.slot = cellCb->pageCb.pagMonOcc[pageInd->i_s].pagingOccSlot;
2255                pageInfo->mcs = DEFAULT_MCS;
2256                pageInfo->msgLen =  pageInd->pduLen;
2257                SCH_ALLOC(pageInfo->pagePdu, pageInfo->msgLen);
2258                if(!pageInfo->pagePdu)
2259                {
2260                   DU_LOG("\nERROR  --> SCH : MacSchPagingInd(): Failed to allocate memory");
2261                }
2262                else
2263                {
2264                   memcpy(pageInfo->pagePdu, pageInd->pagePdu, pageInfo->msgLen);
2265                   ret = schAddPagingIndtoList(&cellCb->pageCb.pageIndInfoRecord[pageInfo->pageTxTime.sfn], pageInfo);
2266                   if(ret != ROK)
2267                   {
2268                      DU_LOG("\nERROR  --> SCH : MacSchPagingInd(): Failed to store paging record");
2269                   }
2270                }
2271             }
2272             else
2273             {
2274                DU_LOG("\nERROR  --> SCH : MacSchPagingInd(): Failed to allocate memory");
2275             }
2276          }
2277       }
2278       else
2279       {
2280          DU_LOG("\nERROR  -->  SCH : Cell ID [%d] not found", pageInd->cellId);
2281       }
2282       SCH_FREE(pageInd->pagePdu, pageInd->pduLen);
2283       SCH_FREE(pageInd, sizeof(SchPageInd));
2284    }
2285    else
2286    {
2287       DU_LOG("\nERROR  --> SCH : MacSchPagingInd(): Received null pointer");
2288    }
2289    return ret;
2290 }
2291 /**********************************************************************
2292   End of file
2293  **********************************************************************/