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