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