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