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