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