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