1 /*******************************************************************************
2 ################################################################################
3 # Copyright (c) [2017-2019] [Radisys] #
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 #
9 # http://www.apache.org/licenses/LICENSE-2.0 #
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 *******************************************************************************/
19 /************************************************************************
25 Desc: C source code for scheduler fucntions
29 **********************************************************************/
32 @brief This file implements the schedulers main access to MAC layer code.
34 #include "common_def.h"
35 #include "du_app_mac_inf.h"
40 #include "rg_sch_inf.h"
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"
50 #include "sch_utils.h"
52 #include "sch_slice_based.h"
53 SchCb schCb[SCH_MAX_INST];
56 * @brief Scheduler All Apis initialized.
60 * Function : schAllApisInit
62 * This function initializes all Scheduler APIs/functionality for each kind
65 * @param[in] Inst inst, the Scheduler instance
68 void schAllApisInit(Inst inst)
70 schFcfsAllApisInit(&schCb[inst].allApis[SCH_FCFS]);
71 schSliceBasedAllApisInit(&schCb[inst].allApis[SCH_SLICE_BASED]);
75 * @brief Scheduler instance Configuration Handler.
79 * Function : SchInstCfg
81 * This function in called by SchProcGenCfgReq(). It handles the
82 * general configurations of the scheduler instance. Returns
83 * reason for success/failure of this function.
85 * @param[in] RgCfg *cfg, the Configuaration information
87 * -# LCM_REASON_NOT_APPL
88 * -# LCM_REASON_INVALID_MSGTYPE
89 * -# LCM_REASON_MEM_NOAVAIL
91 uint8_t SchInstCfg(RgCfg *cfg, Inst dInst)
93 uint16_t ret = LCM_REASON_NOT_APPL;
94 Inst inst = (dInst - SCH_INST_START);
96 DU_LOG("\nDEBUG --> SCH : Entered SchInstCfg()");
97 /* Check if Instance Configuration is done already */
98 if (schCb[inst].schInit.cfgDone == TRUE)
100 return LCM_REASON_INVALID_MSGTYPE;
102 /* Update the Pst structure for LM interface */
103 memcpy(&schCb[inst].schInit.lmPst, &cfg->s.schInstCfg.genCfg.lmPst, sizeof(Pst));
105 schCb[inst].schInit.inst = inst;
106 schCb[inst].schInit.lmPst.srcProcId = schCb[inst].schInit.procId;
107 schCb[inst].schInit.lmPst.srcEnt = schCb[inst].schInit.ent;
108 schCb[inst].schInit.lmPst.srcInst = schCb[inst].schInit.inst +
110 schCb[inst].schInit.lmPst.event = EVTNONE;
112 schCb[inst].schInit.region = cfg->s.schInstCfg.genCfg.mem.region;
113 schCb[inst].schInit.pool = cfg->s.schInstCfg.genCfg.mem.pool;
115 schCb[inst].genCfg.forceCntrlSrbBoOnPCel = cfg->s.schInstCfg.genCfg.forceCntrlSrbBoOnPCel;
116 schCb[inst].genCfg.isSCellActDeactAlgoEnable = cfg->s.schInstCfg.genCfg.isSCellActDeactAlgoEnable;
118 schCb[inst].genCfg.startCellId = cfg->s.schInstCfg.genCfg.startCellId;
120 schCb[inst].schTimersInfo.tmrRes = cfg->s.schInstCfg.genCfg.tmrRes;
121 /* Initialzie the timer queue */
122 memset(&schCb[inst].schTimersInfo.tmrTq, 0, sizeof(CmTqType) * SCH_TQ_SIZE);
123 /* Initialize the timer control point */
124 memset(&schCb[inst].schTimersInfo.tmrTqCp, 0, sizeof(CmTqCp));
125 schCb[inst].schTimersInfo.tmrTqCp.tmrLen = SCH_TQ_SIZE;
127 /* SS_MT_TMR needs to be enabled as schActvTmr needs instance information */
128 /* Timer Registration request to system services */
129 if (ODU_REG_TMR_MT(schCb[inst].schInit.ent, dInst, (int)schCb[inst].schTimersInfo.tmrRes, schActvTmr) != ROK)
131 DU_LOG("\nERROR --> SCH : SchInstCfg(): Failed to register timer.");
132 return (LCM_REASON_MEM_NOAVAIL);
135 /* Initialize statistics related configurations */
136 memset(&schCb[inst].statistics, 0, sizeof(SchStatistics));
137 cmLListInit(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList);
138 cmLListInit(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList);
140 /* Set Config done in TskInit */
141 schCb[inst].schInit.cfgDone = TRUE;
142 DU_LOG("\nINFO --> SCH : Scheduler gen config done");
144 schAllApisInit(inst);
149 * @brief Layer Manager Configuration request handler.
153 * Function : SchProcGenCfgReq
155 * This function handles the configuration
156 * request received at scheduler instance from the Layer Manager.
157 * -# Based on the cfg->hdr.elmId.elmnt value it invokes one of the
158 * functions rgHdlGenCfg() or rgHdlSapCfg().
159 * -# Invokes RgMiLrgSchCfgCfm() to send back the confirmation to the LM.
161 * @param[in] Pst *pst, the post structure
162 * @param[in] RgMngmt *cfg, the configuration parameter's structure
166 uint8_t SchProcGenCfgReq(Pst *pst, RgMngmt *cfg)
168 uint8_t ret = LCM_PRIM_OK;
169 uint16_t reason = LCM_REASON_NOT_APPL;
173 if(pst->dstInst < SCH_INST_START)
175 DU_LOG("\nERROR --> SCH : Invalid inst ID");
176 DU_LOG("\nERROR --> SCH : SchProcGenCfgReq(): "
177 "pst->dstInst=%d SCH_INST_START=%d", pst->dstInst,SCH_INST_START);
180 DU_LOG("\nINFO --> SCH : Received scheduler gen config");
181 /* Fill the post structure for sending the confirmation */
182 memset(&cfmPst, 0 , sizeof(Pst));
183 SchFillCfmPst(pst, &cfmPst, cfg);
185 memset(&cfm, 0, sizeof(RgMngmt));
192 cfm.hdr.elmId.elmnt = cfg->hdr.elmId.elmnt;
193 switch(cfg->hdr.elmId.elmnt)
196 reason = SchInstCfg(&cfg->t.cfg,pst->dstInst );
200 reason = LCM_REASON_INVALID_ELMNT;
201 DU_LOG("\nERROR --> SCH : Invalid Elmnt=%d", cfg->hdr.elmId.elmnt);
205 if (reason != LCM_REASON_NOT_APPL)
210 cfm.cfm.status = ret;
211 cfm.cfm.reason = reason;
213 SchSendCfgCfm(&cfmPst, &cfm);
214 /* SCH_FREE(pst->region, pst->pool, (Data *)cfg, sizeof(RgMngmt)); */
217 }/*-- SchProcGenCfgReq --*/
221 *@brief Returns TDD periodicity in micro seconds
225 * Function : schGetPeriodicityInMsec
227 * This API retunrs TDD periodicity in micro seconds
229 * @param[in] DlUlTxPeriodicity
230 * @return periodicityInMsec
233 uint16_t schGetPeriodicityInMsec(DlUlTxPeriodicity tddPeriod)
235 uint16_t periodicityInMsec = 0;
238 case TX_PRDCTY_MS_0P5:
240 periodicityInMsec = 500;
243 case TX_PRDCTY_MS_0P625:
245 periodicityInMsec = 625;
250 periodicityInMsec = 1000;
253 case TX_PRDCTY_MS_1P25:
255 periodicityInMsec = 1250;
260 periodicityInMsec = 2000;
263 case TX_PRDCTY_MS_2P5:
265 periodicityInMsec = 2500;
270 periodicityInMsec = 5000;
273 case TX_PRDCTY_MS_10:
275 periodicityInMsec = 10000;
280 DU_LOG("\nERROR --> SCH : Invalid DlUlTxPeriodicity:%d", tddPeriod);
284 return periodicityInMsec;
288 *@brief Fills the slotCfg from CellCfg
292 * Function : schFillSlotConfig
294 * This API Fills the slotCfg from CellCfg
296 * @param[in] SchCellCb *cell, TDDCfg tddCfg
299 void schFillSlotConfig(SchCellCb *cell, TDDCfg tddCfg)
301 uint8_t slotIdx = 0, symbolIdx = 0;
303 for(slotIdx =0 ;slotIdx < MAX_TDD_PERIODICITY_SLOTS; slotIdx++)
305 for(symbolIdx = 0; symbolIdx < MAX_SYMB_PER_SLOT; symbolIdx++)
307 /*Fill Full-DL Slots as well as DL symbols ini 1st Flexi Slo*/
308 if(slotIdx < tddCfg.nrOfDlSlots || \
309 (slotIdx == tddCfg.nrOfDlSlots && symbolIdx < tddCfg.nrOfDlSymbols))
311 cell->slotCfg[slotIdx][symbolIdx] = DL_SYMBOL;
314 /*Fill Full-FLEXI SLOT and as well as Flexi Symbols in 1 slot preceding FULL-UL slot*/
315 else if(slotIdx < (MAX_TDD_PERIODICITY_SLOTS - tddCfg.nrOfUlSlots -1) || \
316 (slotIdx == (MAX_TDD_PERIODICITY_SLOTS - tddCfg.nrOfUlSlots -1) && \
317 symbolIdx < (MAX_SYMB_PER_SLOT - tddCfg.nrOfUlSymbols)))
319 cell->slotCfg[slotIdx][symbolIdx] = FLEXI_SYMBOL;
321 /*Fill Partial UL symbols and Full-UL slot*/
324 cell->slotCfg[slotIdx][symbolIdx] = UL_SYMBOL;
331 * @brief init TDD slot config
335 * Function : schInitTddSlotCfg
337 * This API is invoked after receiving schCellCfg
339 * @param[in] schCellCb *cell
340 * @param[in] SchCellCfg *schCellCfg
343 void schInitTddSlotCfg(SchCellCb *cell, SchCellCfg *schCellCfg)
345 uint16_t periodicityInMicroSec = 0;
346 int8_t slotIdx, symbIdx;
348 periodicityInMicroSec = schGetPeriodicityInMsec(schCellCfg->tddCfg.tddPeriod);
349 cell->numSlotsInPeriodicity = (periodicityInMicroSec * pow(2, cell->numerology))/1000;
350 cell->slotFrmtBitMap = 0;
351 schFillSlotConfig(cell, schCellCfg->tddCfg);
352 for(slotIdx = cell->numSlotsInPeriodicity-1; slotIdx >= 0; slotIdx--)
355 /* If the first and last symbol are the same, the entire slot is the same type */
356 if((cell->slotCfg[slotIdx][symbIdx] == cell->slotCfg[slotIdx][MAX_SYMB_PER_SLOT-1]) &&
357 cell->slotCfg[slotIdx][symbIdx] != FLEXI_SYMBOL)
359 switch(cell->slotCfg[slotIdx][symbIdx])
363 /*BitMap to be set to 00 */
364 cell->slotFrmtBitMap = (cell->slotFrmtBitMap<<2);
369 /*BitMap to be set to 01 */
370 cell->slotFrmtBitMap = ((cell->slotFrmtBitMap<<2) | (UL_SLOT));
374 DU_LOG("\nERROR --> SCH : Invalid slot Config in schInitTddSlotCfg");
378 /* slot config is flexible. First set slotBitMap to 10 */
379 cell->slotFrmtBitMap = ((cell->slotFrmtBitMap<<2) | (FLEXI_SLOT));
385 * @brief Fill SSB start symbol
389 * Function : fillSsbStartSymb
391 * This API stores SSB start index per beam
393 * @param[in] SchCellCb *cellCb
398 void fillSsbStartSymb(SchCellCb *cellCb)
400 uint8_t cnt, scs, symbIdx, ssbStartSymbArr[SCH_MAX_SSB_BEAM];
402 scs = cellCb->cellCfg.ssbScs;
404 memset(ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
406 /* Determine value of "n" based on Section 4.1 of 3GPP TS 38.213 */
411 if(cellCb->cellCfg.ssbFrequency <= 300000)
412 cnt = 2;/* n = 0, 1 */
414 cnt = 4; /* n = 0, 1, 2, 3 */
415 for(uint8_t idx=0; idx<cnt; idx++)
417 /* start symbol determined using {2, 8} + 14n */
418 ssbStartSymbArr[symbIdx++] = 2 + MAX_SYMB_PER_SLOT*idx;
419 ssbStartSymbArr[symbIdx++] = 8 + MAX_SYMB_PER_SLOT*idx;
425 if(cellCb->cellCfg.ssbFrequency <= 300000)
428 cnt = 2; /* n = 0, 1 */
429 for(uint8_t idx=0; idx<cnt; idx++)
431 /* start symbol determined using {4, 8, 16, 20} + 28n */
432 ssbStartSymbArr[symbIdx++] = 4 + MAX_SYMB_PER_SLOT*idx;
433 ssbStartSymbArr[symbIdx++] = 8 + MAX_SYMB_PER_SLOT*idx;
434 ssbStartSymbArr[symbIdx++] = 16 + MAX_SYMB_PER_SLOT*idx;
435 ssbStartSymbArr[symbIdx++] = 20 + MAX_SYMB_PER_SLOT*idx;
440 DU_LOG("\nERROR --> SCH : SCS %d is currently not supported", scs);
442 memset(cellCb->ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
443 memcpy(cellCb->ssbStartSymbArr, ssbStartSymbArr, SCH_MAX_SSB_BEAM);
448 * @brief init cellCb based on cellCfg
452 * Function : schInitCellCb
454 * This API is invoked after receiving schCellCfg
456 * @param[in] schCellCb *cell
457 * @param[in] SchCellCfg *schCellCfg
462 uint8_t schInitCellCb(Inst inst, SchCellCfg *schCellCfg)
464 uint16_t scsInKhz = 0;
465 SchCellCb *cell= NULLP;
466 SCH_ALLOC(cell, sizeof(SchCellCb));
469 DU_LOG("\nERROR --> SCH : Memory allocation failed in schInitCellCb");
473 cell->cellId = schCellCfg->cellId;
474 cell->instIdx = inst;
475 scsInKhz = convertScsEnumValToScsVal(schCellCfg->ssbScs);
477 /*Ref : 3GPP 38.211 Table 4.2-1: SCS = (2 ^ numerology * 15kHz)*/
478 cell->numerology = log2(scsInKhz/BASE_SCS);
479 switch(cell->numerology)
481 case SCH_NUMEROLOGY_0:
483 cell->numSlots = SCH_MU0_NUM_SLOTS;
486 case SCH_NUMEROLOGY_1:
488 cell->numSlots = SCH_MU1_NUM_SLOTS;
491 case SCH_NUMEROLOGY_2:
493 cell->numSlots = SCH_MU2_NUM_SLOTS;
496 case SCH_NUMEROLOGY_3:
498 cell->numSlots = SCH_MU3_NUM_SLOTS;
501 case SCH_NUMEROLOGY_4:
503 cell->numSlots = SCH_MU4_NUM_SLOTS;
507 DU_LOG("\nERROR --> SCH : Numerology %d not supported", cell->numerology);
510 schInitTddSlotCfg(cell, schCellCfg);
513 SCH_ALLOC(cell->schDlSlotInfo, cell->numSlots * sizeof(SchDlSlotInfo*));
514 if(!cell->schDlSlotInfo)
516 DU_LOG("\nERROR --> SCH : Memory allocation failed in schInitCellCb for schDlSlotInfo");
520 SCH_ALLOC(cell->schUlSlotInfo, cell->numSlots * sizeof(SchUlSlotInfo*));
521 if(!cell->schUlSlotInfo)
523 DU_LOG("\nERROR --> SCH : Memory allocation failed in schInitCellCb for schUlSlotInfo");
527 for(uint8_t idx=0; idx<cell->numSlots; idx++)
529 SchDlSlotInfo *schDlSlotInfo;
530 SchUlSlotInfo *schUlSlotInfo;
533 SCH_ALLOC(schDlSlotInfo, sizeof(SchDlSlotInfo));
536 DU_LOG("\nERROR --> SCH : Memory allocation failed in schInitCellCb");
541 SCH_ALLOC(schUlSlotInfo, sizeof(SchUlSlotInfo));
544 DU_LOG("\nERROR --> SCH : Memory allocation failed in schInitCellCb");
548 schInitDlSlot(schDlSlotInfo);
549 schInitUlSlot(schUlSlotInfo);
551 cell->schDlSlotInfo[idx] = schDlSlotInfo;
552 cell->schUlSlotInfo[idx] = schUlSlotInfo;
555 cell->firstSsbTransmitted = false;
556 cell->firstSib1Transmitted = false;
557 fillSsbStartSymb(cell);
560 memset(cell->drxCb, 0, MAX_DRX_SIZE*sizeof(SchDrxCb));
562 schCb[inst].cells[inst] = cell;
564 DU_LOG("\nINFO --> SCH : Cell init completed for cellId:%d", cell->cellId);
570 * @brief Fill SIB1 configuration
574 * Function : fillSchSib1Cfg
576 * Fill SIB1 configuration
578 * @param[in] uint8_t bandwidth : total available bandwidth
579 * uint8_t numSlots : total slots per SFN
580 * SchSib1Cfg *sib1SchCfg : cfg to be filled
581 * uint16_t pci : physical cell Id
582 * uint8_t offsetPointA : offset
585 uint8_t fillSchSib1Cfg(uint8_t mu, uint8_t bandwidth, uint8_t numSlots,SchPdcchConfigSib1 *pdcchCfgSib1,\
586 SchSib1Cfg *sib1SchCfg, uint16_t pci, uint8_t offsetPointA, uint16_t sib1PduLen)
588 uint8_t coreset0Idx = 0;
589 uint8_t searchSpace0Idx = 0;
590 //uint8_t ssbMuxPattern = 0;
592 uint8_t numSymbols = 0;
595 //uint8_t numSearchSpacePerSlot = 0;
597 uint8_t firstSymbol = 0; /* need to calculate using formula mentioned in 38.213 */
598 uint8_t slotIndex = 0;
599 uint8_t freqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
606 pdcch = &(sib1SchCfg->sib1PdcchCfg);
607 bwp = &(sib1SchCfg->bwp);
609 coreset0Idx = pdcchCfgSib1->coresetZeroIndex;
610 searchSpace0Idx = pdcchCfgSib1->searchSpaceZeroIndex;
612 /* derive the sib1 coreset0 params from table 13-1 spec 38.213 */
613 //ssbMuxPattern = coresetIdxTable[coreset0Idx][0];
614 numRbs = coresetIdxTable[coreset0Idx][1];
615 numSymbols = coresetIdxTable[coreset0Idx][2];
616 offset = coresetIdxTable[coreset0Idx][3];
618 /* derive the search space params from table 13-11 spec 38.213 */
619 oValue = searchSpaceIdxTable[searchSpace0Idx][0];
620 //numSearchSpacePerSlot = searchSpaceIdxTable[searchSpace0Idx][1];
621 mValue = searchSpaceIdxTable[searchSpace0Idx][2];
622 firstSymbol = searchSpaceIdxTable[searchSpace0Idx][3];
624 /* calculate the n0, need to add the formulae, as of now the value is 0
625 * Need to add the even and odd values of i during configuration
626 * [(O . 2^u + i . M ) ] mod numSlotsPerSubframe
627 * assuming u = 0, i = 0, numSlotsPerSubframe = 10
628 * Also, from this configuration, coreset0 is only on even subframe */
629 slotIndex = (int)((oValue*pow(2, mu)) + floor(ssbIdx*mValue))%numSlots;
630 sib1SchCfg->n0 = slotIndex;
635 case BANDWIDTH_20MHZ:
637 bwp->freqAlloc.numPrb = TOTAL_PRB_20MHZ_MU0;
640 case BANDWIDTH_100MHZ:
642 bwp->freqAlloc.numPrb = TOTAL_PRB_100MHZ_MU1;
646 DU_LOG("\nERROR --> SCH : Bandwidth %d not supported", bandwidth);
649 bwp->freqAlloc.startPrb = 0;
650 bwp->subcarrierSpacing = 0; /* 15Khz */
651 bwp->cyclicPrefix = 0; /* normal */
653 /* fill the PDCCH PDU */
654 pdcch->coresetCfg.coreSetSize = numRbs;
655 pdcch->coresetCfg.startSymbolIndex = firstSymbol;
656 pdcch->coresetCfg.durationSymbols = numSymbols;
658 /* Fill Bitmap for PRBs in coreset */
659 fillCoresetFeqDomAllocMap(((offsetPointA-offset)/6), (numRbs/6), freqDomainResource);
660 memcpy(pdcch->coresetCfg.freqDomainResource, freqDomainResource, FREQ_DOM_RSRC_SIZE);
662 pdcch->coresetCfg.cceRegMappingType = 1; /* coreset0 is always interleaved */
663 pdcch->coresetCfg.regBundleSize = 6; /* spec-38.211 sec 7.3.2.2 */
664 pdcch->coresetCfg.interleaverSize = 2; /* spec-38.211 sec 7.3.2.2 */
665 pdcch->coresetCfg.coreSetType = 0;
666 pdcch->coresetCfg.shiftIndex = pci;
667 pdcch->coresetCfg.precoderGranularity = 0; /* sameAsRegBundle */
669 pdcch->dci[0].rnti = SI_RNTI;
670 pdcch->dci[0].scramblingId = pci;
671 pdcch->dci[0].scramblingRnti = 0;
672 pdcch->dci[0].cceIndex = 0;
673 pdcch->dci[0].aggregLevel = 4;
674 pdcch->dci[0].beamPdcchInfo.numPrgs = 1;
675 pdcch->dci[0].beamPdcchInfo.prgSize = 1;
676 pdcch->dci[0].beamPdcchInfo.digBfInterfaces = 0;
677 pdcch->dci[0].beamPdcchInfo.prg[0].pmIdx = 0;
678 pdcch->dci[0].beamPdcchInfo.prg[0].beamIdx[0] = 0;
679 pdcch->dci[0].txPdcchPower.beta_pdcch_1_0= 0;
680 pdcch->dci[0].txPdcchPower.powerControlOffsetSS = 0;
681 /* Storing pdschCfg pointer here. Required to access pdsch config while
682 fillig up pdcch pdu */
683 pdsch = &pdcch->dci[0].pdschCfg;
685 /* fill the PDSCH PDU */
687 pdsch->pduBitmap = 0; /* PTRS and CBG params are excluded */
688 pdsch->rnti = 0xFFFF; /* SI-RNTI */
690 pdsch->numCodewords = 1;
691 for(cwCount = 0; cwCount < pdsch->numCodewords; cwCount++)
693 pdsch->codeword[cwCount].targetCodeRate = 308;
694 pdsch->codeword[cwCount].qamModOrder = 2;
695 pdsch->codeword[cwCount].mcsIndex = DEFAULT_MCS;
696 pdsch->codeword[cwCount].mcsTable = 0; /* notqam256 */
697 pdsch->codeword[cwCount].rvIndex = 0;
698 tbSize = schCalcTbSize(sib1PduLen + TX_PAYLOAD_HDR_LEN);
699 pdsch->codeword[cwCount].tbSize = tbSize;
701 pdsch->dataScramblingId = pci;
702 pdsch->numLayers = 1;
703 pdsch->transmissionScheme = 0;
705 pdsch->dmrs.dlDmrsSymbPos = DL_DMRS_SYMBOL_POS;
706 pdsch->dmrs.dmrsConfigType = 0; /* type-1 */
707 pdsch->dmrs.dlDmrsScramblingId = pci;
708 pdsch->dmrs.scid = 0;
709 pdsch->dmrs.numDmrsCdmGrpsNoData = 1;
710 pdsch->dmrs.dmrsPorts = 0x0001;
711 pdsch->dmrs.mappingType = DMRS_MAP_TYPE_A; /* Type-A */
712 pdsch->dmrs.nrOfDmrsSymbols = NUM_DMRS_SYMBOLS;
713 pdsch->dmrs.dmrsAddPos = DMRS_ADDITIONAL_POS;
715 pdsch->pdschFreqAlloc.resourceAllocType = 1; /* RAT type-1 RIV format */
716 /* the RB numbering starts from coreset0, and PDSCH is always above SSB */
717 pdsch->pdschFreqAlloc.startPrb = offsetPointA + SCH_SSB_NUM_PRB;
718 pdsch->pdschFreqAlloc.numPrb = schCalcNumPrb(tbSize, DEFAULT_MCS, NUM_PDSCH_SYMBOL);
719 pdsch->pdschFreqAlloc.vrbPrbMapping = 0; /* non-interleaved */
720 pdsch->pdschTimeAlloc.rowIndex = 1;
721 /* This is Intel's requirement. PDSCH should start after PDSCH DRMS symbol */
722 pdsch->pdschTimeAlloc.startSymb = 3; /* spec-38.214, Table 5.1.2.1-1 */
723 pdsch->pdschTimeAlloc.numSymb = NUM_PDSCH_SYMBOL;
724 pdsch->beamPdschInfo.numPrgs = 1;
725 pdsch->beamPdschInfo.prgSize = 1;
726 pdsch->beamPdschInfo.digBfInterfaces = 0;
727 pdsch->beamPdschInfo.prg[0].pmIdx = 0;
728 pdsch->beamPdschInfo.prg[0].beamIdx[0] = 0;
729 pdsch->txPdschPower.powerControlOffset = 0;
730 pdsch->txPdschPower.powerControlOffsetSS = 0;
736 * @brief cell config from MAC to SCH.
740 * Function : macSchCellCfgReq
742 * This API is invoked by MAC to send cell config to SCH
744 * @param[in] Pst *pst
745 * @param[in] SchCellCfg *schCellCfg
750 uint8_t SchProcCellCfgReq(Pst *pst, SchCellCfg *schCellCfg)
754 SchCellCfgCfm schCellCfgCfm;
756 Inst inst = pst->dstInst - SCH_INST_START;
757 uint8_t coreset0Idx = 0;
760 uint8_t freqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
761 SchPdschConfig pdschCfg;
763 schInitCellCb(inst, schCellCfg);
764 cellCb = schCb[inst].cells[inst]; //cells is of MAX_CELLS, why inst
765 cellCb->macInst = pst->srcInst;
767 /* derive the SIB1 config parameters */
768 ret = fillSchSib1Cfg(cellCb->numerology, schCellCfg->dlBandwidth, cellCb->numSlots,
769 &(schCellCfg->pdcchCfgSib1), &(cellCb->sib1SchCfg), schCellCfg->phyCellId,
770 schCellCfg->dlCfgCommon.schFreqInfoDlSib.offsetToPointA, schCellCfg->sib1PduLen);
774 DU_LOG("\nERROR --> SCH : Failed to fill sib1 configuration");
777 memcpy(&cellCb->cellCfg, schCellCfg, sizeof(SchCellCfg));
778 schProcPagingCfg(cellCb);
780 /* Fill coreset frequencyDomainResource bitmap */
781 coreset0Idx = cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdcchCommon.commonSearchSpace.coresetId;
782 numRbs = coresetIdxTable[coreset0Idx][1];
783 offset = coresetIdxTable[coreset0Idx][3];
784 fillCoresetFeqDomAllocMap(((cellCb->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA - offset)/6), \
785 (numRbs/6), freqDomainResource);
786 memcpy(cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdcchCommon.commonSearchSpace.freqDomainRsrc,\
787 freqDomainResource,FREQ_DOM_RSRC_SIZE);
788 /* Fill K0 - K1 table for common cfg*/
789 BuildK0K1Table(cellCb, &cellCb->k0K1InfoTbl, true, cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdschCommon,
790 pdschCfg, DEFAULT_UL_ACK_LIST_COUNT, defaultUlAckTbl);
792 BuildK2InfoTable(cellCb, cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList,\
793 cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.numTimeDomRsrcAlloc, &cellCb->msg3K2InfoTbl, \
796 /*As per Spec 38.211, Sec 6.3.3.2; RootSeq Len(Lra) where Lra=839 or Lra=139,
797 *depending on the PRACH preamble format as given by Tables 6.3.3.1-1 and 6.3.3.1-2.*/
798 if(prachCfgIdxTable[cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.prachCfgIdx][0] <= 3)
800 cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.rootSeqLen = ROOT_SEQ_LEN_1;
804 cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.rootSeqLen = ROOT_SEQ_LEN_2;
806 /* Initializing global variables */
807 cellCb->actvUeBitMap = 0;
808 cellCb->boIndBitMap = 0;
810 cellCb->schHqCfg.maxDlDataHqTx = SCH_MAX_NUM_DL_HQ_TX;
811 cellCb->schHqCfg.maxMsg4HqTx = SCH_MAX_NUM_MSG4_TX;
812 cellCb->schHqCfg.maxUlDataHqTx = SCH_MAX_NUM_UL_HQ_TX;
813 cellCb->maxMsg3Tx = SCH_MAX_NUM_MSG3_TX;
815 cellCb->schAlgoType = SCH_FCFS;
816 cellCb->api = &schCb[inst].allApis[cellCb->schAlgoType]; /* For FCFS */
817 cellCb->api->SchCellCfgReq(cellCb);
819 /* Fill and send Cell config confirm */
820 memset(&rspPst, 0, sizeof(Pst));
821 FILL_PST_SCH_TO_MAC(rspPst, pst->dstInst);
822 rspPst.event = EVENT_SCH_CELL_CFG_CFM;
824 schCellCfgCfm.cellId = schCellCfg->cellId;
825 schCellCfgCfm.rsp = RSP_OK;
827 ret = MacMessageRouter(&rspPst, (void *)&schCellCfgCfm);
832 /*******************************************************************
834 * @brief Fill and send Cell delete response to MAC
838 * Function : SchSendCellDeleteRspToMac
840 * Functionality: Fill and send Cell delete response to MAC
842 * @params[in] SchCellDelete *ueDelete, Inst inst, SchMacRsp result
843 * @return ROK - success
846 * ****************************************************************/
847 uint8_t SchSendCellDeleteRspToMac(SchCellDeleteReq *ueDelete, Inst inst, SchMacRsp result)
852 SchCellDeleteRsp delRsp;
854 DU_LOG("\nINFO --> SCH : Filling Cell Delete response");
855 memset(&delRsp, 0, sizeof(SchCellDeleteRsp));
856 delRsp.cellId = ueDelete->cellId;
859 /* Filling response post */
860 memset(&rspPst, 0, sizeof(Pst));
861 FILL_PST_SCH_TO_MAC(rspPst, inst);
862 rspPst.event = EVENT_CELL_DELETE_RSP_TO_MAC;
863 ret = MacMessageRouter(&rspPst, (void *)&delRsp);
866 DU_LOG("\nERROR --> SCH : SchSendCellDeleteRspToMac(): failed to send the Cell Delete response");
872 /*******************************************************************
874 * @brief Function for cellCb Deletion
878 * Function : deleteSchCellCb
880 * Functionality: Function for cellCb Deletion
882 * @params[in] SchCellDelete *cellDelete
883 * @return ROK - success
886 * ****************************************************************/
887 void deleteSchCellCb(SchCellCb *cellCb)
889 uint8_t sliceIdx=0, slotIdx=0, plmnIdx = 0;
891 CmLListCp *list=NULL;
892 CmLList *node=NULL, *next=NULL;
893 SchPageInfo *tempNode = NULLP;
895 if(cellCb->schDlSlotInfo)
897 for(slotIdx=0; slotIdx<cellCb->numSlots; slotIdx++)
899 list = &cellCb->schDlSlotInfo[slotIdx]->prbAlloc.freePrbBlockList;
904 SCH_FREE(node->node, sizeof(FreePrbBlock));
905 deleteNodeFromLList(list, node);
908 for(ueIdx = 0; ueIdx< MAX_NUM_UE; ueIdx++)
910 SCH_FREE(cellCb->schDlSlotInfo[slotIdx]->rarAlloc[ueIdx], sizeof(RarAlloc));
911 SCH_FREE(cellCb->schDlSlotInfo[slotIdx]->dlMsgAlloc[ueIdx], sizeof(DlMsgSchInfo));
913 SCH_FREE(cellCb->schDlSlotInfo[slotIdx]->ulGrant, sizeof(DciInfo));
914 SCH_FREE(cellCb->schDlSlotInfo[slotIdx], sizeof(SchDlSlotInfo));
916 SCH_FREE(cellCb->schDlSlotInfo, cellCb->numSlots *sizeof(SchDlSlotInfo*));
919 if(cellCb->schUlSlotInfo)
921 for(slotIdx=0; slotIdx<cellCb->numSlots; slotIdx++)
923 list = &cellCb->schUlSlotInfo[slotIdx]->prbAlloc.freePrbBlockList;
928 SCH_FREE(node->node, sizeof(FreePrbBlock));
929 deleteNodeFromLList(list, node);
932 for(ueIdx = 0; ueIdx< MAX_NUM_UE; ueIdx++)
934 SCH_FREE(cellCb->schUlSlotInfo[slotIdx]->schPuschInfo[ueIdx], sizeof(SchPuschInfo));
936 SCH_FREE(cellCb->schUlSlotInfo[slotIdx], sizeof(SchUlSlotInfo));
938 SCH_FREE(cellCb->schUlSlotInfo, cellCb->numSlots * sizeof(SchUlSlotInfo*));
941 for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
943 if(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai)
945 for(sliceIdx=0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices; sliceIdx++)
947 SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai[sliceIdx], sizeof(Snssai));
949 SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices*sizeof(Snssai*));
953 for(uint16_t idx =0; idx<MAX_SFN; idx++)
955 list = &cellCb->pageCb.pageIndInfoRecord[idx];
962 tempNode = (SchPageInfo*)(node->node);
963 SCH_FREE(tempNode->pagePdu, tempNode->msgLen);
964 SCH_FREE(node->node, sizeof(SchPageInfo));
966 deleteNodeFromLList(list, node);
971 cellCb->api->SchCellDeleteReq(cellCb);
973 memset(cellCb, 0, sizeof(SchCellCb));
976 /*******************************************************************
978 * @brief Function for cell Delete request from MAC to SCH
982 * Function : SchProcCellDeleteReq
984 * Functionality: Function for cell Delete request from MAC to SCH
986 * @params[in] Pst *pst, SchCellDelete *cellDelete
987 * @return ROK - success
990 * ****************************************************************/
991 uint8_t SchProcCellDeleteReq(Pst *pst, SchCellDeleteReq *cellDelete)
993 uint8_t cellIdx=0, ret = RFAILED;
994 Inst inst = pst->dstInst - SCH_INST_START;
995 SchMacRsp result= RSP_OK;
999 DU_LOG("\nERROR --> SCH : SchProcCellDeleteReq(): Ue Delete request failed");
1003 GET_CELL_IDX(cellDelete->cellId, cellIdx);
1004 if(schCb[inst].cells[cellIdx] == NULLP)
1006 DU_LOG("\nERROR --> SCH : SchProcCellDeleteReq(): cell Id[%d] is not available", cellDelete->cellId);
1011 if(schCb[inst].cells[cellIdx]->cellId == cellDelete->cellId)
1013 deleteSchCellCb(schCb[inst].cells[cellIdx]);
1016 SCH_FREE(schCb[inst].cells[cellIdx], sizeof(SchCellCb));
1017 DU_LOG("\nINFO --> SCH : Sending Cell Delete response to MAC");
1021 DU_LOG("\nERROR --> SCH : SchProcCellDeleteReq(): cell Id[%d] is not available",cellDelete->cellId);
1026 if(SchSendCellDeleteRspToMac(cellDelete, inst, result)!=ROK)
1028 DU_LOG("\nERROR --> SCH : SchProcCellDeleteReq(): failed to send Cell Delete response");
1035 /*******************************************************************
1037 * @brief Processes DL RLC BO info from MAC
1041 * Function : SchProcDlRlcBoInfo
1044 * Processes DL RLC BO info from MAC
1047 * @return ROK - success
1050 * ****************************************************************/
1051 uint8_t SchProcDlRlcBoInfo(Pst *pst, DlRlcBoInfo *dlBoInfo)
1055 bool isLcIdValid = false;
1056 SchUeCb *ueCb = NULLP;
1057 SchCellCb *cell = NULLP;
1058 Inst inst = pst->dstInst-SCH_INST_START;
1060 DU_LOG("\nDEBUG --> SCH : Received RLC BO Status indication LCId [%d] BO [%d]", dlBoInfo->lcId, dlBoInfo->dataVolume);
1061 cell = schCb[inst].cells[inst];
1065 DU_LOG("\nERROR --> SCH : SchProcDlRlcBoInfo(): Cell does not exists");
1069 GET_UE_ID(dlBoInfo->crnti, ueId);
1070 ueCb = &cell->ueCb[ueId-1];
1071 if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1073 DU_LOG("INFO --> SCH : DL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1077 lcId = dlBoInfo->lcId;
1078 CHECK_LCID(lcId, isLcIdValid);
1079 if(isLcIdValid == FALSE)
1081 DU_LOG("ERROR --> SCH: LCID:%d is not valid", lcId);
1085 /*Expected when theres a case of Retransmission Failure or Resetablishment
1086 *By Zero BO, the RLC is informing that previous data can be cleared out
1087 *Thus clearing out the LC from the Lc priority list*/
1088 if(dlBoInfo->dataVolume == 0)
1090 /* TODO : Check the LC is Dedicated or default and accordingly LCList
1095 if(lcId == SRB0_LCID)
1097 cell->raCb[ueId -1].msg4recvd = true;
1098 cell->raCb[ueId -1].dlMsgPduLen = dlBoInfo->dataVolume;
1102 /* TODO : These part of changes will be corrected during DL scheduling as
1103 * per K0 - K1 -K2 */
1104 SET_ONE_BIT(ueId, cell->boIndBitMap);
1105 if(ueCb->dlInfo.dlLcCtxt[lcId].lcId == lcId)
1107 ueCb->dlInfo.dlLcCtxt[lcId].bo = dlBoInfo->dataVolume;
1111 DU_LOG("ERROR --> SCH: LCID:%d is not configured in SCH Cb",lcId);
1115 /* Adding UE Id to list of pending UEs to be scheduled */
1116 cell->api->SchDlRlcBoInfo(cell, ueId);
1120 /*******************************************************************
1122 * @brief Processes BSR indiation from MAC
1126 * Function : SchProcBsr
1129 * Processes DL BSR from MAC
1131 * @params[in] Pst pst
1132 * UlBufferStatusRptInd bsrInd
1133 * @return ROK - success
1136 * ****************************************************************/
1137 uint8_t SchProcBsr(Pst *pst, UlBufferStatusRptInd *bsrInd)
1139 Inst schInst = pst->dstInst-SCH_INST_START;
1140 SchCellCb *cellCb = NULLP;
1141 SchUeCb *ueCb = NULLP;
1144 DU_LOG("\nDEBUG --> SCH : Received BSR");
1147 DU_LOG("\nERROR --> SCH : BSR Ind is empty");
1150 cellCb = schCb[schInst].cells[schInst];
1153 DU_LOG("\nERROR --> SCH : CellCb is empty");
1156 ueCb = schGetUeCb(cellCb, bsrInd->crnti);
1160 DU_LOG("\nERROR --> SCH : UeCB is empty");
1164 if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1166 DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1170 ueCb->bsrRcvd = true;
1171 /* store dataVolume per lcg in uecb */
1172 for(lcgIdx = 0; lcgIdx < bsrInd->numLcg; lcgIdx++)
1174 ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].priority = 1; //TODO: determining LCG priority?
1175 ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].dataVol = bsrInd->dataVolInfo[lcgIdx].dataVol;
1178 /* Adding UE Id to list of pending UEs to be scheduled */
1179 cellCb->api->SchBsr(cellCb, ueCb->ueId);
1183 /*******************************************************************
1185 * @brief Processes SR UCI indication from MAC
1189 * Function : SchProcSrUciInd
1192 * Processes SR UCI indication from MAC
1194 * @params[in] Post structure
1196 * @return ROK - success
1199 * ****************************************************************/
1200 uint8_t SchProcSrUciInd(Pst *pst, SrUciIndInfo *uciInd)
1202 Inst inst = pst->dstInst-SCH_INST_START;
1205 SchCellCb *cellCb = schCb[inst].cells[inst];
1207 DU_LOG("\nDEBUG --> SCH : Received SR");
1209 ueCb = schGetUeCb(cellCb, uciInd->crnti);
1211 if(ueCb->state == SCH_UE_STATE_INACTIVE)
1213 DU_LOG("\nERROR --> SCH : Crnti %d is inactive", uciInd->crnti);
1216 if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1218 DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1221 if(uciInd->numSrBits)
1223 ueCb->srRcvd = true;
1224 /* Adding UE Id to list of pending UEs to be scheduled */
1225 cellCb->api->SchSrUciInd(cellCb, ueCb->ueId);
1230 /*******************************************************************
1232 * @brief Processes DL HARQ indication from MAC
1236 * Function : SchProcDlHarqInd
1239 * Processes DL HARQ indication from MAC
1241 * @params[in] Post structure
1242 * DL HARQ Indication
1243 * @return ROK - success
1246 * ****************************************************************/
1247 uint8_t SchProcDlHarqInd(Pst *pst, DlHarqInd *dlHarqInd)
1249 Inst inst = pst->dstInst-SCH_INST_START;
1251 SchCellCb *cellCb = schCb[inst].cells[inst];
1253 DU_LOG("\nDEBUG --> SCH : Received HARQ");
1255 ueCb = schGetUeCb(cellCb, dlHarqInd->crnti);
1257 if(ueCb->state == SCH_UE_STATE_INACTIVE)
1259 DU_LOG("\nERROR --> SCH : Crnti %d is inactive", dlHarqInd->crnti);
1263 schUpdateHarqFdbk(ueCb, dlHarqInd->numHarq, dlHarqInd->harqPayload, &dlHarqInd->slotInd);
1268 /*******************************************************************
1270 * @brief Allocates requested PRBs for DL
1274 * Function : allocatePrbDl
1277 * Allocates requested PRBs in DL
1278 * Keeps track of allocated PRB (using bitmap) and remaining PRBs
1280 * @params[in] prbAlloc table
1286 * @return ROK - success
1289 * ****************************************************************/
1290 uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
1291 uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1294 uint16_t broadcastPrbStart=0, broadcastPrbEnd=0;
1295 FreePrbBlock *freePrbBlock = NULLP;
1296 CmLList *freePrbNode = NULLP;
1297 PduTxOccsaion ssbOccasion=0, sib1Occasion=0;
1298 SchDlSlotInfo *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1299 SchPrbAlloc *prbAlloc = &schDlSlotInfo->prbAlloc;
1301 /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1302 * Search for an appropriate location in PRB grid and allocate requested resources */
1303 if(*startPrb == MAX_NUM_RB)
1305 /* Check if SSB/SIB1 is also scheduled in this slot */
1306 ssbOccasion = schCheckSsbOcc(cell, slotTime);
1307 sib1Occasion = schCheckSib1Occ(cell, slotTime);
1309 if(ssbOccasion && sib1Occasion)
1311 broadcastPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1312 broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1314 else if(ssbOccasion)
1316 broadcastPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1317 broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB -1;
1319 else if(sib1Occasion)
1321 broadcastPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.startPrb;
1322 broadcastPrbEnd = broadcastPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1325 /* Iterate through all free PRB blocks */
1326 freePrbNode = prbAlloc->freePrbBlockList.first;
1329 freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1331 /* If broadcast message is scheduled in this slot, then check if its PRBs belong to the current free block.
1332 * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1333 if((ssbOccasion || sib1Occasion) &&
1334 ((broadcastPrbStart >= freePrbBlock->startPrb) && (broadcastPrbStart <= freePrbBlock->endPrb)) && \
1335 ((broadcastPrbEnd >= freePrbBlock->startPrb) && (broadcastPrbEnd <= freePrbBlock->endPrb)))
1337 /* Implmentation is done such that highest-numbered free-RB is allocated first */
1338 if((freePrbBlock->endPrb > broadcastPrbEnd) && ((freePrbBlock->endPrb - broadcastPrbEnd) >= numPrb))
1340 /* If sufficient free PRBs are available above bradcast message then,
1341 * endPrb = freePrbBlock->endPrb
1342 * startPrb = endPrb - numPrb +1;
1344 *startPrb = freePrbBlock->endPrb - numPrb +1;
1347 else if((broadcastPrbStart > freePrbBlock->startPrb) && ((broadcastPrbStart - freePrbBlock->startPrb) >= numPrb))
1349 /* If free PRBs are available below broadcast message then,
1350 * endPrb = broadcastPrbStart - 1
1351 * startPrb = endPrb - numPrb +1
1353 *startPrb = broadcastPrbStart - numPrb;
1358 freePrbNode = freePrbNode->next;
1364 /* Check if requested number of blocks can be allocated from the current block */
1365 if (freePrbBlock->numFreePrb < numPrb)
1367 freePrbNode = freePrbNode->next;
1370 *startPrb = freePrbBlock->endPrb - numPrb +1;
1375 /* If no free block can be used to allocated request number of RBs */
1376 if(*startPrb == MAX_NUM_RB)
1380 /* If startPrb is known already, check if requested PRBs are available for allocation */
1383 freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1386 DU_LOG("\nERROR --> SCH: Requested DL PRB unavailable");
1391 /* Update bitmap to allocate PRBs */
1392 for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1394 if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1396 DU_LOG("\nERROR --> SCH: fillPrbBitmap() failed for symbol [%d] in DL", symbol);
1401 /* Update statistics of PRB usage if stats calculation is enabled */
1402 if(schCb[cell->instIdx].statistics.activeKpiList.dlTotPrbUseList.count)
1403 prbAlloc->numPrbAlloc += numPrb;
1405 /* Update the remaining number for free PRBs */
1406 removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1411 /*******************************************************************
1413 * @brief Allocates requested PRBs for UL
1417 * Function : allocatePrbUl
1420 * Allocates requested PRBs in UL
1421 * Keeps track of allocated PRB (using bitmap) and remaining PRBs
1423 * @params[in] prbAlloc table
1429 * @return ROK - success
1432 * ****************************************************************/
1433 uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
1434 uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1437 uint16_t prachStartPrb, prachNumPrb, prachEndPrb;
1438 bool isPrachOccasion;
1439 FreePrbBlock *freePrbBlock = NULLP;
1440 CmLList *freePrbNode = NULLP;
1441 SchPrbAlloc *prbAlloc = NULLP;
1445 DU_LOG("\nERROR --> SCH : allocatePrbUl(): Received cellCb is null");
1449 prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1450 /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1451 * Search for an appropriate location in PRB grid and allocate requested resources */
1452 if(*startPrb == MAX_NUM_RB)
1454 /* Check if PRACH is also scheduled in this slot */
1455 isPrachOccasion = schCheckPrachOcc(cell, slotTime);
1458 prachStartPrb = cell->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.msg1FreqStart;
1459 prachNumPrb = schCalcPrachNumRb(cell);
1460 prachEndPrb = prachStartPrb + prachNumPrb -1;
1463 /* Iterate through all free PRB blocks */
1464 freePrbNode = prbAlloc->freePrbBlockList.first;
1467 freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1469 /* If PRACH is scheduled in this slot, then check if its PRBs belong to the current free block.
1470 * PRBs required for PRACH cannot be allocated to any other message */
1471 if((isPrachOccasion) &&
1472 ((prachStartPrb >= freePrbBlock->startPrb) && (prachStartPrb <= freePrbBlock->endPrb)) &&
1473 ((prachEndPrb >= freePrbBlock->startPrb) && (prachEndPrb <= freePrbBlock->endPrb)))
1475 /* Implmentation is done such that highest-numbered free-RB is allocated first */
1476 if((freePrbBlock->endPrb > prachEndPrb) && ((freePrbBlock->endPrb - prachEndPrb) >= numPrb))
1478 /* If sufficient free PRBs are available above PRACH message then,
1479 * endPrb = freePrbBlock->endPrb
1480 * startPrb = endPrb - numPrb +1;
1482 *startPrb = freePrbBlock->endPrb - numPrb +1;
1485 else if((prachStartPrb > freePrbBlock->startPrb) && ((prachStartPrb - freePrbBlock->startPrb) >= numPrb))
1487 /* If free PRBs are available below PRACH message then,
1488 * endPrb = prachStartPrb - 1
1489 * startPrb = endPrb - numPrb +1
1491 *startPrb = prachStartPrb - numPrb;
1496 freePrbNode = freePrbNode->next;
1502 /* Check if requested number of PRBs can be allocated from currect block */
1503 if(freePrbBlock->numFreePrb < numPrb)
1505 freePrbNode = freePrbNode->next;
1508 *startPrb = freePrbBlock->endPrb - numPrb +1;
1513 /* If no free block can be used to allocated requested number of RBs */
1514 if(*startPrb == MAX_NUM_RB)
1519 /* If startPrb is known already, check if requested PRBs are available for allocation */
1520 freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1523 DU_LOG("\nERROR --> SCH: Requested UL PRB unavailable");
1528 /* Update bitmap to allocate PRBs */
1529 for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1531 if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1533 DU_LOG("\nERROR --> SCH: fillPrbBitmap() failed for symbol [%d] in UL", symbol);
1538 /* Update statistics of PRB usage if stats calculation is enabled */
1539 if(schCb[cell->instIdx].statistics.activeKpiList.ulTotPrbUseList.count)
1540 prbAlloc->numPrbAlloc += numPrb;
1542 /* Update the remaining number for free PRBs */
1543 removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1548 /*******************************************************************************
1550 * @brief Try to find Best Free Block with Max Num PRB
1554 * Function : searchLargestFreeBlock
1557 * Finds the FreeBlock with MaxNum of FREE PRB considering SSB/SIB1 ocassions.
1559 * @params[in] I/P > prbAlloc table (FreeBlock list)
1560 * I/P > Slot timing Info
1562 * I/P > Direction (UL/DL)
1565 * @return Max Number of Free PRB
1566 * If 0, then no Suitable Free Block
1568 * ********************************************************************************/
1570 uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_t *startPrb, Direction dir)
1572 uint16_t reservedPrbStart=0, reservedPrbEnd=0, maxFreePRB = 0;
1573 FreePrbBlock *freePrbBlock = NULLP;
1574 CmLList *freePrbNode = NULLP;
1575 SchPrbAlloc *prbAlloc = NULLP;
1576 bool checkOccasion = FALSE;
1578 *startPrb = 0; /*Initialize the StartPRB to zero*/
1580 /*Based on Direction, Reserved Messsages will differi.e.
1581 * DL >> SSB and SIB1 ocassions wheres for UL, PRACH ocassions to be checked
1582 * and reserved before allocation for dedicated DL/UL msg*/
1585 SchDlSlotInfo *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1586 PduTxOccsaion ssbOccasion=0, sib1Occasion=0;
1588 prbAlloc = &schDlSlotInfo->prbAlloc;
1590 ssbOccasion = schCheckSsbOcc(cell, slotTime);
1591 sib1Occasion = schCheckSib1Occ(cell, slotTime);
1593 checkOccasion = TRUE;
1594 if(ssbOccasion && sib1Occasion)
1596 reservedPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1597 reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB + \
1598 cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1600 else if(ssbOccasion)
1602 reservedPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1603 reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB -1;
1605 else if(sib1Occasion)
1607 reservedPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.startPrb;
1608 reservedPrbEnd = reservedPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1612 checkOccasion = FALSE;
1615 else if(dir == DIR_UL)
1617 prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1619 /* Check if PRACH is also scheduled in this slot */
1620 checkOccasion = schCheckPrachOcc(cell, slotTime);
1623 reservedPrbStart = cell->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.msg1FreqStart;
1624 reservedPrbEnd = reservedPrbStart + (schCalcPrachNumRb(cell)) -1;
1629 DU_LOG("\nERROR --> SCH: Invalid Direction!");
1630 return (maxFreePRB);
1633 freePrbNode = prbAlloc->freePrbBlockList.first;
1636 freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1638 /*For block with same numFreeBlocks, choose the one with HighestPRB range
1639 *Since FreeBLockList are arranged in Descending order of PRB range thus Skipping this block*/
1640 if(maxFreePRB >= freePrbBlock->numFreePrb)
1643 freePrbNode = freePrbNode->next;
1647 /* If Broadcast/Prach message is scheduled in this slot, then check if its PRBs belong to the current free block.
1648 * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1650 ((reservedPrbStart >= freePrbBlock->startPrb) && (reservedPrbStart <= freePrbBlock->endPrb)) && \
1651 ((reservedPrbEnd >= freePrbBlock->startPrb) && (reservedPrbEnd <= freePrbBlock->endPrb)))
1654 /* Implmentation is done such that highest-numbered free-RB is Checked first
1655 and freePRB in this block is greater than Max till now */
1656 if((freePrbBlock->endPrb > reservedPrbEnd) && ((freePrbBlock->endPrb - reservedPrbEnd) > maxFreePRB))
1658 /* If sufficient free PRBs are available above reserved message*/
1659 *startPrb = reservedPrbEnd + 1;
1660 maxFreePRB = (freePrbBlock->endPrb - reservedPrbEnd);
1662 /*Also check the other freeBlock (i.e. Above the reserved message) for MAX FREE PRB*/
1663 if((reservedPrbStart > freePrbBlock->startPrb) && ((reservedPrbStart - freePrbBlock->startPrb) > maxFreePRB))
1665 /* If free PRBs are available below reserved message*/
1666 *startPrb = freePrbBlock->startPrb;
1667 maxFreePRB = (reservedPrbStart - freePrbBlock->startPrb);
1672 if(maxFreePRB < freePrbBlock->numFreePrb)
1674 *startPrb = freePrbBlock->startPrb;
1675 maxFreePRB = freePrbBlock->numFreePrb;
1679 freePrbNode = freePrbNode->next;
1684 /*******************************************************************************
1686 * @brief This function is used to send Slice Cfg rsp to MAC
1690 * Function : SchSendSliceCfgRspToMac
1693 * function is used to send Slice Cfg rsp to MAC
1695 * @params[in] Pst *pst, SchSliceCfgRsp sliceCfgRsp
1699 * ********************************************************************************/
1700 void SchSendSliceCfgRspToMac(Inst inst, SchSliceCfgRsp sliceCfgRsp)
1704 memset(&rspPst, 0, sizeof(Pst));
1705 FILL_PST_SCH_TO_MAC(rspPst, inst);
1706 rspPst.event = EVENT_SLICE_CFG_RSP_TO_MAC;
1708 MacMessageRouter(&rspPst, (void *)&sliceCfgRsp);
1712 /*******************************************************************************
1714 * @brief This function is used to store or modify the slice configuration Sch DB
1718 * Function : addOrModifySliceCfgInSchDb
1721 * function is used to store or modify the slice configuration Sch DB
1723 * @params[in] SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq,
1724 * SchSliceCfgRsp cfgRsp, uint8_t count
1730 * ********************************************************************************/
1731 uint8_t addSliceCfgInSchDb(CmLListCp *sliceCfgInDb, SchRrmPolicyOfSlice *cfgReq)
1733 SchRrmPolicyOfSlice *sliceToStore;
1735 SCH_ALLOC(sliceToStore, sizeof(SchRrmPolicyOfSlice));
1738 memcpy(&sliceToStore->snssai, &cfgReq->snssai, sizeof(Snssai));
1739 memcpy(&sliceToStore->rrmPolicyRatioInfo, &cfgReq->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1740 addNodeToLList(sliceCfgInDb, sliceToStore, NULL);
1744 DU_LOG("\nERROR --> SCH : Memory allocation failed in addOrModifySliceCfgInSchDb");
1750 /*******************************************************************************
1752 * @brief fill slice configuration response
1756 * Function : fillSliceCfgRsp
1759 * fill slice configuration response
1761 * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t count
1767 * ********************************************************************************/
1768 uint8_t fillSliceCfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchCellCb *cellCb, SchSliceCfgReq *schSliceCfgReq)
1770 SchMacRsp sliceFound;
1771 uint8_t cfgIdx = 0, sliceIdx = 0, plmnIdx = 0, ret =ROK;
1772 SchSliceCfgRsp schSliceCfgRsp;
1774 for(cfgIdx = 0; cfgIdx<schSliceCfgReq->numOfConfiguredSlice; cfgIdx++)
1776 sliceFound = RSP_NOK;
1777 /* Here comparing the slice cfg request with the slice stored in cellCfg */
1778 for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
1780 for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices; sliceIdx++)
1782 /* If we find the SliceCfgReq's SNSSAI in CellCb's SNSSAI DB, we mark this slice as configured and add it to Sch's DB. */
1783 if(!memcmp(&schSliceCfgReq->listOfSlices[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai[sliceIdx], sizeof(Snssai)))
1785 if(addSliceCfgInSchDb(storedSliceCfg, schSliceCfgReq->listOfSlices[cfgIdx]) == ROK)
1787 sliceFound = RSP_OK;
1788 schSliceCfgRsp.cause = SUCCESSFUL;
1792 DU_LOG("\nERROR --> SCH : Failed to store slice configuration in SchDb");
1793 schSliceCfgRsp.cause = RESOURCE_UNAVAILABLE;
1802 if((sliceFound == RSP_NOK) && (schSliceCfgRsp.cause != RESOURCE_UNAVAILABLE))
1803 schSliceCfgRsp.cause = SLICE_NOT_FOUND;
1805 schSliceCfgRsp.snssai = schSliceCfgReq->listOfSlices[cfgIdx]->snssai;
1806 schSliceCfgRsp.rsp = sliceFound;
1807 SchSendSliceCfgRspToMac(inst, schSliceCfgRsp);
1812 /*******************************************************************************
1814 * @brief This function is used to free the slice cfg and re cfg request pointer
1818 * Function : freeSchSliceCfgReq
1821 * function is used to free the slice cfg and re cfg request pointer
1823 * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1828 * ********************************************************************************/
1829 void freeSchSliceCfgReq(SchSliceCfgReq *sliceCfgReq)
1835 if(sliceCfgReq->numOfConfiguredSlice)
1837 for(cfgIdx = 0; cfgIdx<sliceCfgReq->numOfConfiguredSlice; cfgIdx++)
1839 if(sliceCfgReq->listOfSlices[cfgIdx])
1841 SCH_FREE(sliceCfgReq->listOfSlices[cfgIdx], sizeof(SchRrmPolicyOfSlice));
1844 SCH_FREE(sliceCfgReq->listOfSlices, sliceCfgReq->numOfConfiguredSlice * sizeof(SchRrmPolicyOfSlice*));
1846 SCH_FREE(sliceCfgReq, sizeof(SchSliceCfgReq));
1849 /*******************************************************************************
1851 * @brief This function is used to store the slice configuration Sch DB
1855 * Function : SchProcSliceCfgReq
1858 * function is used to store the slice configuration Sch DB
1860 * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1866 * ********************************************************************************/
1867 uint8_t SchProcSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
1870 Inst inst = pst->dstInst - SCH_INST_START;
1872 DU_LOG("\nINFO --> SCH : Received Slice Cfg request from MAC");
1875 if(schSliceCfgReq->listOfSlices)
1877 /* filling the slice configuration response of each slice */
1878 if(fillSliceCfgRsp(inst, &schCb[inst].sliceCfg, schCb[inst].cells[0], schSliceCfgReq) != ROK)
1880 DU_LOG("\nERROR --> SCH : Failed to fill the slice cfg rsp");
1883 freeSchSliceCfgReq(schSliceCfgReq);
1888 DU_LOG("\nERROR --> SCH : Received SchSliceCfgReq is NULL");
1894 /*******************************************************************************
1896 * @brief This function is used to send Slice re Cfg rsp to MAC
1900 * Function : SchSendSliceRecfgRspToMac
1903 * function is used to send Slice re Cfg rsp to MAC
1905 * @params[in] Pst *pst, SchSliceRecfgRsp schSliceRecfgRsp
1909 * ********************************************************************************/
1910 void SchSendSliceRecfgRspToMac(Inst inst, SchSliceRecfgRsp schSliceRecfgRsp)
1914 memset(&rspPst, 0, sizeof(Pst));
1915 FILL_PST_SCH_TO_MAC(rspPst, inst);
1916 rspPst.event = EVENT_SLICE_RECFG_RSP_TO_MAC;
1918 MacMessageRouter(&rspPst, (void *)&schSliceRecfgRsp);
1921 /*******************************************************************************
1923 * @brief fill slice configuration response
1927 * Function : fillSliceRecfgRsp
1929 * Functionality: fill slice reconfiguration response
1931 * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t count
1937 * ********************************************************************************/
1939 uint8_t fillSliceRecfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchSliceRecfgReq *schSliceRecfgReq)
1941 SchMacRsp sliceFound;
1943 SchRrmPolicyOfSlice *rrmPolicyOfSlices;
1944 SchSliceRecfgRsp schSliceRecfgRsp;
1946 for(cfgIdx = 0; cfgIdx<schSliceRecfgReq->numOfConfiguredSlice; cfgIdx++)
1948 sliceFound = RSP_NOK;
1949 /* Here comparing the slice recfg request with the StoredSliceCfg */
1950 CmLList *sliceCfg = storedSliceCfg->first;
1954 rrmPolicyOfSlices = (SchRrmPolicyOfSlice*)sliceCfg->node;
1956 if(rrmPolicyOfSlices && (memcmp(&schSliceRecfgReq->listOfSlices[cfgIdx]->snssai, &(rrmPolicyOfSlices->snssai), sizeof(Snssai)) == 0))
1958 memcpy(&rrmPolicyOfSlices->rrmPolicyRatioInfo, &schSliceRecfgReq->listOfSlices[cfgIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1959 sliceFound = RSP_OK;
1962 sliceCfg = sliceCfg->next;
1965 schSliceRecfgRsp.snssai = schSliceRecfgReq->listOfSlices[cfgIdx]->snssai;
1966 schSliceRecfgRsp.rsp = sliceFound;
1967 if(schSliceRecfgRsp.rsp == RSP_OK)
1968 schSliceRecfgRsp.cause = SUCCESSFUL;
1970 schSliceRecfgRsp.cause = SLICE_NOT_FOUND;
1971 SchSendSliceRecfgRspToMac(inst, schSliceRecfgRsp);
1975 /*******************************************************************************
1977 * @brief This function is used to store the slice reconfiguration Sch DB
1981 * Function : SchProcSliceRecfgReq
1984 * function is used to store the slice re configuration Sch DB
1986 * @params[in] Pst *pst, SchSliceRecfgReq *schSliceRecfgReq
1992 * ********************************************************************************/
1993 uint8_t SchProcSliceRecfgReq(Pst *pst, SchSliceRecfgReq *schSliceRecfgReq)
1996 Inst inst = pst->dstInst - SCH_INST_START;
1998 DU_LOG("\nINFO --> SCH : Received Slice ReCfg request from MAC");
1999 if(schSliceRecfgReq)
2001 if(schSliceRecfgReq->listOfSlices)
2003 /* filling the slice configuration response of each slice */
2004 if(fillSliceRecfgRsp(inst, &schCb[inst].sliceCfg, schSliceRecfgReq) != ROK)
2006 DU_LOG("\nERROR --> SCH : Failed to fill sch slice cfg response");
2009 freeSchSliceCfgReq(schSliceRecfgReq);
2014 DU_LOG("\nERROR --> SCH : Received SchSliceRecfgReq is NULL");
2020 /****************************************************************************
2022 * @brief Stores the Paging Configuration from DU APP in CellCb
2026 * Function : schProcPagingParam
2029 * Process the Paging Configuration when FirstPDCCHMonitoring for
2030 * Paging Ocassion is not present.
2032 * As per 38.304 Sec 7.1,
2033 * "When firstPDCCH-MonitoringOccasionOfPO is present, the
2034 * starting PDCCH monitoring occasion number of (i_s + 1)th PO is the
2035 * (i_s + 1)th value of the firstPDCCHMonitoringOccasionOfPO
2036 * parameter; otherwise, it is equal to i_s * S."
2037 * "S = number of actual transmitted SSBs determined according
2038 * to ssb-PositionsInBurst in SIB1"
2040 * @params[in] SchCellCb *cell
2044 *************************************************************************/
2045 void schProcPagingCfg(SchCellCb *cell)
2047 SchPcchCfg *pageCfgRcvd = NULL;
2050 pageCfgRcvd = &(cell->cellCfg.dlCfgCommon.schPcchCfg);
2052 if(pageCfgRcvd->poPresent == TRUE)
2054 /*Fetching first Pdcch Monitoring Occasion for SFN (i_s + 1)th*/
2055 for(i_sIdx = 0; i_sIdx < pageCfgRcvd->numPO; i_sIdx++)
2057 cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pageCfgRcvd->pagingOcc[i_sIdx] / MAX_SYMB_PER_SLOT ;
2058 if ((pageCfgRcvd->pagingOcc[i_sIdx] % MAX_SYMB_PER_SLOT) != 0 )
2060 cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot++;
2063 cell->pageCb.pagMonOcc[i_sIdx].frameOffset = 0;
2069 schCfgPdcchMonOccOfPO(cell);
2073 /****************************************************************************
2075 * @brief Calculate PO if not present in Configuration
2079 * Function : schCfgPdcchMonOccOfPO
2081 * Functionality: In this function, PO are calculated i_s * S because
2082 * FirstPDCCHMonitoring_ForPO is not present.
2084 * @params[in] SchCellCb *cellCb
2088 *************************************************************************/
2089 void schCfgPdcchMonOccOfPO(SchCellCb *cell)
2091 uint8_t cnt = 0, incr = 1, i_sIdx = 0, frameOffSet = 0;
2092 uint8_t nsValue = cell->cellCfg.dlCfgCommon.schPcchCfg.numPO;
2093 uint8_t totalNumSsb = countSetBits(cell->cellCfg.ssbPosInBurst[0]);
2094 SlotTimingInfo tmpTimingInfo, pdcchTime;
2096 /*Starting with First Sfn and slot*/
2097 tmpTimingInfo.sfn = 0;
2098 tmpTimingInfo.slot = 0;
2100 pdcchTime = tmpTimingInfo;
2102 while(i_sIdx < nsValue)
2104 /*Increment frame Offset if PO falls on next SFN*/
2105 if(pdcchTime.sfn != tmpTimingInfo.sfn)
2109 pdcchTime = tmpTimingInfo;
2110 schIncrSlot(&(tmpTimingInfo), incr, cell->numSlots);
2114 cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2115 cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2121 if((cnt == totalNumSsb) && (i_sIdx < MAX_PO_PER_PF))
2123 cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2124 cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2132 /****************************************************************************
2134 * @brief Storing the paging information in SCH database
2138 * Function : schAddPagingIndtoList
2140 * Functionality: Storing the paging information in SCH database
2142 * @params[in] CmLListCp *storedPageList, CmLList *pageIndInfo
2144 * @return ROK - sucess
2147 *************************************************************************/
2148 uint8_t schAddPagingIndtoList(CmLListCp *storedPageList,void * pageIndInfo)
2150 CmLList *firstNodeOfList = NULLP;
2151 CmLList *currentNodeInfo = NULLP;
2152 SchPageInfo *tempNode = NULLP, *recvdNode = NULLP;
2154 recvdNode = (SchPageInfo*) pageIndInfo;
2155 CM_LLIST_FIRST_NODE(storedPageList,firstNodeOfList);
2157 SCH_ALLOC(currentNodeInfo, sizeof(CmLList));
2158 if(!currentNodeInfo)
2160 DU_LOG("\nERROR --> SCH : schAddPagingIndtoList() : Memory allocation failed");
2164 currentNodeInfo->node = (PTR)pageIndInfo;
2165 while(firstNodeOfList)
2167 tempNode = (SchPageInfo*)(firstNodeOfList->node);
2168 if ((recvdNode->pageTxTime.slot < tempNode->pageTxTime.slot))
2170 cmLListInsCrnt(storedPageList, currentNodeInfo);
2173 else if ((recvdNode->pageTxTime.slot == tempNode->pageTxTime.slot))
2175 DU_LOG("\nERROR --> SCH : schAddPagingIndtoList() : Slot[%d] is already present in the list", recvdNode->pageTxTime.slot);
2180 CM_LLIST_NEXT_NODE(storedPageList, firstNodeOfList);
2184 if(!firstNodeOfList)
2186 cmLListAdd2Tail(storedPageList, currentNodeInfo);
2188 DU_LOG("\nDEBUG --> SCH : Paging information is stored successfully for PF:%d, Slot:%d",\
2189 recvdNode->pageTxTime.sfn, recvdNode->pageTxTime.slot);
2193 /****************************************************************************
2195 * @brief Process paging indication at SCH recevied form MAC
2199 * Function : SchProcPagingInd
2201 * Functionality: Process paging indication at SCH recevied form MAC
2203 * @params[in] Pst *pst, SchPageInd *pageInd
2207 *************************************************************************/
2208 uint8_t SchProcPagingInd(Pst *pst, SchPageInd *pageInd)
2210 uint8_t ret = RFAILED;
2211 uint16_t cellIdx = 0;
2212 Inst inst = pst->dstInst - SCH_INST_START;
2213 SchCellCb *cellCb = NULLP;
2214 SchPageInfo *pageInfo = NULLP;
2218 DU_LOG("\nDEBUG --> SCH : Received paging indication from MAC for cellId[%d]",\
2222 for(cellIdx = 0; cellIdx < MAX_NUM_CELL; cellIdx++)
2224 if((schCb[inst].cells[cellIdx]) && (schCb[inst].cells[cellIdx]->cellId == pageInd->cellId))
2226 cellCb = schCb[inst].cells[cellIdx];
2232 if(pageInd->i_s > cellCb->cellCfg.dlCfgCommon.schPcchCfg.numPO)
2234 DU_LOG("\nERROR --> SCH : SchProcPagingInd(): i_s should not be greater than number of paging occasion");
2238 SCH_ALLOC(pageInfo, sizeof(SchPageInfo));
2241 pageInfo->pf = pageInd->pf;
2242 pageInfo->i_s = pageInd->i_s;
2243 pageInfo->pageTxTime.cellId = pageInd->cellId;
2244 pageInfo->pageTxTime.sfn = (pageInd->pf + cellCb->pageCb.pagMonOcc[pageInd->i_s].frameOffset) % MAX_SFN;
2245 pageInfo->pageTxTime.slot = cellCb->pageCb.pagMonOcc[pageInd->i_s].pagingOccSlot;
2246 pageInfo->mcs = DEFAULT_MCS;
2247 pageInfo->msgLen = pageInd->pduLen;
2248 SCH_ALLOC(pageInfo->pagePdu, pageInfo->msgLen);
2249 if(!pageInfo->pagePdu)
2251 DU_LOG("\nERROR --> SCH : SchProcPagingInd(): Failed to allocate memory");
2255 memcpy(pageInfo->pagePdu, pageInd->pagePdu, pageInfo->msgLen);
2256 ret = schAddPagingIndtoList(&cellCb->pageCb.pageIndInfoRecord[pageInfo->pageTxTime.sfn], pageInfo);
2259 DU_LOG("\nERROR --> SCH : SchProcPagingInd(): Failed to store paging record");
2265 DU_LOG("\nERROR --> SCH : SchProcPagingInd(): Failed to allocate memory");
2271 DU_LOG("\nERROR --> SCH : Cell ID [%d] not found", pageInd->cellId);
2273 SCH_FREE(pageInd->pagePdu, pageInd->pduLen);
2274 SCH_FREE(pageInd, sizeof(SchPageInd));
2278 DU_LOG("\nERROR --> SCH : SchProcPagingInd(): Received null pointer");
2284 /***********************************************************
2286 * Func : SchFillCfmPst
2289 * Desc : Fills the Confirmation Post Structure cfmPst using the reqPst
2290 * and the cfm->hdr.response.
2297 * File : rg_sch_lmm.c
2299 **********************************************************/
2309 inst = (reqPst->dstInst - SCH_INST_START);
2311 cfmPst->srcEnt = ENTMAC;
2312 cfmPst->srcInst = (Inst) 1;
2313 cfmPst->srcProcId = schCb[inst].schInit.procId;
2314 cfmPst->dstEnt = ENTMAC;
2315 cfmPst->dstInst = (Inst) 0;
2316 cfmPst->dstProcId = reqPst->srcProcId;
2318 cfmPst->selector = cfm->hdr.response.selector;
2319 cfmPst->region = cfm->hdr.response.mem.region;
2320 cfmPst->pool = cfm->hdr.response.mem.pool;
2325 /*******************************************************************
2327 * @brief Processes DL CQI ind from MAC
2331 * Function : SchProcDlCqiInd
2334 * Processes DL CQI ind from MAC
2337 * @return ROK - success
2340 * ****************************************************************/
2341 uint8_t SchProcDlCqiInd(Pst *pst, SchDlCqiInd *dlCqiInd)
2344 uint16_t ueId = 0, cellIdx = 0;
2345 SchUeCb *ueCb = NULLP;
2346 SchCellCb *cell = NULLP;
2347 Inst inst = pst->dstInst-SCH_INST_START;
2351 DU_LOG("\nERROR --> SCH : SchProcDlCqiInd(): CQI Ind is empty");
2356 GET_CELL_IDX(dlCqiInd->cellId, cellIdx);
2357 cell = schCb[inst].cells[cellIdx];
2360 DU_LOG("\nERROR --> SCH : SchProcDlCqiInd(): cell Id[%d] not found", dlCqiInd->cellId);
2365 if(cell->cellId == dlCqiInd->cellId)
2367 GET_UE_ID(dlCqiInd->crnti, ueId);
2368 ueCb = &cell->ueCb[ueId-1];
2369 if(ueCb->crnti != dlCqiInd->crnti)
2371 DU_LOG("\nERROR --> SCH : SchProcDlCqiInd(): UeCb for received crnti[%d] not found", dlCqiInd->crnti);
2376 /*TODO: complete the processing of DL CQI Ind*/
2381 DU_LOG("\nERROR --> SCH : SchProcDlCqiInd(): Received cell Id[%d] from MAC is not matching with CellID[%d] in SCH Cb",\
2382 dlCqiInd->cellId, cell->cellId);
2390 /*******************************************************************
2392 * @brief Processes UL CQI ind from MAC
2396 * Function : SchProcUlCqiInd
2399 * Processes UL CQI ind from MAC
2402 * @return ROK - success
2405 * ****************************************************************/
2406 uint8_t SchProcUlCqiInd(Pst *pst, SchUlCqiInd *ulCqiInd)
2409 uint16_t ueId = 0, cellIdx = 0;
2410 SchUeCb *ueCb = NULLP;
2411 SchCellCb *cell = NULLP;
2412 Inst inst = pst->dstInst-SCH_INST_START;
2416 DU_LOG("\nERROR --> SCH : SchProcUlCqiInd(): CQI Ind is empty");
2421 GET_CELL_IDX(ulCqiInd->cellId, cellIdx);
2422 cell = schCb[inst].cells[cellIdx];
2425 DU_LOG("\nERROR --> SCH : SchProcUlCqiInd(): cell Id[%d] not found", ulCqiInd->cellId);
2430 if(cell->cellId == ulCqiInd->cellId)
2432 GET_UE_ID(ulCqiInd->crnti, ueId);
2433 ueCb = &cell->ueCb[ueId-1];
2434 if(ueCb->crnti != ulCqiInd->crnti)
2436 DU_LOG("\nERROR --> SCH : SchProcUlCqiInd(): UeCb for received crnti[%d] not found",ulCqiInd->crnti);
2441 /*TODO: complete the processing of UL CQI Ind*/
2446 DU_LOG("\nERROR --> SCH : SchProcUlCqiInd(): Received cell Id[%d] from MAC is not matching with CellId[%d] in SCH Cb",\
2447 ulCqiInd->cellId, cell->cellId);
2455 /*******************************************************************
2457 * @brief Processes PHR ind from MAC
2461 * Function : SchProcPhrInd
2464 * Processes PHR ind from MAC
2467 * @return ROK - success
2470 * ****************************************************************/
2471 uint8_t SchProcPhrInd(Pst *pst, SchPwrHeadroomInd *schPhrInd)
2474 uint16_t ueId = 0, cellIdx = 0;
2475 SchUeCb *ueCb = NULLP;
2476 SchCellCb *cell = NULLP;
2477 Inst inst = pst->dstInst-SCH_INST_START;
2481 DU_LOG("\nERROR --> SCH : SchProcPhrInd(): PHR is empty");
2486 GET_CELL_IDX(schPhrInd->cellId, cellIdx);
2487 cell = schCb[inst].cells[cellIdx];
2490 DU_LOG("\nERROR --> SCH : schProcPhrInd(): cell Id[%d] is not found", schPhrInd->cellId);
2495 if(cell->cellId == schPhrInd->cellId)
2497 GET_UE_ID(schPhrInd->crnti, ueId);
2498 ueCb = &cell->ueCb[ueId-1];
2499 if(ueCb->crnti != schPhrInd->crnti)
2501 DU_LOG("\nERROR --> SCH : SchProcPhrInd(): UeCb for received crnti[%d] not found",schPhrInd->crnti);
2506 /*TODO: complete the processing of PHR Ind*/
2511 DU_LOG("\nERROR --> SCH : SchProcPhrInd(): Mismatch between Received cell Id[%d] from MAC and CellID[%d] in SCH CB ",\
2512 schPhrInd->cellId, cell->cellId);
2520 /*******************************************************************
2522 * @brief Fill and send statistics response to MAC
2526 * Function : SchSendStatsRspToMac
2528 * Functionality: Fill and send statistics response to MAC
2530 * @params[in] Inst inst, SchMacRsp result
2531 * @return ROK - success
2534 * ****************************************************************/
2535 uint8_t SchSendStatsRspToMac(SchStatsRsp *statsRsp)
2539 SchStatsRsp *schStatsRsp;
2541 DU_LOG("\nINFO --> SCH : Filling statistics response");
2542 SCH_ALLOC(schStatsRsp, sizeof(SchStatsRsp));
2543 if(schStatsRsp == NULLP)
2545 DU_LOG("\nERROR --> SCH : Failed to allocate memory in SchSendStatsRspToMac()");
2549 memcpy(schStatsRsp, statsRsp, sizeof(SchStatsRsp));
2550 memset(statsRsp, 0, sizeof(SchStatsRsp));
2552 /* Filling response post */
2553 memset(&rspPst, 0, sizeof(Pst));
2554 FILL_PST_SCH_TO_MAC(rspPst, inst);
2555 rspPst.event = EVENT_STATISTICS_RSP_TO_MAC;
2557 ret = MacMessageRouter(&rspPst, (void *)schStatsRsp);
2560 DU_LOG("\nERROR --> SCH : SchSendStatsRspToMac(): Failed to send Statistics Response");
2566 /*******************************************************************
2568 * @brief Rejects all statistics group requested by MAC
2572 * Function : SchRejectAllStats
2574 * Functionality: Add all statistics group received in statistics
2575 * request from MAC, to Reject-Stats-Group-List in statistics
2578 * @params[in] Statistics request from MAC
2579 * Cause of rejection
2580 * @return ROK - success
2583 * ****************************************************************/
2584 uint8_t SchRejectAllStats(SchStatsReq *schStatsReq, CauseOfResult cause)
2587 SchStatsRsp schStatsRsp;
2589 memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
2591 /* Copying all stats group from stats request to stats response */
2592 schStatsRsp.subscriptionId = schStatsReq->subscriptionId;
2593 for(grpIdx = 0; grpIdx < schStatsReq->numStatsGroup; grpIdx++)
2595 schStatsRsp.statsGrpRejectedList[grpIdx].groupId = schStatsReq->statsGrpList[grpIdx].groupId;
2596 schStatsRsp.statsGrpRejectedList[grpIdx].cause = cause;
2598 schStatsRsp.numGrpRejected = schStatsReq->numStatsGroup;
2600 return SchSendStatsRspToMac(&schStatsRsp);
2603 /*******************************************************************
2605 * @brief Add active KPI pointers to KPI-Active-List
2609 * Function : schAddToKpiActiveList
2611 * Functionality: For each active statistics group for which timer
2612 * is running, add its KPI pointer to KPI-Active-List.
2614 * When it is needed to update a KPI parameters, we need not
2615 * traverse all statistics group and all KPIs within a group
2616 * to get the specific KPI pointer to be updated.
2617 * Instead, we can traverse through KPI-Active-List and update
2618 * all entries in this list.
2620 * @params[in] Pointer to the prb usage info link list
2621 * Pointer to the stats ccnfig which we need to add
2622 * @return ROK - success
2625 * ****************************************************************/
2626 uint8_t schAddToKpiActiveList(CmLListCp *kpiList, PTR kpiStatsInfo)
2628 CmLList *node = NULLP;
2630 SCH_ALLOC(node, sizeof(CmLList));
2633 node->node = kpiStatsInfo;
2634 cmLListAdd2Tail(kpiList, node);
2637 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2641 /*******************************************************************
2643 * @brief add the stats group information in statistics's statsGrpList
2647 * Function : schAddToStatsGrpList
2649 * Functionality: add the stats group information in statsGrpList
2650 * [Step 1] - Allocating the memory for the stats group in which
2651 * we need to fill into the list as a node.
2652 * [Step 2] - If allocation is successful then start traversing
2653 * each measurment cfg index of received group info.
2654 * [Step 2.1] Validate all measurements. If validation succeeds, go
2655 * to [step 2.2]. Otherwise, reject the stats group and go to step 3.
2656 * [Step 2.2] Add each KPI/measurementCfg into activeKpiList one by one.
2657 * If it fails for any KPI, reject the whole statsGrp and go to step 3..
2658 * [Step 2.3] Fill other group related information
2659 * [Step 2.4] Initialise and start timer
2660 * [Step 2.5] Once all validation and configuration is successful, add
2661 * statsGrp node into statistic's StatsGrpList.
2662 * [Step 2.5.1] If node successfully added to the list, then
2663 * fill the group related info in stats rsp's accepted list.
2664 * [Step 2.5.2] Else goto step 3
2665 * [Step 3] - If failed fill the group related info in stats rsp's
2670 * Pointer to the stats rsp
2672 * Stats Grp Info which needs to be store in the list
2673 * @return ROK - success
2676 * ****************************************************************/
2678 uint8_t schAddToStatsGrpList(Inst inst, struct schStatsRsp *statsRsp, uint64_t subscriptionId, SchStatsGrpInfo *grpInfo)
2682 uint8_t reqMeasIdx=0;
2683 CauseOfResult cause;
2684 bool measTypeInvalid=false;
2685 CmLList *statsGrpNode=NULLP;
2686 SchStatsGrp *grpInfoDb = NULLP;
2689 SCH_ALLOC(grpInfoDb, sizeof(SchStatsGrp));
2690 if(grpInfoDb == NULLP)
2692 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2693 cause = RESOURCE_UNAVAILABLE;
2699 for(reqMeasIdx = 0; reqMeasIdx < grpInfo->numStats; reqMeasIdx++)
2702 switch(grpInfo->statsList[reqMeasIdx])
2704 case SCH_DL_TOTAL_PRB_USAGE:
2706 SCH_ALLOC(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
2707 if(!grpInfoDb->kpiStats.dlTotalPrbUsage)
2709 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2710 measTypeInvalid = true;
2711 cause = RESOURCE_UNAVAILABLE;
2717 case SCH_UL_TOTAL_PRB_USAGE:
2719 SCH_ALLOC(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
2720 if(!grpInfoDb->kpiStats.ulTotalPrbUsage)
2722 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2723 measTypeInvalid = true;
2724 cause = RESOURCE_UNAVAILABLE;
2732 DU_LOG("\nERROR --> SCH : SchProcStatsReq: Invalid measurement type [%d]", \
2733 grpInfo->statsList[reqMeasIdx]);
2734 measTypeInvalid = true;
2735 cause = PARAM_INVALID;
2747 while(measTypeInvalid==false)
2749 if(grpInfoDb->kpiStats.dlTotalPrbUsage)
2752 if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, (PTR)grpInfoDb->kpiStats.dlTotalPrbUsage)!=ROK)
2754 DU_LOG("\nERROR --> E2AP : KPI addition failed in %s at %d",__func__,__LINE__);
2755 cause = RESOURCE_UNAVAILABLE;
2761 if(grpInfoDb->kpiStats.ulTotalPrbUsage)
2764 if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR)grpInfoDb->kpiStats.ulTotalPrbUsage) != ROK)
2766 DU_LOG("\nERROR --> E2AP : KPI addition failed in %s at %d",__func__,__LINE__);
2767 cause = RESOURCE_UNAVAILABLE;
2774 grpInfoDb->schInst = inst;
2775 grpInfoDb->groupId = grpInfo->groupId;
2776 grpInfoDb->periodicity = grpInfo->periodicity;
2777 grpInfoDb->subscriptionId = subscriptionId;
2780 cmInitTimers(&(grpInfoDb->periodTimer), 1);
2781 schStartTmr(&schCb[inst], (PTR)(grpInfoDb), EVENT_STATISTICS_TMR, grpInfoDb->periodicity);
2784 SCH_ALLOC(statsGrpNode, sizeof(CmLList));
2788 statsGrpNode->node = (PTR) grpInfoDb;
2789 cmLListAdd2Tail(&schCb[inst].statistics.statsGrpList, statsGrpNode);
2790 statsRsp->statsGrpAcceptedList[statsRsp->numGrpAccepted] = grpInfo->groupId;
2791 statsRsp->numGrpAccepted++;
2799 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at %d",__func__,__LINE__);
2800 cause = RESOURCE_UNAVAILABLE;
2812 deleteStatsGrpInfo(inst, grpInfoDb);
2813 SCH_FREE(grpInfoDb, sizeof(SchStatsGrp));
2815 statsRsp->statsGrpRejectedList[statsRsp->numGrpRejected].groupId = grpInfo->groupId;
2816 statsRsp->statsGrpRejectedList[statsRsp->numGrpRejected].cause = cause;
2817 statsRsp->numGrpRejected++;
2823 /*******************************************************************
2825 * @brief Processes Statistics Request from MAC
2829 * Function : SchProcStatsReq
2833 * This function process the statistics request from MAC:
2834 * [Step 1] Basic validation. If fails, all stats group in stats request are
2836 * [Step 2] If basic validations passed, traverse all stats group and
2837 * validate each measurement types in each group.
2838 * [Step 3] If any measurement type validation fails in a group, that group
2839 * is not configured and it is added to stats-group-rejected-list in
2840 * sch-stats-response message.
2841 * [Step 4] If a group passes all validation, it is added to SCH database.
2842 * And the group is added to stats-group-accepted-list in sch-stats-response message.
2843 * [Step 5] sch-stats-response is sent to du app with stats-group-rejected-list
2844 * and stats-group-accepted-list.
2846 * @params[in] Post structure
2847 * Statistics Request from MAC
2848 * @return ROK - success
2851 * ****************************************************************/
2852 uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq)
2854 bool allocFailed = false;
2855 uint8_t grpIdx = 0, reqGrpIdx = 0;
2856 SchStatsGrpInfo *grpInfo = NULLP;
2857 SchStatsRsp schStatsRsp;
2858 Inst inst = pst->dstInst - SCH_INST_START;
2860 DU_LOG("\nINFO --> SCH : Received Statistics Request from MAC");
2862 if(statsReq == NULLP)
2864 DU_LOG("\nERROR --> SCH : SchProcStatsReq(): Received Null pointer");
2869 if(schCb[inst].statistics.statsGrpList.count >= MAX_NUM_STATS_GRP)
2871 DU_LOG("\nERROR --> SCH : SchProcStatsReq: Maximum number of statistics configured. \
2872 Cannot process new request.");
2873 SchRejectAllStats(statsReq, RESOURCE_UNAVAILABLE);
2874 SCH_FREE(statsReq, sizeof(SchStatsReq));
2878 memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
2881 for(reqGrpIdx=0; reqGrpIdx<statsReq->numStatsGroup && grpIdx<MAX_NUM_STATS; reqGrpIdx++)
2883 grpInfo = &statsReq->statsGrpList[reqGrpIdx];
2885 if(allocFailed == true)
2887 schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].groupId = grpInfo->groupId;
2888 schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].cause = RESOURCE_UNAVAILABLE;
2889 schStatsRsp.numGrpRejected++;
2894 if(schAddToStatsGrpList(inst, &schStatsRsp, statsReq->subscriptionId, grpInfo) != ROK)
2896 DU_LOG("\nERROR --> SCH : SchProcStatsReq(): Failed to fill the stats group list");
2897 if((schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected-1].groupId == grpInfo->groupId &&\
2898 (schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected-1].cause == RESOURCE_UNAVAILABLE)))
2906 schStatsRsp.subscriptionId = statsReq->subscriptionId;
2907 SCH_FREE(statsReq, sizeof(SchStatsReq));
2910 SchSendStatsRspToMac(&schStatsRsp);
2915 /*******************************************************************
2917 * @brief Fill and send statistics indication to MAC
2921 * Function : SchSendStatsIndToMac
2923 * Functionality: Fill and send statistics indication to MAC
2925 * @params[in] SCH Instance
2928 * Size of value parameter
2929 * @return ROK - success
2932 * ****************************************************************/
2933 uint8_t SchSendStatsIndToMac(Inst inst, SchStatsInd *statsInd)
2939 DU_LOG("\nDEBUG --> SCH : Filling statistics indication");
2942 /* Filling post structure */
2943 memset(&pst, 0, sizeof(Pst));
2944 FILL_PST_SCH_TO_MAC(pst, inst);
2945 pst.event = EVENT_STATISTICS_IND_TO_MAC;
2947 ret = MacMessageRouter(&pst, (void *)statsInd);
2950 DU_LOG("\nERROR --> SCH : SchSendStatsIndToMac(): Failed to send Statistics Indication");
2956 * @brief Handler to process Timer expiry of DL Total PRB Usage calculation
2958 * @param[in] cb Control block depending on the type of the timer event.
2959 * @param[in] tmrEvnt Timer event to be started
2961 * @return Bool indicating whether the timer is running or not
2965 double calcDlTotalPrbUsage(TotalPrbUsage *dlTotalPrbUsage)
2967 double percentageOfTotalPrbUsed = 0;
2969 if(dlTotalPrbUsage->totalPrbAvailForTx)
2970 percentageOfTotalPrbUsed = ((100.0 * dlTotalPrbUsage->numPrbUsedForTx) / dlTotalPrbUsage->totalPrbAvailForTx);
2972 memset(dlTotalPrbUsage, 0, sizeof(TotalPrbUsage));
2974 return percentageOfTotalPrbUsed;
2978 * @brief Handler to check if the timer is running
2980 * @param[in] cb Control block depending on the type of the timer event.
2981 * @param[in] tmrEvnt Timer event to be started
2983 * @return Bool indicating whether the timer is running or not
2987 uint8_t calcUlTotalPrbUsage(TotalPrbUsage *ulTotalPrbUsage)
2989 double percentageOfTotalPrbUsed = 0;
2991 if(ulTotalPrbUsage->totalPrbAvailForTx)
2992 percentageOfTotalPrbUsed = ((100.0 * ulTotalPrbUsage->numPrbUsedForTx) / ulTotalPrbUsage->totalPrbAvailForTx);
2994 memset(ulTotalPrbUsage, 0, sizeof(TotalPrbUsage));
2996 return percentageOfTotalPrbUsed;
3000 * @brief Calculates statistics in a group and sends
3001 * statistics indication for this group
3003 * @param[in] Statistics group info
3009 uint8_t schCalcAndSendGrpStats(SchStatsGrp *grpInfo)
3011 uint8_t measStatsIdx = 0;
3012 SchStatsInd statsInd;
3014 memset(&statsInd, 0, sizeof(SchStatsInd));
3015 statsInd.subscriptionId = grpInfo->subscriptionId;
3016 statsInd.groupId = grpInfo->groupId;
3018 if(grpInfo->kpiStats.dlTotalPrbUsage)
3020 statsInd.measuredStatsList[measStatsIdx].type = SCH_DL_TOTAL_PRB_USAGE;
3021 statsInd.measuredStatsList[measStatsIdx].value = calcDlTotalPrbUsage(grpInfo->kpiStats.dlTotalPrbUsage);
3025 if(grpInfo->kpiStats.ulTotalPrbUsage)
3027 statsInd.measuredStatsList[measStatsIdx].type = SCH_UL_TOTAL_PRB_USAGE;
3028 statsInd.measuredStatsList[measStatsIdx].value = calcUlTotalPrbUsage(grpInfo->kpiStats.ulTotalPrbUsage);
3032 statsInd.numStats = measStatsIdx;
3034 return SchSendStatsIndToMac(grpInfo->schInst, &statsInd);
3037 /*******************************************************************
3039 * @brief Delete node from active kpi list
3043 * Function :deleteNodeFrmKpiList
3046 * Delete statistics group
3049 * Kpi list from which a node needs to be deleted
3050 * Nodes info which a node needs to be deleted
3052 * ****************************************************************/
3054 void deleteNodeFrmKpiList(CmLListCp *kpiList, PTR kpiNodeInfoToDel)
3056 CmLList *kpiNode=NULLP;
3058 CM_LLIST_FIRST_NODE(kpiList, kpiNode);
3061 if(kpiNode->node == kpiNodeInfoToDel)
3063 cmLListDelFrm(kpiList, kpiNode);
3064 SCH_FREE(kpiNode, sizeof(CmLList));
3067 kpiNode = kpiNode->next;
3072 /*******************************************************************
3074 * @brief Delete statistics group info
3078 * Function : deleteStatsGrpInfo
3081 * Delete statistics group info
3088 * ****************************************************************/
3089 void deleteStatsGrpInfo(Inst inst, SchStatsGrp *statsGrpInfo)
3093 if(statsGrpInfo->kpiStats.dlTotalPrbUsage)
3095 deleteNodeFrmKpiList(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, (PTR) statsGrpInfo->kpiStats.dlTotalPrbUsage);
3096 SCH_FREE(statsGrpInfo->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
3099 if(statsGrpInfo->kpiStats.ulTotalPrbUsage)
3101 deleteNodeFrmKpiList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR) statsGrpInfo->kpiStats.ulTotalPrbUsage);
3102 SCH_FREE(statsGrpInfo->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
3105 if(schChkTmr((PTR)statsGrpInfo, EVENT_STATISTICS_TMR) == true)
3107 schStopTmr(&schCb[inst], (PTR)statsGrpInfo, EVENT_STATISTICS_TMR);
3110 memset(statsGrpInfo, 0, sizeof(SchStatsGrp));
3114 /*******************************************************************
3116 * @brief Delete statistics group Node
3120 * Function : deleteStatsGrpNode
3123 * Delete statistics group node
3130 * ****************************************************************/
3131 void deleteStatsGrpNode(Inst inst, CmLList *grpNode)
3133 SchStatsGrp *statsGrpInfo=NULLP;
3137 statsGrpInfo = (SchStatsGrp*)grpNode->node;
3138 deleteStatsGrpInfo(inst, statsGrpInfo);
3139 memset(statsGrpInfo, 0, sizeof(SchStatsGrp));
3140 SCH_FREE(grpNode->node, sizeof(SchStatsGrp));
3141 SCH_FREE(grpNode, sizeof(CmLList));
3145 /******************************************************************
3147 * @brief Deletion of node from statistics group list
3151 * Function : deleteFromStatsGrpList
3153 * Functionality: Deletion of node from statistics group list
3154 * [Step 1]: Traverse each and every node of stats group list
3155 * stored in the database
3156 * [Step 2]: Check if the node's subscription id is same
3157 * as the subscription id received. If same then go to step 3
3158 * else move to the next node of the list.
3159 * [Step 3]: If deleteAllGrp == true, then delete the node and
3160 * move to the next node of the list.
3161 * [Step 4]: If deleteAllGrp != true, then check if the node's group
3162 * id is same as group id received then delete the node and mark the
3163 * status found true else move to the next node of the list.
3164 * [Step 5]: Once the traversing complete,
3165 * if deleteAllGrp is true, then return successful rsp;
3166 * else if status found is true, then return successful rsp;
3167 * else return failure.
3173 * boolen of deleteAllGrp
3176 * ****************************************************************/
3177 uint8_t deleteFromStatsGrpList(Inst inst, CmLListCp *statsGrpList, uint64_t subscriptionId, uint8_t groupId, bool deleteAllGrp)
3179 bool statsFound=false;
3180 SchStatsGrp *statsGrpInfo=NULLP;
3181 CmLList *grpNode=NULLP;
3184 CM_LLIST_FIRST_NODE(statsGrpList, grpNode);
3187 statsGrpInfo = (SchStatsGrp*)grpNode->node;
3190 if(statsGrpInfo->subscriptionId== subscriptionId)
3192 if(deleteAllGrp == true)
3195 cmLListDelFrm(statsGrpList, grpNode);
3196 deleteStatsGrpNode(inst, grpNode);
3201 if(statsGrpInfo->groupId== groupId)
3203 cmLListDelFrm(statsGrpList, grpNode);
3204 deleteStatsGrpNode(inst, grpNode);
3209 CM_LLIST_FIRST_NODE(statsGrpList, grpNode);
3213 if(deleteAllGrp == true)
3219 if(statsFound == true)
3225 /*******************************************************************
3227 * @brief Delete statistics information
3231 * Function : deleteStatsInfo
3234 * Delete statistics information base on numStatsGroup
3235 * Info- If numStatsGroup = 0' indicates the Deletion procedure triggered by
3236 * 'SUBS_DELETION_REQ' wherein all the groups of this particular
3237 * Subscription has to be removed
3238 * else when numStatsGroup != 0 then this is
3239 * for SUBS_MOD_REQ's actionToBeDeleted wherein particular action(s) has
3240 * to be removed thus need to pass groupId belonging to that subscription
3241 * which has to be deleted.'
3243 * [Step-1] If numStatsGroup = 0, Deletion of all stats group belonging to
3244 * received subscription Id.
3245 * [Step-2] Else if numStatsGroup > 0, Deletion of individual stats group
3246 * from list whose information are present in stats delete request.
3247 * [Step-3] Fill the result of the stats deletion in the SCH stats delete
3251 * Subscription delete req
3252 * Subscription delete rsp
3253 * @return ROK - success
3256 * ****************************************************************/
3257 uint8_t deleteStatsInfo(Inst inst, SchStatsDeleteReq *statsDeleteReq, SchStatsDeleteRsp *schStatsDeleteRsp)
3259 uint8_t statsGrpIdx=0;
3260 CmLListCp *statsGrpList =NULLP;
3262 statsGrpList = &schCb[inst].statistics.statsGrpList;
3264 if(!statsDeleteReq->numStatsGroupToBeDeleted)
3267 if(deleteFromStatsGrpList(inst,statsGrpList, statsDeleteReq->subscriptionId, 0, true) == ROK)
3270 schStatsDeleteRsp->subsDelRsp = RSP_OK;
3271 schStatsDeleteRsp->subsDelCause = SUCCESSFUL;
3276 schStatsDeleteRsp->subsDelRsp = RSP_NOK;
3277 schStatsDeleteRsp->subsDelCause = STATS_ID_NOT_FOUND;
3282 for(statsGrpIdx=0; statsGrpIdx<statsDeleteReq->numStatsGroupToBeDeleted; statsGrpIdx++)
3285 if(deleteFromStatsGrpList(inst, statsGrpList, statsDeleteReq->subscriptionId,\
3286 statsDeleteReq->statsGrpIdToBeDelList[statsGrpIdx], false) == ROK)
3289 schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelRsp = RSP_OK;
3290 schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelCause = SUCCESSFUL;
3295 schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelRsp = RSP_NOK;
3296 schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelCause = STATS_ID_NOT_FOUND;
3299 schStatsDeleteRsp->numStatsGroupDeleted = statsDeleteReq->numStatsGroupToBeDeleted;
3304 /*******************************************************************
3306 * @brief Processes Statistics Delete Request from MAC
3310 * Function : SchProcStatsDeleteReq
3313 * This function process the statistics delete request from MAC:
3315 * @params[in] Post structure
3316 * Statistics Delete Request from MAC
3317 * @return ROK - success
3320 * ****************************************************************/
3321 uint8_t SchProcStatsDeleteReq(Pst *pst, SchStatsDeleteReq *statsDeleteReq)
3325 SchStatsDeleteRsp *schStatsDeleteRsp;
3326 Inst inst = pst->dstInst - SCH_INST_START;
3328 DU_LOG("\nINFO --> SCH : Received Statistics Delete Request from MAC");
3330 if(statsDeleteReq == NULLP)
3332 DU_LOG("\nERROR --> SCH : SchProcStatsDeleteReq(): Received Null pointer");
3336 /* Process Stats delete request and fill stats delete response simultaneously */
3337 SCH_ALLOC(schStatsDeleteRsp, sizeof(SchStatsDeleteRsp));
3338 if(schStatsDeleteRsp == NULLP)
3340 DU_LOG("\nERROR --> SCH : Failed to allocate memory in SchProcStatsDeleteReq()");
3343 schStatsDeleteRsp->subscriptionId=statsDeleteReq->subscriptionId;
3344 deleteStatsInfo(inst, statsDeleteReq, schStatsDeleteRsp);
3346 memset(&rspPst, 0, sizeof(Pst));
3347 FILL_PST_SCH_TO_MAC(rspPst, inst);
3348 rspPst.event = EVENT_STATISTICS_DELETE_RSP_TO_MAC;
3350 ret = MacMessageRouter(&rspPst, (void *)schStatsDeleteRsp);
3353 DU_LOG("\nERROR --> SCH : SchProcStatsDeleteReq(): Failed to send Statistics Response");
3355 SCH_FREE(statsDeleteReq, sizeof(SchStatsDeleteReq));
3358 } /* End of SchProcStatsDeleteReq */
3360 /*******************************************************************
3362 * @brief Fill and send statistics modification response to MAC
3366 * Function : SchSendStatsRspToMac
3368 * Functionality: Fill and send statistics
3369 * modification response to MAC
3371 * @params[in] Inst inst, SchMacRsp result
3372 * @return ROK - success
3375 * ****************************************************************/
3376 uint8_t SchSendStatsModificationRspToMac(SchStatsModificationRsp *tmpSchStatsModRsp)
3380 SchStatsModificationRsp *schStatsModificationRsp=NULLP;
3382 DU_LOG("\nINFO --> SCH : Filling statistics modification response");
3383 SCH_ALLOC(schStatsModificationRsp, sizeof(SchStatsModificationRsp));
3384 if(schStatsModificationRsp == NULLP)
3386 DU_LOG("\nERROR --> SCH : Failed to allocate memory in SchSendStatsModificationRspToMac()");
3390 memcpy(schStatsModificationRsp, tmpSchStatsModRsp, sizeof(SchStatsModificationRsp));
3391 memset(tmpSchStatsModRsp, 0, sizeof(SchStatsModificationRsp));
3393 /* Filling response post */
3394 memset(&rspPst, 0, sizeof(Pst));
3395 FILL_PST_SCH_TO_MAC(rspPst, inst);
3396 rspPst.event = EVENT_STATISTICS_MODIFY_RSP_TO_MAC;
3398 ret = MacMessageRouter(&rspPst, (void *)schStatsModificationRsp);
3401 DU_LOG("\nERROR --> SCH : SchSendStatsModificationRspToMac(): Failed to send Statistics Modification Response");
3407 /*******************************************************************
3409 * @brief Rejects all statistics modification group requested by MAC
3413 * Function : SchRejectAllStatsModification
3415 * Functionality: Add all statistics modification group received in statistics
3416 * request from MAC, to Reject-StatsModification-Group-List in statistics
3419 * @params[in] Statistics request from MAC
3420 * Cause of rejection
3421 * @return ROK - success
3424 * ****************************************************************/
3425 uint8_t SchRejectAllStatsModification(SchStatsModificationReq *statsModificationReq, CauseOfResult cause)
3428 SchStatsModificationRsp statsModificationRsp;
3430 memset(&statsModificationRsp, 0, sizeof(SchStatsModificationRsp));
3432 /* fill the subscriptionId and the rejected list in stats modification rsp */
3433 statsModificationRsp.subscriptionId = statsModificationReq->subscriptionId;
3434 for(grpIdx = 0; grpIdx < statsModificationReq->numStatsGroup; grpIdx++)
3436 statsModificationRsp.statsGrpRejectedList[grpIdx].groupId = statsModificationReq->statsGrpList[grpIdx].groupId;
3437 statsModificationRsp.statsGrpRejectedList[grpIdx].cause = cause;
3439 statsModificationRsp.numGrpRejected = statsModificationReq->numStatsGroup;
3441 return SchSendStatsModificationRspToMac(&statsModificationRsp);
3444 /****************************************************************************************
3446 * @brief Processes Statistics modification Request from MAC
3450 * Function :SchProcStatsModificationReq
3453 * This function process the statistics modification request from MAC:
3454 * [Step -1] Check the stored stats group list empty.
3455 * [Step - 1.1] If empty Send the rejected group list to MAC as a stats
3456 * modification response.
3457 * [Step - 1.2] Else go to step 2.
3458 * [Step -2] Traverse all stats group and validate each measurement types in
3460 * [Step -3] Check for any failure and if failed fill the remaining group's
3461 * info in rejected list.
3462 * [Step -4] Else Check if the received subscriptionId and groupId match the
3463 * values with the database node.
3464 * [Step -4.1] If matches then follow the below mentioned steps.
3465 * [Step -4.1.1] Stop the timer.
3466 * [Step -4.1.2] Reconfigure stats group by adding a new entry for this
3467 * statsGroup with updated configuration in database.
3468 * [Step -4.1.3] if configured successfully, store stats info into
3469 * stats mod rsp's accepted list, restart timer and go to step 4.1.4
3470 * [Step -4.1.4] Delete the old entry of this stats group..
3471 * [Step -4.2] Else fill the group related info in stats modification rsp's
3473 * [Step -5] Send the stats modification rsp to MAC
3474 * @params[in] Post structure
3475 * Statistics modification Request from MAC
3476 * @return ROK - success
3479 * *******************************************************************************************/
3480 uint8_t SchProcStatsModificationReq(Pst *pst, SchStatsModificationReq *statsModificationReq)
3483 uint8_t reqGrpIdx=0;
3484 uint64_t subscriptionId =0;
3485 bool allocFailed = false;
3486 bool statsGrpFound= false;
3487 CmLList *grpNode = NULLP;
3488 SchStatsGrp *statsGrpInfo=NULLP;
3489 SchStatsGrpInfo statsGrpToModify;
3490 SchStatsModificationRsp statsModificationRsp;
3492 inst=pst->dstInst - SCH_INST_START;
3494 DU_LOG("\nINFO --> SCH : Received Statistics modification request from MAC");
3496 if(statsModificationReq == NULLP)
3498 DU_LOG("\nERROR --> SCH : SchProcStatsModificationReq(): Received Null pointer");
3501 memset(&statsModificationRsp, 0, sizeof(SchStatsRsp));
3504 if(schCb[inst].statistics.statsGrpList.count)
3507 subscriptionId = statsModificationReq->subscriptionId;
3510 for(reqGrpIdx=0; reqGrpIdx<statsModificationReq->numStatsGroup; reqGrpIdx++)
3513 statsGrpToModify = statsModificationReq->statsGrpList[reqGrpIdx];
3514 if(allocFailed != true)
3516 CM_LLIST_FIRST_NODE(&schCb[inst].statistics.statsGrpList, grpNode);
3520 statsGrpInfo = (SchStatsGrp*)grpNode->node;
3521 if((statsGrpInfo->subscriptionId== subscriptionId) && (statsGrpInfo->groupId== statsGrpToModify.groupId))
3523 statsGrpFound= true;
3526 grpNode = grpNode->next;
3530 if(statsGrpFound== true)
3532 /* [Step - 4.1.1] */
3533 if(schChkTmr((PTR)statsGrpInfo, EVENT_STATISTICS_TMR) == true)
3535 schStopTmr(&schCb[inst], (PTR)statsGrpInfo, EVENT_STATISTICS_TMR);
3538 /* [Step - 4.1.2] */
3539 if(schAddToStatsGrpList(inst, &statsModificationRsp, subscriptionId, &statsGrpToModify) != ROK)
3541 DU_LOG("\nERROR --> SCH : SchProcStatsReq(): Failed to fill the stats group list");
3542 if(statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected-1].groupId == statsGrpToModify.groupId)
3544 /* [Step - 4.1.3] */
3545 schStartTmr(&schCb[inst], (PTR)(statsGrpInfo), EVENT_STATISTICS_TMR, statsGrpInfo->periodicity);
3546 if(statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected-1].cause == RESOURCE_UNAVAILABLE)
3555 /* [Step - 4.1.4] */
3556 deleteStatsGrpNode(inst, grpNode);
3562 statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].groupId = statsGrpToModify.groupId;
3563 statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].cause = STATS_ID_NOT_FOUND;
3564 statsModificationRsp.numGrpRejected++;
3569 statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].groupId = statsGrpToModify.groupId;
3570 statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].cause = RESOURCE_UNAVAILABLE;
3571 statsModificationRsp.numGrpRejected++;
3575 statsModificationRsp.subscriptionId = statsModificationReq->subscriptionId;
3576 SchSendStatsModificationRspToMac(&statsModificationRsp);
3581 SchRejectAllStatsModification(statsModificationReq, STATS_ID_NOT_FOUND);
3583 SCH_FREE(statsModificationReq, sizeof(SchStatsModificationReq));
3586 /**********************************************************************
3588 **********************************************************************/