e5330cc8e19488bcb7b62a3900769d2f90ffe8fa
[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
62 /**
63  * @brief Task Initiation function. 
64  *
65  * @details
66  *
67  *     Function : schActvInit
68  *     
69  *     This function is supplied as one of parameters during MAC's 
70  *     task registration. MAC will invoke this function once, after
71  *     it creates and attaches this TAPA Task to a system task.
72  *     
73  *  @param[in]  Ent Entity, the entity ID of this task.     
74  *  @param[in]  Inst Inst, the instance ID of this task.
75  *  @param[in]  Region Region, the region ID registered for memory 
76  *              usage of this task.
77  *  @param[in]  Reason Reason.
78  *  @return  int
79  *      -# ROK
80  **/
81 uint8_t schActvInit(Ent entity, Inst instId, Region region, Reason reason)
82 {
83    Inst inst = (instId  - SCH_INST_START);
84
85    /* Initialize the MAC TskInit structure to zero */
86    memset ((uint8_t *)&schCb[inst], 0, sizeof(schCb));
87
88    /* Initialize the MAC TskInit with received values */
89    schCb[inst].schInit.ent = entity;
90    schCb[inst].schInit.inst = inst;
91    schCb[inst].schInit.region = region;
92    schCb[inst].schInit.pool = 0;
93    schCb[inst].schInit.reason = reason;
94    schCb[inst].schInit.cfgDone = FALSE;
95    schCb[inst].schInit.acnt = FALSE;
96    schCb[inst].schInit.usta = FALSE;
97    schCb[inst].schInit.trc = FALSE;
98    schCb[inst].schInit.procId = ODU_GET_PROCID();
99
100    return ROK;
101 } /* schActvInit */
102
103 /**
104  * @brief Scheduler instance Configuration Handler. 
105  *
106  * @details
107  *
108  *     Function : SchInstCfg
109  *     
110  *     This function in called by SchProcGenCfgReq(). It handles the
111  *     general configurations of the scheduler instance. Returns
112  *     reason for success/failure of this function.
113  *     
114  *  @param[in]  RgCfg *cfg, the Configuaration information 
115  *  @return  uint16_t
116  *      -# LCM_REASON_NOT_APPL 
117  *      -# LCM_REASON_INVALID_MSGTYPE
118  *      -# LCM_REASON_MEM_NOAVAIL
119  **/
120 uint8_t SchInstCfg(RgCfg *cfg, Inst  dInst)
121 {
122    uint16_t ret = LCM_REASON_NOT_APPL;
123    Inst     inst = (dInst - SCH_INST_START);
124
125    DU_LOG("\nDEBUG  -->  SCH : Entered SchInstCfg()");
126    /* Check if Instance Configuration is done already */
127    if (schCb[inst].schInit.cfgDone == TRUE)
128    {
129       return LCM_REASON_INVALID_MSGTYPE;
130    }
131    /* Update the Pst structure for LM interface */
132    memcpy(&schCb[inst].schInit.lmPst,
133          &cfg->s.schInstCfg.genCfg.lmPst,
134          sizeof(Pst));
135
136    schCb[inst].schInit.inst = inst;
137    schCb[inst].schInit.lmPst.srcProcId = schCb[inst].schInit.procId;
138    schCb[inst].schInit.lmPst.srcEnt = schCb[inst].schInit.ent;
139    schCb[inst].schInit.lmPst.srcInst = schCb[inst].schInit.inst +
140       SCH_INST_START;
141    schCb[inst].schInit.lmPst.event = EVTNONE;
142
143    schCb[inst].schInit.region = cfg->s.schInstCfg.genCfg.mem.region;
144    schCb[inst].schInit.pool = cfg->s.schInstCfg.genCfg.mem.pool;
145    schCb[inst].genCfg.tmrRes = cfg->s.schInstCfg.genCfg.tmrRes;
146 #ifdef LTE_ADV
147    schCb[inst].genCfg.forceCntrlSrbBoOnPCel =  cfg->s.schInstCfg.genCfg.forceCntrlSrbBoOnPCel;
148    schCb[inst].genCfg.isSCellActDeactAlgoEnable =  cfg->s.schInstCfg.genCfg.isSCellActDeactAlgoEnable;
149 #endif
150    schCb[inst].genCfg.startCellId    = cfg->s.schInstCfg.genCfg.startCellId;
151
152    /* Initialzie the timer queue */   
153    memset(&schCb[inst].tmrTq, 0, sizeof(CmTqType) * SCH_TQ_SIZE);
154    /* Initialize the timer control point */
155    memset(&schCb[inst].tmrTqCp, 0, sizeof(CmTqCp));
156    schCb[inst].tmrTqCp.tmrLen = RGSCH_TQ_SIZE;
157
158    /* SS_MT_TMR needs to be enabled as schActvTmr needs instance information */
159    /* Timer Registration request to system services */
160    if (ODU_REG_TMR_MT(schCb[inst].schInit.ent, dInst,
161             (int)schCb[inst].genCfg.tmrRes, schActvTmr) != ROK)
162    {
163       DU_LOG("\nERROR  -->  SCH : SchInstCfg(): Failed to "
164             "register timer.");
165       return (LCM_REASON_MEM_NOAVAIL);
166    }   
167               
168    /* Set Config done in TskInit */
169    schCb[inst].schInit.cfgDone = TRUE;
170    DU_LOG("\nINFO   -->  SCH : Scheduler gen config done");
171
172    return ret;
173 }
174
175 /**
176  * @brief Layer Manager Configuration request handler. 
177  *
178  * @details
179  *
180  *     Function : SchProcGenCfgReq
181  *     
182  *     This function handles the configuration
183  *     request received at scheduler instance from the Layer Manager.
184  *     -# Based on the cfg->hdr.elmId.elmnt value it invokes one of the
185  *        functions rgHdlGenCfg() or rgHdlSapCfg().
186  *     -# Invokes RgMiLrgSchCfgCfm() to send back the confirmation to the LM.
187  *     
188  *  @param[in]  Pst *pst, the post structure     
189  *  @param[in]  RgMngmt *cfg, the configuration parameter's structure
190  *  @return  S16
191  *      -# ROK
192  **/
193 uint8_t SchProcGenCfgReq(Pst *pst, RgMngmt *cfg)
194 {
195    uint8_t   ret = LCM_PRIM_OK;
196    uint16_t  reason = LCM_REASON_NOT_APPL;
197    RgMngmt   cfm;
198    Pst       cfmPst;
199
200 #ifdef CALL_FLOW_DEBUG_LOG
201    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : GENERAL_CFG_REQ\n");
202 #endif
203
204    if(pst->dstInst < SCH_INST_START)
205    {
206       DU_LOG("\nERROR  -->  SCH : Invalid inst ID");
207       DU_LOG("\nERROR  -->  SCH : SchProcGenCfgReq(): "
208             "pst->dstInst=%d SCH_INST_START=%d", pst->dstInst,SCH_INST_START); 
209       return ROK;
210    }
211    DU_LOG("\nINFO   -->  SCH : Received scheduler gen config");
212    /* Fill the post structure for sending the confirmation */
213    memset(&cfmPst, 0 , sizeof(Pst));
214    SchFillCfmPst(pst, &cfmPst, cfg);
215
216    memset(&cfm, 0, sizeof(RgMngmt));
217
218 #ifdef LMINT3
219    cfm.hdr.transId =
220       cfg->hdr.transId;
221 #endif
222
223    cfm.hdr.elmId.elmnt = cfg->hdr.elmId.elmnt;
224    switch(cfg->hdr.elmId.elmnt)
225    {
226       case STSCHINST:
227          reason = SchInstCfg(&cfg->t.cfg,pst->dstInst );
228          break;
229       default:
230          ret = LCM_PRIM_NOK;
231          reason = LCM_REASON_INVALID_ELMNT;
232          DU_LOG("\nERROR  -->  SCH : Invalid Elmnt=%d", cfg->hdr.elmId.elmnt);
233          break;
234    }
235
236    if (reason != LCM_REASON_NOT_APPL)
237    {
238       ret = LCM_PRIM_NOK;
239    }
240
241    cfm.cfm.status = ret;
242    cfm.cfm.reason = reason;
243
244    SchSendCfgCfm(&cfmPst, &cfm);
245    /*   SCH_FREE(pst->region, pst->pool, (Data *)cfg, sizeof(RgMngmt)); */
246
247    return ROK;
248 }/*-- SchProcGenCfgReq --*/
249
250 /**
251  * @brief slot indication from MAC to SCH.
252  *
253  * @details
254  *
255  *     Function : MacSchSlotInd 
256  *      
257  *      This API is invoked by PHY to indicate slot indication to Scheduler for
258  *      a cell.
259  *           
260  *  @param[in]  Pst            *pst
261  *  @param[in]  SlotTimingInfo    *slotInd
262  *  @return  S16
263  *      -# ROK 
264  *      -# RFAILED 
265  **/
266 uint8_t MacSchSlotInd(Pst *pst, SlotTimingInfo *slotInd)
267 {
268    Inst  inst = pst->dstInst-SCH_INST_START;
269
270 #ifdef CALL_FLOW_DEBUG_LOG
271    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_SLOT_IND_TO_SCH\n");
272 #endif
273
274    schProcessSlotInd(slotInd, inst);
275
276    return ROK;
277 }  /* MacSchSlotInd */
278
279 /*******************************************************************
280  *
281  * @brief Processes Rach indication from MAC 
282  *
283  * @details
284  *
285  *    Function : MacSchRachInd
286  *
287  *    Functionality:
288  *      Processes Rach indication from MAC
289  *
290  * @params[in] 
291  * @return ROK     - success
292  *         RFAILED - failure
293  *
294  * ****************************************************************/
295 uint8_t MacSchRachInd(Pst *pst, RachIndInfo *rachInd)
296 {
297    Inst  inst = pst->dstInst-SCH_INST_START;
298
299 #ifdef CALL_FLOW_DEBUG_LOG
300    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_RACH_IND_TO_SCH\n");
301 #endif
302
303    DU_LOG("\nINFO  -->  SCH : Received Rach indication");
304    schProcessRachInd(rachInd, inst);
305    return ROK;
306 }
307
308 /*******************************************************************
309  *
310  * @brief Processes CRC indication from MAC 
311  *
312  * @details
313  *
314  *    Function : MacSchCrcInd
315  *
316  *    Functionality:
317  *      Processes CRC indication from MAC
318  *
319  * @params[in] Post structure
320  *             Crc Indication
321  * @return ROK     - success
322  *         RFAILED - failure
323  *
324  * ****************************************************************/
325 uint8_t MacSchCrcInd(Pst *pst, CrcIndInfo *crcInd)
326 {
327 #ifdef CALL_FLOW_DEBUG_LOG
328    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_CRC_IND_TO_SCH\n");
329 #endif
330
331    switch(crcInd->crcInd[0])
332    {
333       case CRC_FAILED:
334          DU_LOG("\nDEBUG  -->  SCH : Received CRC indication. CRC Status [FAILURE]");
335          break;
336       case CRC_PASSED:
337          DU_LOG("\nDEBUG  -->  SCH : Received CRC indication. CRC Status [PASS]");
338          break;
339       default:
340          DU_LOG("\nDEBUG  -->  SCH : Invalid CRC state %d", crcInd->crcInd[0]);
341          return RFAILED;
342    }
343    return ROK;
344 }
345
346 #ifdef NR_TDD
347 /**
348  *@brief Returns TDD periodicity in micro seconds
349  *
350  * @details
351  * 
352  * Function : schGetPeriodicityInMsec 
353  * 
354  * This API retunrs TDD periodicity in micro seconds
355  * 
356  * @param[in] DlUlTxPeriodicity 
357  * @return  periodicityInMsec
358  * **/
359
360 uint16_t schGetPeriodicityInMsec(DlUlTxPeriodicity tddPeriod)
361 {
362    uint16_t  periodicityInMsec = 0;
363    switch(tddPeriod)
364    {
365       case TX_PRDCTY_MS_0P5:
366       {
367          periodicityInMsec = 500;
368          break;
369       }
370       case TX_PRDCTY_MS_0P625:
371       {
372          periodicityInMsec = 625;
373          break;
374       }
375       case TX_PRDCTY_MS_1:
376       {
377          periodicityInMsec = 1000;
378          break;
379       }
380       case TX_PRDCTY_MS_1P25:
381       {
382          periodicityInMsec = 1250;
383          break;
384       }
385       case TX_PRDCTY_MS_2:
386       {
387          periodicityInMsec = 2000;
388          break;
389       }
390       case TX_PRDCTY_MS_2P5:
391       {
392          periodicityInMsec = 2500;
393          break;
394       }
395       case TX_PRDCTY_MS_5:
396       {
397          periodicityInMsec = 5000;
398          break;
399       }
400       case TX_PRDCTY_MS_10:
401       {
402          periodicityInMsec = 10000;
403          break;
404       }
405       default:
406       {
407          DU_LOG("\nERROR  -->  SCH : Invalid DlUlTxPeriodicity:%d", tddPeriod);
408       }
409    }
410
411    return periodicityInMsec;
412 }
413
414
415 /**
416  * @brief init TDD slot config 
417  *
418  * @details
419  *
420  *     Function : schInitTddSlotCfg 
421  *      
422  *      This API is invoked after receiving schCellCfg
423  *           
424  *  @param[in]  schCellCb *cell
425  *  @param[in]  SchCellCfg *schCellCfg
426  *  @return  void
427  **/
428 void schInitTddSlotCfg(SchCellCb *cell, SchCellCfg *schCellCfg)
429 {
430    uint16_t periodicityInMicroSec = 0;
431    int8_t slotIdx, symbIdx;
432
433    periodicityInMicroSec = schGetPeriodicityInMsec(schCellCfg->tddCfg.tddPeriod);
434    cell->numSlotsInPeriodicity = (periodicityInMicroSec * pow(2, schCellCfg->numerology))/1000;
435    cell->slotFrmtBitMap = 0;
436    cell->symbFrmtBitMap = 0;
437    for(slotIdx = cell->numSlotsInPeriodicity-1; slotIdx >= 0; slotIdx--)
438    {
439       symbIdx = 0;
440       /* If the first and last symbol are the same, the entire slot is the same type */
441       if((schCellCfg->tddCfg.slotCfg[slotIdx][symbIdx] == schCellCfg->tddCfg.slotCfg[slotIdx][MAX_SYMB_PER_SLOT-1]) &&
442               schCellCfg->tddCfg.slotCfg[slotIdx][symbIdx] != FLEXI_SLOT)
443       {
444          switch(schCellCfg->tddCfg.slotCfg[slotIdx][symbIdx])
445          {
446             case DL_SLOT:
447             {
448                /*BitMap to be set to 00 */
449                cell->slotFrmtBitMap = (cell->slotFrmtBitMap<<2);
450                break;
451             }
452             case UL_SLOT:
453             {
454                /*BitMap to be set to 01 */
455                cell->slotFrmtBitMap = ((cell->slotFrmtBitMap<<2) | (UL_SLOT));
456                break;
457             }
458             default:
459                DU_LOG("\nERROR  -->  SCH : Invalid slot Config in schInitTddSlotCfg");
460            }
461          continue;
462       }
463       /* slot config is flexible. First set slotBitMap to 10 */
464       cell->slotFrmtBitMap = ((cell->slotFrmtBitMap<<2) | (FLEXI_SLOT));
465
466       /* Now set symbol bitmap */ 
467       for(symbIdx = MAX_SYMB_PER_SLOT-1; symbIdx >= 0; symbIdx--)
468       {
469          switch(schCellCfg->tddCfg.slotCfg[slotIdx][symbIdx])
470          {
471             case DL_SLOT:
472             {
473                /*symbol BitMap to be set to 00 */
474                cell->symbFrmtBitMap = (cell->symbFrmtBitMap<<2);
475                break;
476             }
477             case UL_SLOT:
478             {
479                /*symbol BitMap to be set to 01 */
480                cell->symbFrmtBitMap = ((cell->symbFrmtBitMap<<2) | (UL_SLOT));
481                break;
482             }
483             case FLEXI_SLOT:
484             {
485                /*symbol BitMap to be set to 10 */
486                cell->symbFrmtBitMap = ((cell->symbFrmtBitMap<<2) | (FLEXI_SLOT));
487                break;
488             }
489             default:
490                DU_LOG("\nERROR  -->  SCH : Invalid slot Config in schInitTddSlotCfg");
491          }
492       }
493    }
494 }
495 #endif
496
497 /**
498  * @brief Fill SSB start symbol
499  *
500  * @details
501  *
502  *     Function : fillSsbStartSymb 
503  *      
504  *      This API stores SSB start index per beam
505  *           
506  *  @param[in]  SchCellCb     *cellCb
507  *  @return  int
508  *      -# ROK 
509  *      -# RFAILED 
510  **/
511 void fillSsbStartSymb(SchCellCb *cellCb)
512 {
513    uint8_t cnt, scs, symbIdx, ssbStartSymbArr[SCH_MAX_SSB_BEAM];
514
515    scs = cellCb->cellCfg.ssbSchCfg.scsCommon;
516
517    memset(ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
518    symbIdx = 0;
519    /* Determine value of "n" based on Section 4.1 of 3GPP TS 38.213 */
520    switch(scs)
521    {
522       case SCS_15KHZ:
523          {
524             if(cellCb->cellCfg.dlFreq <= 300000)
525                cnt = 2;/* n = 0, 1 */
526             else
527                cnt = 4; /* n = 0, 1, 2, 3 */
528             for(uint8_t idx=0; idx<cnt; idx++)
529             {
530                /* start symbol determined using {2, 8} + 14n */
531                ssbStartSymbArr[symbIdx++] = 2 +  MAX_SYMB_PER_SLOT*idx;
532                ssbStartSymbArr[symbIdx++] = 8 +  MAX_SYMB_PER_SLOT*idx;
533             }
534          }
535          break;
536       case SCS_30KHZ:
537          {
538             if(cellCb->cellCfg.dlFreq <= 300000)
539                cnt = 1;/* n = 0 */
540             else
541                cnt = 2; /* n = 0, 1 */
542             for(uint8_t idx=0; idx<cnt; idx++)
543             {
544                /* start symbol determined using {4, 8, 16, 20} + 28n */
545                ssbStartSymbArr[symbIdx++] = 4 +  MAX_SYMB_PER_SLOT*idx;
546                ssbStartSymbArr[symbIdx++] = 8 +  MAX_SYMB_PER_SLOT*idx;
547                ssbStartSymbArr[symbIdx++] = 16 +  MAX_SYMB_PER_SLOT*idx;
548                ssbStartSymbArr[symbIdx++] = 20 +  MAX_SYMB_PER_SLOT*idx;
549             }
550          }
551          break;
552       default:
553          DU_LOG("\nERROR  -->  SCH : SCS %d is currently not supported", scs);
554    }
555    memset(cellCb->ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
556    memcpy(cellCb->ssbStartSymbArr, ssbStartSymbArr, SCH_MAX_SSB_BEAM);
557
558 }
559
560
561 /**
562  * @brief init cellCb based on cellCfg
563  *
564  * @details
565  *
566  *     Function : schInitCellCb 
567  *      
568  *      This API is invoked after receiving schCellCfg
569  *           
570  *  @param[in]  schCellCb *cell
571  *  @param[in]  SchCellCfg *schCellCfg
572  *  @return  int
573  *      -# ROK 
574  *      -# RFAILED 
575  **/
576 uint8_t schInitCellCb(Inst inst, SchCellCfg *schCellCfg)
577 {
578    SchCellCb *cell= NULLP;
579    SCH_ALLOC(cell, sizeof(SchCellCb));
580    if(!cell)
581    {
582       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb");
583       return RFAILED;
584    }
585
586    cell->cellId = schCellCfg->cellId; 
587    cell->instIdx = inst;
588    switch(schCellCfg->numerology)
589    {
590       case SCH_NUMEROLOGY_0:
591          {
592             cell->numSlots = SCH_MU0_NUM_SLOTS;
593          }
594          break;
595       case SCH_NUMEROLOGY_1:
596          {
597             cell->numSlots = SCH_MU1_NUM_SLOTS;
598          }
599          break;
600       case SCH_NUMEROLOGY_2:
601          {
602             cell->numSlots = SCH_MU2_NUM_SLOTS;
603          }
604          break;
605       case SCH_NUMEROLOGY_3:
606          {
607             cell->numSlots = SCH_MU3_NUM_SLOTS;
608          }
609          break;
610       case SCH_NUMEROLOGY_4:
611          {
612             cell->numSlots = SCH_MU4_NUM_SLOTS;
613          }
614          break;
615       default:
616          DU_LOG("\nERROR  -->  SCH : Numerology %d not supported", schCellCfg->numerology);
617    }
618 #ifdef NR_TDD
619    schInitTddSlotCfg(cell, schCellCfg);   
620 #endif
621
622    SCH_ALLOC(cell->schDlSlotInfo, cell->numSlots * sizeof(SchDlSlotInfo*));
623    if(!cell->schDlSlotInfo)
624    {
625       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb for schDlSlotInfo");
626       return RFAILED;
627    }
628
629    SCH_ALLOC(cell->schUlSlotInfo, cell->numSlots * sizeof(SchUlSlotInfo*));
630    if(!cell->schUlSlotInfo)
631    {
632       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb for schUlSlotInfo");
633       return RFAILED;
634    }
635
636    for(uint8_t idx=0; idx<cell->numSlots; idx++)
637    {
638       SchDlSlotInfo *schDlSlotInfo;
639       SchUlSlotInfo *schUlSlotInfo;
640
641       /* DL Alloc */
642       SCH_ALLOC(schDlSlotInfo, sizeof(SchDlSlotInfo));
643       if(!schDlSlotInfo)
644       {
645          DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb");
646          return RFAILED;
647       }
648
649       /* UL Alloc */
650       SCH_ALLOC(schUlSlotInfo, sizeof(SchUlSlotInfo));
651       if(!schUlSlotInfo)
652       {
653          DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb");
654          return RFAILED;
655       }
656
657       schInitDlSlot(schDlSlotInfo);
658       schInitUlSlot(schUlSlotInfo);
659
660       cell->schDlSlotInfo[idx] = schDlSlotInfo;
661       cell->schUlSlotInfo[idx] = schUlSlotInfo;
662
663    }
664    cell->firstSsbTransmitted = false;
665    cell->firstSib1Transmitted = false;
666    fillSsbStartSymb(cell);
667    cmLListInit(&cell->ueToBeScheduled);
668    schCb[inst].cells[inst] = cell;
669
670    DU_LOG("\nINFO  -->  SCH : Cell init completed for cellId:%d", cell->cellId);
671
672    return ROK;   
673 }
674
675 /**
676  * @brief Fill SIB1 configuration
677  *
678  * @details
679  *
680  *     Function : fillSchSib1Cfg
681  *
682  *     Fill SIB1 configuration
683  *
684  *  @param[in]  uint8_t bandwidth : total available bandwidth
685  *              uint8_t numSlots : total slots per SFN
686  *              SchSib1Cfg *sib1SchCfg : cfg to be filled
687  *              uint16_t pci : physical cell Id
688  *              uint8_t offsetPointA : offset
689  *  @return  void
690  **/
691 void fillSchSib1Cfg(uint8_t mu, uint8_t bandwidth, uint8_t numSlots, SchSib1Cfg *sib1SchCfg, uint16_t pci, uint8_t offsetPointA)
692 {
693    uint8_t coreset0Idx = 0;
694    uint8_t searchSpace0Idx = 0;
695    //uint8_t ssbMuxPattern = 0;
696    uint8_t numRbs = 0;
697    uint8_t numSymbols = 0;
698    uint8_t offset = 0;
699    uint8_t oValue = 0;
700    //uint8_t numSearchSpacePerSlot = 0;
701    uint8_t mValue = 0;
702    uint8_t firstSymbol = 0; /* need to calculate using formula mentioned in 38.213 */
703    uint8_t slotIndex = 0;
704    uint8_t FreqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
705    uint16_t tbSize = 0;
706    uint8_t ssbIdx = 0;
707
708    PdcchCfg *pdcch = &(sib1SchCfg->sib1PdcchCfg);
709    PdschCfg *pdsch = &(sib1SchCfg->sib1PdschCfg);
710    BwpCfg *bwp = &(sib1SchCfg->bwp);
711
712    coreset0Idx     = sib1SchCfg->coresetZeroIndex;
713    searchSpace0Idx = sib1SchCfg->searchSpaceZeroIndex;
714
715    /* derive the sib1 coreset0 params from table 13-1 spec 38.213 */
716    //ssbMuxPattern = coresetIdxTable[coreset0Idx][0];
717    numRbs        = coresetIdxTable[coreset0Idx][1];
718    numSymbols    = coresetIdxTable[coreset0Idx][2];
719    offset        = coresetIdxTable[coreset0Idx][3];
720
721    /* derive the search space params from table 13-11 spec 38.213 */
722    oValue                = searchSpaceIdxTable[searchSpace0Idx][0];
723    //numSearchSpacePerSlot = searchSpaceIdxTable[searchSpace0Idx][1];
724    mValue                = searchSpaceIdxTable[searchSpace0Idx][2];
725    firstSymbol           = searchSpaceIdxTable[searchSpace0Idx][3];
726
727    /* calculate the n0, need to add the formulae, as of now the value is 0 
728     * Need to add the even and odd values of i during configuration 
729     * [(O . 2^u + i . M )  ] mod numSlotsPerSubframe 
730     * assuming u = 0, i = 0, numSlotsPerSubframe = 10
731     * Also, from this configuration, coreset0 is only on even subframe */
732    slotIndex = (int)((oValue*pow(2, mu)) + floor(ssbIdx*mValue))%numSlots;
733    sib1SchCfg->n0 = slotIndex;
734
735    /* fill BWP */
736    switch(bandwidth)
737    {
738       case BANDWIDTH_20MHZ:
739          {
740             bwp->freqAlloc.numPrb = TOTAL_PRB_20MHZ_MU0;
741          }
742          break;
743       case BANDWIDTH_100MHZ:
744          {
745             bwp->freqAlloc.numPrb = TOTAL_PRB_100MHZ_MU1;
746          }
747          break;
748       default:
749          DU_LOG("\nERROR  -->  SCH : Bandwidth %d not supported", bandwidth);
750
751    }
752    bwp->freqAlloc.startPrb = 0;
753    bwp->subcarrierSpacing  = 0;         /* 15Khz */
754    bwp->cyclicPrefix       = 0;              /* normal */
755
756    /* fill the PDCCH PDU */
757    pdcch->coresetCfg.coreSetSize = numRbs;
758    pdcch->coresetCfg.startSymbolIndex = firstSymbol;
759    pdcch->coresetCfg.durationSymbols = numSymbols;
760    
761    /* Fill Bitmap for PRBs in coreset */
762    fillCoresetFeqDomAllocMap(((offsetPointA-offset)/6), (numRbs/6), FreqDomainResource);
763    covertFreqDomRsrcMapToIAPIFormat(FreqDomainResource, pdcch->coresetCfg.freqDomainResource);
764
765    pdcch->coresetCfg.cceRegMappingType = 1; /* coreset0 is always interleaved */
766    pdcch->coresetCfg.regBundleSize = 6;    /* spec-38.211 sec 7.3.2.2 */
767    pdcch->coresetCfg.interleaverSize = 2;  /* spec-38.211 sec 7.3.2.2 */
768    pdcch->coresetCfg.coreSetType = 0;
769    pdcch->coresetCfg.shiftIndex = pci;
770    pdcch->coresetCfg.precoderGranularity = 0; /* sameAsRegBundle */
771    pdcch->numDlDci = 1;
772    pdcch->dci.rnti = SI_RNTI;
773    pdcch->dci.scramblingId = pci;
774    pdcch->dci.scramblingRnti = 0;
775    pdcch->dci.cceIndex = 0;
776    pdcch->dci.aggregLevel = 4;
777    pdcch->dci.beamPdcchInfo.numPrgs = 1;
778    pdcch->dci.beamPdcchInfo.prgSize = 1;
779    pdcch->dci.beamPdcchInfo.digBfInterfaces = 0;
780    pdcch->dci.beamPdcchInfo.prg[0].pmIdx = 0;
781    pdcch->dci.beamPdcchInfo.prg[0].beamIdx[0] = 0;
782    pdcch->dci.txPdcchPower.powerValue = 0;
783    pdcch->dci.txPdcchPower.powerControlOffsetSS = 0;
784    /* Storing pdschCfg pointer here. Required to access pdsch config while
785       fillig up pdcch pdu */
786    pdcch->dci.pdschCfg = pdsch; 
787
788    /* fill the PDSCH PDU */
789    uint8_t cwCount = 0;
790    pdsch->pduBitmap = 0; /* PTRS and CBG params are excluded */
791    pdsch->rnti = 0xFFFF; /* SI-RNTI */
792    pdsch->pduIndex = 0;
793    pdsch->numCodewords = 1;
794    for(cwCount = 0; cwCount < pdsch->numCodewords; cwCount++)
795    {
796       pdsch->codeword[cwCount].targetCodeRate = 308;
797       pdsch->codeword[cwCount].qamModOrder = 2;
798       pdsch->codeword[cwCount].mcsIndex = sib1SchCfg->sib1Mcs;
799       pdsch->codeword[cwCount].mcsTable = 0; /* notqam256 */
800       pdsch->codeword[cwCount].rvIndex = 0;
801       tbSize = schCalcTbSize(sib1SchCfg->sib1PduLen + TX_PAYLOAD_HDR_LEN);
802       pdsch->codeword[cwCount].tbSize = tbSize;
803    }
804    pdsch->dataScramblingId                   = pci;
805    pdsch->numLayers                          = 1;
806    pdsch->transmissionScheme                 = 0;
807    pdsch->refPoint                           = 0;
808    pdsch->dmrs.dlDmrsSymbPos                 = 4; /* Bitmap value 00000000000100 i.e. using 3rd symbol for PDSCH DMRS */
809    pdsch->dmrs.dmrsConfigType                = 0; /* type-1 */
810    pdsch->dmrs.dlDmrsScramblingId            = pci;
811    pdsch->dmrs.scid                          = 0;
812    pdsch->dmrs.numDmrsCdmGrpsNoData          = 1;
813    pdsch->dmrs.dmrsPorts                     = 0x0001;
814    pdsch->dmrs.mappingType                   = DMRS_MAP_TYPE_A; /* Type-A */
815    pdsch->dmrs.nrOfDmrsSymbols               = NUM_DMRS_SYMBOLS;
816    pdsch->dmrs.dmrsAddPos                    = DMRS_ADDITIONAL_POS;
817
818    pdsch->pdschFreqAlloc.resourceAllocType   = 1; /* RAT type-1 RIV format */
819    /* the RB numbering starts from coreset0, and PDSCH is always above SSB */
820    pdsch->pdschFreqAlloc.freqAlloc.startPrb  = offsetPointA + SCH_SSB_NUM_PRB;
821    pdsch->pdschFreqAlloc.freqAlloc.numPrb    = schCalcNumPrb(tbSize,sib1SchCfg->sib1Mcs, NUM_PDSCH_SYMBOL);
822    pdsch->pdschFreqAlloc.vrbPrbMapping       = 0; /* non-interleaved */
823    pdsch->pdschTimeAlloc.rowIndex            = 1;
824    /* This is Intel's requirement. PDSCH should start after PDSCH DRMS symbol */
825    pdsch->pdschTimeAlloc.timeAlloc.startSymb = 3; /* spec-38.214, Table 5.1.2.1-1 */
826    pdsch->pdschTimeAlloc.timeAlloc.numSymb   = NUM_PDSCH_SYMBOL;
827    pdsch->beamPdschInfo.numPrgs              = 1;
828    pdsch->beamPdschInfo.prgSize              = 1;
829    pdsch->beamPdschInfo.digBfInterfaces      = 0;
830    pdsch->beamPdschInfo.prg[0].pmIdx         = 0;
831    pdsch->beamPdschInfo.prg[0].beamIdx[0]    = 0;
832    pdsch->txPdschPower.powerControlOffset    = 0;
833    pdsch->txPdschPower.powerControlOffsetSS  = 0;
834
835 }
836
837 /**
838  * @brief cell config from MAC to SCH.
839  *
840  * @details
841  *
842  *     Function : macSchCellCfgReq
843  *      
844  *      This API is invoked by MAC to send cell config to SCH
845  *           
846  *  @param[in]  Pst            *pst
847  *  @param[in]  SchCellCfg     *schCellCfg
848  *  @return  int
849  *      -# ROK 
850  *      -# RFAILED 
851  **/
852 uint8_t SchHdlCellCfgReq(Pst *pst, SchCellCfg *schCellCfg)
853 {
854    uint8_t ret = ROK;
855    SchCellCb *cellCb;
856    SchCellCfgCfm schCellCfgCfm;
857    Pst rspPst;
858    Inst inst = pst->dstInst-1; 
859    uint8_t coreset0Idx = 0;
860    uint8_t numRbs = 0;
861    uint8_t offset = 0;
862    uint8_t freqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
863    SchPdschConfig pdschCfg;
864
865 #ifdef CALL_FLOW_DEBUG_LOG
866    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_SCH_CELL_CFG\n");
867 #endif 
868
869    schInitCellCb(inst, schCellCfg);
870    cellCb = schCb[inst].cells[inst]; //cells is of MAX_CELLS, why inst
871    cellCb->macInst = pst->srcInst;
872
873    /* derive the SIB1 config parameters */
874    fillSchSib1Cfg(schCellCfg->numerology, schCellCfg->bandwidth, cellCb->numSlots,
875          &(schCellCfg->sib1SchCfg), schCellCfg->phyCellId,
876          schCellCfg->ssbSchCfg.ssbOffsetPointA);
877    memcpy(&cellCb->cellCfg, schCellCfg, sizeof(SchCellCfg));
878
879    /* Fill coreset frequencyDomainResource bitmap */
880    coreset0Idx = cellCb->cellCfg.schInitialDlBwp.pdcchCommon.commonSearchSpace.coresetId;
881    numRbs = coresetIdxTable[coreset0Idx][1];
882    offset = coresetIdxTable[coreset0Idx][3];
883    fillCoresetFeqDomAllocMap(((cellCb->cellCfg.ssbSchCfg.ssbOffsetPointA - offset)/6), (numRbs/6), freqDomainResource);
884    covertFreqDomRsrcMapToIAPIFormat(freqDomainResource, \
885       cellCb->cellCfg.schInitialDlBwp.pdcchCommon.commonSearchSpace.freqDomainRsrc);
886
887    /* Fill K0 - K1 table for common cfg*/ 
888    BuildK0K1Table(cellCb, &cellCb->cellCfg.schInitialDlBwp.k0K1InfoTbl, true, cellCb->cellCfg.schInitialDlBwp.pdschCommon,
889    pdschCfg, DEFAULT_UL_ACK_LIST_COUNT, defaultUlAckTbl);
890    
891    BuildK2InfoTable(cellCb, cellCb->cellCfg.schInitialUlBwp.puschCommon.timeDomRsrcAllocList,\
892    cellCb->cellCfg.schInitialUlBwp.puschCommon.numTimeDomRsrcAlloc, &cellCb->cellCfg.schInitialUlBwp.msg3K2InfoTbl, \
893    &cellCb->cellCfg.schInitialUlBwp.k2InfoTbl);
894    /* Initializing global variables */
895    cellCb->actvUeBitMap = 0;
896    cellCb->boIndBitMap = 0;
897
898    /* Fill and send Cell config confirm */
899    memset(&rspPst, 0, sizeof(Pst));
900    FILL_PST_SCH_TO_MAC(rspPst, pst->dstInst);
901    rspPst.event = EVENT_SCH_CELL_CFG_CFM;
902
903    schCellCfgCfm.cellId = schCellCfg->cellId; 
904    schCellCfgCfm.rsp = RSP_OK;
905
906    ret = (*SchCellCfgCfmOpts[rspPst.selector])(&rspPst, &schCellCfgCfm);
907    return ret;
908
909 }
910
911 /*******************************************************************
912  *
913  * @brief Processes DL RLC BO info from MAC
914  *
915  * @details
916  *
917  *    Function : MacSchDlRlcBoInfo
918  *
919  *    Functionality:
920  *       Processes DL RLC BO info from MAC
921  *
922  * @params[in] 
923  * @return ROK     - success
924  *         RFAILED - failure
925  *
926  * ****************************************************************/
927 uint8_t MacSchDlRlcBoInfo(Pst *pst, DlRlcBoInfo *dlBoInfo)
928 {
929    uint8_t  lcId = 0;
930    uint16_t ueId = 0;
931    bool isLcIdValid = false;
932    SchUeCb *ueCb = NULLP;
933    SchCellCb *cell = NULLP;
934    Inst  inst = pst->dstInst-SCH_INST_START;
935    CmLListCp *lcLL = NULLP;
936
937 #ifdef CALL_FLOW_DEBUG_LOG
938    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_DL_RLC_BO_INFO_TO_SCH\n");
939 #endif
940
941    DU_LOG("\nDEBUG  -->  SCH : Received RLC BO Status indication LCId [%d] BO [%d]", dlBoInfo->lcId, dlBoInfo->dataVolume);
942    cell = schCb[inst].cells[inst];
943
944    if(cell == NULLP)
945    {
946       DU_LOG("\nERROR  -->  SCH : MacSchDlRlcBoInfo(): Cell does not exists");
947       return RFAILED;
948    }
949
950    GET_UE_IDX(dlBoInfo->crnti, ueId);
951    ueCb = &cell->ueCb[ueId-1];
952    lcId  = dlBoInfo->lcId;
953    CHECK_LCID(lcId, isLcIdValid);
954    if(isLcIdValid == FALSE)
955    {
956       DU_LOG("ERROR --> SCH: LCID:%d is not valid", lcId);
957       return RFAILED;
958    }
959
960    /*Expected when theres a case of Retransmission Failure or Resetablishment
961     *By Zero BO, the RLC is informing that previous data can be cleared out
962     *Thus clearing out the LC from the Lc priority list*/
963    if(dlBoInfo->dataVolume == 0)
964    {
965       /*Check the LC is Dedicated or default and accordingly LCList will
966        * be used*/
967       if(ueCb->dlInfo.dlLcCtxt[lcId].isDedicated)
968       {
969          lcLL = &(ueCb->dlLcPrbEst.dedLcInfo->dedLcList);
970       }
971       else
972       {
973          lcLL = &(ueCb->dlLcPrbEst.defLcList);
974       }
975       handleLcLList(lcLL, lcId, DELETE);
976       return ROK;
977    }
978
979    if(lcId == SRB0_LCID)
980    {
981       cell->raCb[ueId -1].msg4recvd = true;
982       cell->raCb[ueId -1].dlMsgPduLen = dlBoInfo->dataVolume;
983       
984    }
985    else
986    {
987       /* TODO : These part of changes will be corrected during DL scheduling as
988        * per K0 - K1 -K2 */
989       SET_ONE_BIT(ueId, cell->boIndBitMap);
990       if(ueCb->dlInfo.dlLcCtxt[lcId].lcId == lcId)
991       {
992          ueCb->dlInfo.dlLcCtxt[lcId].bo = dlBoInfo->dataVolume;
993       }
994       else
995       {
996          DU_LOG("ERROR --> SCH: LCID:%d is not configured in SCH Cb",lcId);
997          return RFAILED;
998       }
999    }
1000    
1001    /* Adding UE Id to list of pending UEs to be scheduled */
1002    addUeToBeScheduled(cell, ueId);
1003    return ROK;
1004 }
1005
1006 /*******************************************************************
1007  *
1008  * @brief Processes BSR indiation from MAC
1009  *
1010  * @details
1011  *
1012  *    Function : MacSchBsr
1013  *
1014  *    Functionality:
1015  *       Processes DL BSR from MAC
1016  *
1017  * @params[in]    Pst pst
1018  *                UlBufferStatusRptInd bsrInd
1019  * @return ROK     - success
1020  *         RFAILED - failure
1021  *
1022  * ****************************************************************/
1023 uint8_t MacSchBsr(Pst *pst, UlBufferStatusRptInd *bsrInd)
1024 {
1025    Inst           schInst       = pst->dstInst-SCH_INST_START;
1026    SchCellCb      *cellCb       = NULLP;
1027    SchUeCb        *ueCb         = NULLP;
1028    uint8_t        lcgIdx = 0;
1029
1030 #ifdef CALL_FLOW_DEBUG_LOG
1031    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_SHORT_BSR\n");
1032 #endif
1033
1034    DU_LOG("\nDEBUG  -->  SCH : Received BSR");
1035    if(bsrInd == NULLP)
1036    {
1037       DU_LOG("\nERROR  -->  SCH : BSR Ind is empty");
1038       return RFAILED;
1039    }
1040    cellCb = schCb[schInst].cells[schInst];
1041    if(cellCb == NULLP)
1042    {
1043       DU_LOG("\nERROR  -->  SCH : CellCb is empty");
1044       return RFAILED;
1045    }
1046    ueCb = schGetUeCb(cellCb, bsrInd->crnti);
1047
1048    if(ueCb == NULLP)
1049    {
1050       DU_LOG("\nERROR  -->  SCH : UeCB is empty");
1051       return RFAILED;
1052    }
1053
1054    ueCb->bsrRcvd = true;
1055    /* store dataVolume per lcg in uecb */
1056    for(lcgIdx = 0; lcgIdx < bsrInd->numLcg; lcgIdx++)
1057    {
1058       ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].priority = 1; //TODO: determining LCG priority?
1059       ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].dataVol = bsrInd->dataVolInfo[lcgIdx].dataVol;
1060    }
1061    
1062    /* Adding UE Id to list of pending UEs to be scheduled */
1063    addUeToBeScheduled(cellCb, ueCb->ueIdx);
1064    return ROK;
1065 }
1066
1067 /*******************************************************************
1068  *
1069  * @brief Processes SR UCI indication from MAC 
1070  *
1071  * @details
1072  *
1073  *    Function : MacSchSrUciInd
1074  *
1075  *    Functionality:
1076  *      Processes SR UCI indication from MAC
1077  *
1078  * @params[in] Post structure
1079  *             UCI Indication
1080  * @return ROK     - success
1081  *         RFAILED - failure
1082  *
1083  * ****************************************************************/
1084 uint8_t MacSchSrUciInd(Pst *pst, SrUciIndInfo *uciInd)
1085 {
1086    Inst  inst = pst->dstInst-SCH_INST_START;
1087
1088    SchUeCb   *ueCb; 
1089    SchCellCb *cellCb = schCb[inst].cells[inst];
1090
1091 #ifdef CALL_FLOW_DEBUG_LOG
1092    DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_UCI_IND_TO_SCH\n");
1093 #endif
1094
1095    DU_LOG("\nDEBUG  -->  SCH : Received SR");
1096
1097    ueCb = schGetUeCb(cellCb, uciInd->crnti);
1098    
1099    if(ueCb->state == SCH_UE_STATE_INACTIVE)
1100    {
1101       DU_LOG("\nERROR  -->  SCH : Crnti %d is inactive", uciInd->crnti);
1102       return ROK;  
1103    }
1104
1105    if(uciInd->numSrBits)
1106    {
1107       ueCb->srRcvd = true;
1108       
1109       /* Adding UE Id to list of pending UEs to be scheduled */
1110       addUeToBeScheduled(cellCb, ueCb->ueIdx);
1111    }
1112    return ROK;
1113 }
1114
1115 /*******************************************************************
1116  *
1117  * @brief Allocates requested PRBs for DL
1118  *
1119  * @details
1120  *
1121  *    Function : allocatePrbDl
1122  *
1123  *    Functionality:
1124  *      Allocates requested PRBs in DL
1125  *      Keeps track of allocated PRB (using bitmap) and remaining PRBs
1126  *
1127  * @params[in] prbAlloc table
1128  *             Start symbol
1129  *             Number of symbols
1130  *             Start PRB
1131  *             Number of PRBs
1132  *
1133  * @return ROK     - success
1134  *         RFAILED - failure
1135  *
1136  * ****************************************************************/
1137 uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
1138    uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1139 {
1140    uint8_t        symbol = 0;
1141    uint16_t       broadcastPrbStart=0, broadcastPrbEnd=0;
1142    FreePrbBlock   *freePrbBlock = NULLP;
1143    CmLList        *freePrbNode = NULLP;
1144    PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
1145    SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1146    SchPrbAlloc    *prbAlloc = &schDlSlotInfo->prbAlloc;
1147
1148    /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1149     * Search for an appropriate location in PRB grid and allocate requested resources */
1150    if(*startPrb == MAX_NUM_RB)
1151    {
1152       /* Check if SSB/SIB1 is also scheduled in this slot  */
1153       ssbOccasion = schCheckSsbOcc(cell, slotTime);
1154       sib1Occasion = schCheckSib1Occ(cell, slotTime);
1155
1156       if(ssbOccasion && sib1Occasion)
1157       {
1158          broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA; 
1159          broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1160       }
1161       else if(ssbOccasion)
1162       {
1163          broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
1164          broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB -1;
1165       }
1166       else if(sib1Occasion)
1167       {
1168          broadcastPrbStart = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.startPrb;
1169          broadcastPrbEnd = broadcastPrbStart + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1170       }
1171
1172       /* Iterate through all free PRB blocks */
1173       freePrbNode = prbAlloc->freePrbBlockList.first; 
1174       while(freePrbNode)
1175       {
1176          freePrbBlock = (FreePrbBlock *)freePrbNode->node; 
1177
1178          /* If broadcast message is scheduled in this slot, then check if its PRBs belong to the current free block.
1179           * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1180          if((ssbOccasion || sib1Occasion) && 
1181             ((broadcastPrbStart >= freePrbBlock->startPrb) && (broadcastPrbStart <= freePrbBlock->endPrb)) && \
1182             ((broadcastPrbEnd >= freePrbBlock->startPrb) && (broadcastPrbEnd <= freePrbBlock->endPrb)))
1183          {
1184             /* Implmentation is done such that highest-numbered free-RB is allocated first */ 
1185             if((freePrbBlock->endPrb > broadcastPrbEnd) && ((freePrbBlock->endPrb - broadcastPrbEnd) >= numPrb))
1186             {
1187                /* If sufficient free PRBs are available above bradcast message then,
1188                 * endPrb = freePrbBlock->endPrb
1189                 * startPrb = endPrb - numPrb +1;
1190                 */
1191                *startPrb = freePrbBlock->endPrb - numPrb +1;
1192                break;
1193             }
1194             else if((broadcastPrbStart > freePrbBlock->startPrb) && ((broadcastPrbStart - freePrbBlock->startPrb) >= numPrb))
1195             {
1196                /* If free PRBs are available below broadcast message then,
1197                 * endPrb = broadcastPrbStart - 1
1198                 * startPrb = endPrb - numPrb +1
1199                 */
1200                *startPrb = broadcastPrbStart - numPrb; 
1201                break;
1202             }
1203             else
1204             {
1205                freePrbNode = freePrbNode->next;
1206                continue;
1207             }
1208          }
1209          else
1210          {
1211             /* Check if requested number of blocks can be allocated from the current block */ 
1212             if (freePrbBlock->numFreePrb < numPrb)
1213             {
1214                freePrbNode = freePrbNode->next;
1215                continue;
1216             }
1217             *startPrb = freePrbBlock->endPrb - numPrb +1;
1218             break;  
1219          }
1220       }
1221
1222       /* If no free block can be used to allocated request number of RBs */
1223       if(*startPrb == MAX_NUM_RB)
1224          return RFAILED;
1225    }
1226
1227    /* If startPrb is known already, check if requested PRBs are available for allocation */
1228    else
1229    {
1230       freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1231       if(!freePrbNode)
1232       {
1233          DU_LOG("\nERROR  -->  SCH: Requested DL PRB unavailable");
1234          return RFAILED;
1235       }
1236    }
1237
1238    /* Update bitmap to allocate PRBs */
1239    for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1240    {
1241       if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1242       {
1243          DU_LOG("\nERROR  -->  SCH: fillPrbBitmap() failed for symbol [%d] in DL", symbol);
1244          return RFAILED;
1245       }
1246    }
1247
1248    /* Update the remaining number for free PRBs */
1249    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1250
1251    return ROK;
1252 }
1253
1254 /*******************************************************************
1255  *
1256  * @brief Allocates requested PRBs for UL
1257  *
1258  * @details
1259  *
1260  *    Function : allocatePrbUl
1261  *
1262  *    Functionality:
1263  *      Allocates requested PRBs in UL
1264  *      Keeps track of allocated PRB (using bitmap) and remaining PRBs
1265  *
1266  * @params[in] prbAlloc table
1267  *             Start symbol
1268  *             Number of symbols
1269  *             Start PRB
1270  *             Number of PRBs
1271  *
1272  * @return ROK     - success
1273  *         RFAILED - failure
1274  *
1275  * ****************************************************************/
1276 uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
1277    uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1278 {
1279    uint8_t        symbol = 0;
1280    uint16_t       prachStartPrb, prachNumPrb, prachEndPrb;
1281    bool           isPrachOccasion;
1282    FreePrbBlock   *freePrbBlock = NULLP;
1283    CmLList        *freePrbNode = NULLP;
1284    SchPrbAlloc    *prbAlloc = NULLP;
1285
1286    if(cell == NULLP)
1287    {
1288       DU_LOG("\nERROR  --> SCH : allocatePrbUl(): Received cellCb is null");
1289       return RFAILED;
1290    }
1291    
1292    prbAlloc =   &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1293    /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1294     * Search for an appropriate location in PRB grid and allocate requested resources */
1295    if(*startPrb == MAX_NUM_RB)
1296    {
1297       /* Check if PRACH is also scheduled in this slot */
1298       isPrachOccasion = schCheckPrachOcc(cell, slotTime);
1299       if(isPrachOccasion)
1300       {
1301          prachStartPrb =  cell->cellCfg.schRachCfg.msg1FreqStart;
1302          prachNumPrb = schCalcPrachNumRb(cell);
1303          prachEndPrb = prachStartPrb + prachNumPrb -1;
1304       }
1305
1306       /* Iterate through all free PRB blocks */
1307       freePrbNode = prbAlloc->freePrbBlockList.first; 
1308       while(freePrbNode)
1309       {
1310          freePrbBlock = (FreePrbBlock *)freePrbNode->node; 
1311
1312          /* If PRACH is scheduled in this slot, then check if its PRBs belong to the current free block.
1313           * PRBs required for PRACH cannot be allocated to any other message */
1314          if((isPrachOccasion) &&
1315             ((prachStartPrb >= freePrbBlock->startPrb) && (prachStartPrb <= freePrbBlock->endPrb)) &&
1316             ((prachEndPrb >= freePrbBlock->startPrb) && (prachEndPrb <= freePrbBlock->endPrb)))
1317          {
1318             /* Implmentation is done such that highest-numbered free-RB is allocated first */ 
1319             if((freePrbBlock->endPrb > prachEndPrb) && ((freePrbBlock->endPrb - prachEndPrb) >= numPrb))
1320             {
1321                /* If sufficient free PRBs are available above PRACH message then,
1322                 * endPrb = freePrbBlock->endPrb
1323                 * startPrb = endPrb - numPrb +1;
1324                 */
1325                *startPrb = freePrbBlock->endPrb - numPrb +1;
1326                break;
1327             }
1328             else if((prachStartPrb > freePrbBlock->startPrb) && ((prachStartPrb - freePrbBlock->startPrb) >= numPrb))
1329             {
1330                /* If free PRBs are available below PRACH message then,
1331                 * endPrb = prachStartPrb - 1
1332                 * startPrb = endPrb - numPrb +1
1333                 */
1334                *startPrb = prachStartPrb - numPrb; 
1335                break;
1336             }
1337             else
1338             {
1339                freePrbNode = freePrbNode->next;
1340                continue;
1341             } 
1342          }
1343          else
1344          {
1345             /* Check if requested number of PRBs can be allocated from currect block */
1346             if(freePrbBlock->numFreePrb < numPrb)
1347             {
1348                freePrbNode = freePrbNode->next;
1349                continue;
1350             }
1351             *startPrb = freePrbBlock->endPrb - numPrb +1;
1352             break;
1353          }
1354       }
1355
1356       /* If no free block can be used to allocated requested number of RBs */
1357       if(*startPrb == MAX_NUM_RB)
1358          return RFAILED;
1359    }
1360    else
1361    {
1362       /* If startPrb is known already, check if requested PRBs are available for allocation */
1363       freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1364       if(!freePrbNode)
1365       {
1366          DU_LOG("\nERROR  -->  SCH: Requested UL PRB unavailable");
1367          return RFAILED;
1368       }
1369    }
1370
1371    /* Update bitmap to allocate PRBs */
1372    for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1373    {
1374       if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1375       {
1376          DU_LOG("\nERROR  -->  SCH: fillPrbBitmap() failed for symbol [%d] in UL", symbol);
1377          return RFAILED;
1378       }
1379    }
1380
1381    /* Update the remaining number for free PRBs */
1382    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1383
1384    return ROK;
1385 }
1386
1387 /*******************************************************************
1388  *
1389  * @brief Add UE to ueToBeScheduled List
1390  *
1391  * @details
1392  *
1393  *    Function : addUeToBeScheduled
1394  *
1395  *    Functionality:
1396  *      Search if UE entry present in the list
1397  *      If yes, return.
1398  *      If no, add UE to the list
1399  *
1400  * @params[in] Cell control block
1401  *             Ue Idx to be added
1402  *
1403  * @return ROK     - success
1404  *         RFAILED - failure
1405  *
1406  * ****************************************************************/
1407 uint8_t addUeToBeScheduled(SchCellCb *cell, uint8_t ueIdToAdd)
1408 {
1409    uint8_t *ueId;
1410    CmLList *node;
1411
1412    /* Search if UE entry is already present in ueToBeScheduled list.
1413     * If yes, another entry for same UE not needed. Hence, return */
1414    node = cell->ueToBeScheduled.first;
1415    while(node)
1416    {
1417       ueId = (uint8_t *)node->node;
1418       if(*ueId == ueIdToAdd)
1419          return ROK;
1420       node = node->next;
1421    }
1422
1423    /* If UE entry not present already, add UE to the end of ueToBeScheduled list */
1424    SCH_ALLOC(ueId, sizeof(uint8_t));
1425    if(!ueId)
1426    {
1427       DU_LOG("\nERROR  -->  SCH : Memory allocation failure in addUeToBeScheduled");
1428       return RFAILED;
1429    }
1430    *ueId = ueIdToAdd;
1431    if(addNodeToLList(&cell->ueToBeScheduled, ueId, NULLP) != ROK)
1432    {
1433       DU_LOG("\nERROR  --> SCH : Failed to add UeIdx to cell->ueToBeScheduled list");
1434       return RFAILED;
1435    }
1436    return ROK;
1437 }
1438  
1439 /*******************************************************************************
1440  *
1441  * @brief Try to find Best Free Block with Max Num PRB 
1442  *
1443  * @details
1444  *
1445  *    Function : searchLargestFreeBlock
1446  *
1447  *    Functionality:
1448  *     Finds the FreeBlock with MaxNum of FREE PRB considering SSB/SIB1 ocassions.
1449  *
1450  * @params[in] I/P > prbAlloc table (FreeBlock list)
1451  *             I/P > Slot timing Info
1452  *             O/P > Start PRB
1453  *             I/P > Direction (UL/DL)
1454  *       
1455  *
1456  * @return Max Number of Free PRB 
1457  *         If 0, then no Suitable Free Block
1458  *
1459  * ********************************************************************************/
1460
1461 uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_t *startPrb, Direction dir)
1462 {
1463    uint16_t       reservedPrbStart=0, reservedPrbEnd=0, maxFreePRB = 0;
1464    FreePrbBlock   *freePrbBlock = NULLP;
1465    CmLList        *freePrbNode = NULLP;
1466    SchPrbAlloc    *prbAlloc = NULLP;
1467    bool           checkOccasion = FALSE;
1468
1469    *startPrb = 0; /*Initialize the StartPRB to zero*/
1470
1471    /*Based on Direction, Reserved Messsages will differi.e.
1472     * DL >> SSB and SIB1 ocassions wheres for UL, PRACH ocassions to be checked
1473     * and reserved before allocation for dedicated DL/UL msg*/
1474    if(dir == DIR_DL)
1475    {
1476       SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1477       PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
1478
1479       prbAlloc = &schDlSlotInfo->prbAlloc;
1480
1481       ssbOccasion = schCheckSsbOcc(cell, slotTime);
1482       sib1Occasion = schCheckSib1Occ(cell, slotTime);
1483
1484       checkOccasion = TRUE;
1485       if(ssbOccasion && sib1Occasion)
1486       {
1487          reservedPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA; 
1488          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB + \
1489                           cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1490       }
1491       else if(ssbOccasion)
1492       {
1493          reservedPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
1494          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB -1;
1495       }
1496       else if(sib1Occasion)
1497       {
1498          reservedPrbStart = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.startPrb;
1499          reservedPrbEnd = reservedPrbStart + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1500       }
1501       else
1502       {
1503          checkOccasion = FALSE;  
1504       }
1505    }
1506    else if(dir == DIR_UL)
1507    {
1508       prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1509
1510       /* Check if PRACH is also scheduled in this slot */
1511       checkOccasion = schCheckPrachOcc(cell, slotTime);
1512       if(checkOccasion)
1513       {
1514          reservedPrbStart =  cell->cellCfg.schRachCfg.msg1FreqStart;
1515          reservedPrbEnd = reservedPrbStart + (schCalcPrachNumRb(cell)) -1;
1516       }
1517    }
1518    else
1519    {
1520       DU_LOG("\nERROR --> SCH: Invalid Direction!");
1521       return (maxFreePRB);
1522    }
1523
1524    freePrbNode = prbAlloc->freePrbBlockList.first; 
1525    while(freePrbNode)
1526    {
1527       freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1528
1529       /*For block with same numFreeBlocks, choose the one with HighestPRB range
1530        *Since FreeBLockList are arranged in Descending order of PRB range thus Skipping this block*/
1531       if(maxFreePRB >= freePrbBlock->numFreePrb) 
1532       {
1533          //skip this block
1534          freePrbNode = freePrbNode->next;
1535          continue;
1536       }
1537
1538       /* If Broadcast/Prach message is scheduled in this slot, then check if its PRBs belong to the current free block.
1539        * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1540       if(checkOccasion && 
1541             ((reservedPrbStart >= freePrbBlock->startPrb) && (reservedPrbStart <= freePrbBlock->endPrb)) && \
1542             ((reservedPrbEnd >= freePrbBlock->startPrb) && (reservedPrbEnd <= freePrbBlock->endPrb)))
1543       {
1544
1545          /* Implmentation is done such that highest-numbered free-RB is Checked first
1546             and freePRB in this block is greater than Max till now */
1547          if((freePrbBlock->endPrb > reservedPrbEnd) && ((freePrbBlock->endPrb - reservedPrbEnd) > maxFreePRB))
1548          {
1549             /* If sufficient free PRBs are available above reserved message*/
1550             *startPrb = reservedPrbEnd + 1;
1551             maxFreePRB = (freePrbBlock->endPrb - reservedPrbEnd);                
1552          }
1553          /*Also check the other freeBlock (i.e. Above the reserved message) for MAX FREE PRB*/
1554          if((reservedPrbStart > freePrbBlock->startPrb) && ((reservedPrbStart - freePrbBlock->startPrb) > maxFreePRB))
1555          {
1556             /* If free PRBs are available below reserved message*/
1557             *startPrb = freePrbBlock->startPrb;
1558             maxFreePRB = (reservedPrbStart - freePrbBlock->startPrb);
1559          }
1560       }
1561       else  //Best Block
1562       {
1563          if(maxFreePRB < freePrbBlock->numFreePrb)
1564          {
1565             *startPrb = freePrbBlock->startPrb;
1566             maxFreePRB = freePrbBlock->numFreePrb;
1567          }
1568
1569       }
1570       freePrbNode = freePrbNode->next;
1571    }  
1572    return(maxFreePRB);
1573 }
1574 /**********************************************************************
1575   End of file
1576  **********************************************************************/