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"
55 * @brief Scheduler All Apis initialized.
59 * Function : schAllApisInit
61 * This function initializes all Scheduler APIs/functionality for each kind
64 * @param[in] Inst inst, the Scheduler instance
67 void schAllApisInit(Inst inst)
69 schFcfsAllApisInit(&schCb[inst].allApis[SCH_FCFS]);
70 schSliceBasedAllApisInit(&schCb[inst].allApis[SCH_SLICE_BASED]);
74 * @brief Scheduler instance Configuration Handler.
78 * Function : SchInstCfg
80 * This function in called by SchProcGenCfgReq(). It handles the
81 * general configurations of the scheduler instance. Returns
82 * reason for success/failure of this function.
84 * @param[in] RgCfg *cfg, the Configuaration information
86 * -# LCM_REASON_NOT_APPL
87 * -# LCM_REASON_INVALID_MSGTYPE
88 * -# LCM_REASON_MEM_NOAVAIL
90 uint8_t SchInstCfg(RgCfg *cfg, Inst dInst)
92 uint16_t ret = LCM_REASON_NOT_APPL;
93 Inst inst = (dInst - SCH_INST_START);
95 DU_LOG("\nDEBUG --> SCH : Entered SchInstCfg()");
96 /* Check if Instance Configuration is done already */
97 if (schCb[inst].schInit.cfgDone == TRUE)
99 return LCM_REASON_INVALID_MSGTYPE;
101 /* Update the Pst structure for LM interface */
102 memcpy(&schCb[inst].schInit.lmPst, &cfg->s.schInstCfg.genCfg.lmPst, sizeof(Pst));
104 schCb[inst].schInit.inst = inst;
105 schCb[inst].schInit.lmPst.srcProcId = schCb[inst].schInit.procId;
106 schCb[inst].schInit.lmPst.srcEnt = schCb[inst].schInit.ent;
107 schCb[inst].schInit.lmPst.srcInst = schCb[inst].schInit.inst +
109 schCb[inst].schInit.lmPst.event = EVTNONE;
111 schCb[inst].schInit.region = cfg->s.schInstCfg.genCfg.mem.region;
112 schCb[inst].schInit.pool = cfg->s.schInstCfg.genCfg.mem.pool;
114 schCb[inst].genCfg.forceCntrlSrbBoOnPCel = cfg->s.schInstCfg.genCfg.forceCntrlSrbBoOnPCel;
115 schCb[inst].genCfg.isSCellActDeactAlgoEnable = cfg->s.schInstCfg.genCfg.isSCellActDeactAlgoEnable;
117 schCb[inst].genCfg.startCellId = cfg->s.schInstCfg.genCfg.startCellId;
119 schCb[inst].schTimersInfo.tmrRes = cfg->s.schInstCfg.genCfg.tmrRes;
120 /* Initialzie the timer queue */
121 memset(&schCb[inst].schTimersInfo.tmrTq, 0, sizeof(CmTqType) * SCH_TQ_SIZE);
122 /* Initialize the timer control point */
123 memset(&schCb[inst].schTimersInfo.tmrTqCp, 0, sizeof(CmTqCp));
124 schCb[inst].schTimersInfo.tmrTqCp.tmrLen = SCH_TQ_SIZE;
126 /* SS_MT_TMR needs to be enabled as schActvTmr needs instance information */
127 /* Timer Registration request to system services */
128 if (ODU_REG_TMR_MT(schCb[inst].schInit.ent, dInst, (int)schCb[inst].schTimersInfo.tmrRes, schActvTmr) != ROK)
130 DU_LOG("\nERROR --> SCH : SchInstCfg(): Failed to register timer.");
131 return (LCM_REASON_MEM_NOAVAIL);
134 /* Initialize statistics related configurations */
135 memset(&schCb[inst].statistics, 0, sizeof(SchStatistics));
136 cmLListInit(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList);
137 cmLListInit(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList);
139 /* Set Config done in TskInit */
140 schCb[inst].schInit.cfgDone = TRUE;
141 DU_LOG("\nINFO --> SCH : Scheduler gen config done");
143 schAllApisInit(inst);
148 * @brief Layer Manager Configuration request handler.
152 * Function : SchProcGenCfgReq
154 * This function handles the configuration
155 * request received at scheduler instance from the Layer Manager.
156 * -# Based on the cfg->hdr.elmId.elmnt value it invokes one of the
157 * functions rgHdlGenCfg() or rgHdlSapCfg().
158 * -# Invokes RgMiLrgSchCfgCfm() to send back the confirmation to the LM.
160 * @param[in] Pst *pst, the post structure
161 * @param[in] RgMngmt *cfg, the configuration parameter's structure
165 uint8_t SchProcGenCfgReq(Pst *pst, RgMngmt *cfg)
167 uint8_t ret = LCM_PRIM_OK;
168 uint16_t reason = LCM_REASON_NOT_APPL;
172 if(pst->dstInst < SCH_INST_START)
174 DU_LOG("\nERROR --> SCH : Invalid inst ID");
175 DU_LOG("\nERROR --> SCH : SchProcGenCfgReq(): "
176 "pst->dstInst=%d SCH_INST_START=%d", pst->dstInst,SCH_INST_START);
179 DU_LOG("\nINFO --> SCH : Received scheduler gen config");
180 /* Fill the post structure for sending the confirmation */
181 memset(&cfmPst, 0 , sizeof(Pst));
182 SchFillCfmPst(pst, &cfmPst, cfg);
184 memset(&cfm, 0, sizeof(RgMngmt));
191 cfm.hdr.elmId.elmnt = cfg->hdr.elmId.elmnt;
192 switch(cfg->hdr.elmId.elmnt)
195 reason = SchInstCfg(&cfg->t.cfg,pst->dstInst );
199 reason = LCM_REASON_INVALID_ELMNT;
200 DU_LOG("\nERROR --> SCH : Invalid Elmnt=%d", cfg->hdr.elmId.elmnt);
204 if (reason != LCM_REASON_NOT_APPL)
209 cfm.cfm.status = ret;
210 cfm.cfm.reason = reason;
212 SchSendCfgCfm(&cfmPst, &cfm);
213 /* SCH_FREE(pst->region, pst->pool, (Data *)cfg, sizeof(RgMngmt)); */
216 }/*-- SchProcGenCfgReq --*/
220 *@brief Returns TDD periodicity in micro seconds
224 * Function : schGetPeriodicityInMsec
226 * This API retunrs TDD periodicity in micro seconds
228 * @param[in] DlUlTxPeriodicity
229 * @return periodicityInMsec
232 uint16_t schGetPeriodicityInMsec(DlUlTxPeriodicity tddPeriod)
234 uint16_t periodicityInMsec = 0;
237 case TX_PRDCTY_MS_0P5:
239 periodicityInMsec = 500;
242 case TX_PRDCTY_MS_0P625:
244 periodicityInMsec = 625;
249 periodicityInMsec = 1000;
252 case TX_PRDCTY_MS_1P25:
254 periodicityInMsec = 1250;
259 periodicityInMsec = 2000;
262 case TX_PRDCTY_MS_2P5:
264 periodicityInMsec = 2500;
269 periodicityInMsec = 5000;
272 case TX_PRDCTY_MS_10:
274 periodicityInMsec = 10000;
279 DU_LOG("\nERROR --> SCH : Invalid DlUlTxPeriodicity:%d", tddPeriod);
283 return periodicityInMsec;
287 *@brief Fills the slotCfg from CellCfg
291 * Function : schFillSlotConfig
293 * This API Fills the slotCfg from CellCfg
295 * @param[in] SchCellCb *cell, TDDCfg tddCfg
298 void schFillSlotConfig(SchCellCb *cell, TDDCfg tddCfg)
300 uint8_t slotIdx = 0, symbolIdx = 0;
302 for(slotIdx =0 ;slotIdx < MAX_TDD_PERIODICITY_SLOTS; slotIdx++)
304 for(symbolIdx = 0; symbolIdx < MAX_SYMB_PER_SLOT; symbolIdx++)
306 /*Fill Full-DL Slots as well as DL symbols ini 1st Flexi Slo*/
307 if(slotIdx < tddCfg.nrOfDlSlots || \
308 (slotIdx == tddCfg.nrOfDlSlots && symbolIdx < tddCfg.nrOfDlSymbols))
310 cell->slotCfg[slotIdx][symbolIdx] = DL_SYMBOL;
313 /*Fill Full-FLEXI SLOT and as well as Flexi Symbols in 1 slot preceding FULL-UL slot*/
314 else if(slotIdx < (MAX_TDD_PERIODICITY_SLOTS - tddCfg.nrOfUlSlots -1) || \
315 (slotIdx == (MAX_TDD_PERIODICITY_SLOTS - tddCfg.nrOfUlSlots -1) && \
316 symbolIdx < (MAX_SYMB_PER_SLOT - tddCfg.nrOfUlSymbols)))
318 cell->slotCfg[slotIdx][symbolIdx] = FLEXI_SYMBOL;
320 /*Fill Partial UL symbols and Full-UL slot*/
323 cell->slotCfg[slotIdx][symbolIdx] = UL_SYMBOL;
330 * @brief init TDD slot config
334 * Function : schInitTddSlotCfg
336 * This API is invoked after receiving schCellCfg
338 * @param[in] schCellCb *cell
339 * @param[in] SchCellCfg *schCellCfg
342 void schInitTddSlotCfg(SchCellCb *cell, SchCellCfg *schCellCfg)
344 uint16_t periodicityInMicroSec = 0;
345 int8_t slotIdx, symbIdx;
347 periodicityInMicroSec = schGetPeriodicityInMsec(schCellCfg->tddCfg.tddPeriod);
348 cell->numSlotsInPeriodicity = (periodicityInMicroSec * pow(2, cell->numerology))/1000;
349 cell->slotFrmtBitMap = 0;
350 schFillSlotConfig(cell, schCellCfg->tddCfg);
351 for(slotIdx = cell->numSlotsInPeriodicity-1; slotIdx >= 0; slotIdx--)
354 /* If the first and last symbol are the same, the entire slot is the same type */
355 if((cell->slotCfg[slotIdx][symbIdx] == cell->slotCfg[slotIdx][MAX_SYMB_PER_SLOT-1]) &&
356 cell->slotCfg[slotIdx][symbIdx] != FLEXI_SYMBOL)
358 switch(cell->slotCfg[slotIdx][symbIdx])
362 /*BitMap to be set to 00 */
363 cell->slotFrmtBitMap = (cell->slotFrmtBitMap<<2);
368 /*BitMap to be set to 01 */
369 cell->slotFrmtBitMap = ((cell->slotFrmtBitMap<<2) | (UL_SLOT));
373 DU_LOG("\nERROR --> SCH : Invalid slot Config in schInitTddSlotCfg");
377 /* slot config is flexible. First set slotBitMap to 10 */
378 cell->slotFrmtBitMap = ((cell->slotFrmtBitMap<<2) | (FLEXI_SLOT));
384 * @brief Fill SSB start symbol
388 * Function : fillSsbStartSymb
390 * This API stores SSB start index per beam
392 * @param[in] SchCellCb *cellCb
397 void fillSsbStartSymb(SchCellCb *cellCb)
399 uint8_t cnt, scs, symbIdx, ssbStartSymbArr[SCH_MAX_SSB_BEAM];
401 scs = cellCb->cellCfg.ssbScs;
403 memset(ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
405 /* Determine value of "n" based on Section 4.1 of 3GPP TS 38.213 */
410 if(cellCb->cellCfg.ssbFrequency <= 300000)
411 cnt = 2;/* n = 0, 1 */
413 cnt = 4; /* n = 0, 1, 2, 3 */
414 for(uint8_t idx=0; idx<cnt; idx++)
416 /* start symbol determined using {2, 8} + 14n */
417 ssbStartSymbArr[symbIdx++] = 2 + MAX_SYMB_PER_SLOT*idx;
418 ssbStartSymbArr[symbIdx++] = 8 + MAX_SYMB_PER_SLOT*idx;
424 if(cellCb->cellCfg.ssbFrequency <= 300000)
427 cnt = 2; /* n = 0, 1 */
428 for(uint8_t idx=0; idx<cnt; idx++)
430 /* start symbol determined using {4, 8, 16, 20} + 28n */
431 ssbStartSymbArr[symbIdx++] = 4 + MAX_SYMB_PER_SLOT*idx;
432 ssbStartSymbArr[symbIdx++] = 8 + MAX_SYMB_PER_SLOT*idx;
433 ssbStartSymbArr[symbIdx++] = 16 + MAX_SYMB_PER_SLOT*idx;
434 ssbStartSymbArr[symbIdx++] = 20 + MAX_SYMB_PER_SLOT*idx;
439 DU_LOG("\nERROR --> SCH : SCS %d is currently not supported", scs);
441 memset(cellCb->ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
442 memcpy(cellCb->ssbStartSymbArr, ssbStartSymbArr, SCH_MAX_SSB_BEAM);
447 * @brief init cellCb based on cellCfg
451 * Function : schInitCellCb
453 * This API is invoked after receiving schCellCfg
455 * @param[in] schCellCb *cell
456 * @param[in] SchCellCfg *schCellCfg
461 uint8_t schInitCellCb(Inst inst, SchCellCfg *schCellCfg)
463 uint16_t scsInKhz = 0;
464 SchCellCb *cell= NULLP;
465 SCH_ALLOC(cell, sizeof(SchCellCb));
468 DU_LOG("\nERROR --> SCH : Memory allocation failed in schInitCellCb");
472 cell->cellId = schCellCfg->cellId;
473 cell->instIdx = inst;
474 scsInKhz = convertScsEnumValToScsVal(schCellCfg->ssbScs);
476 /*Ref : 3GPP 38.211 Table 4.2-1: SCS = (2 ^ numerology * 15kHz)*/
477 cell->numerology = log2(scsInKhz/BASE_SCS);
478 switch(cell->numerology)
480 case SCH_NUMEROLOGY_0:
482 cell->numSlots = SCH_MU0_NUM_SLOTS;
485 case SCH_NUMEROLOGY_1:
487 cell->numSlots = SCH_MU1_NUM_SLOTS;
490 case SCH_NUMEROLOGY_2:
492 cell->numSlots = SCH_MU2_NUM_SLOTS;
495 case SCH_NUMEROLOGY_3:
497 cell->numSlots = SCH_MU3_NUM_SLOTS;
500 case SCH_NUMEROLOGY_4:
502 cell->numSlots = SCH_MU4_NUM_SLOTS;
506 DU_LOG("\nERROR --> SCH : Numerology %d not supported", cell->numerology);
509 schInitTddSlotCfg(cell, schCellCfg);
512 SCH_ALLOC(cell->schDlSlotInfo, cell->numSlots * sizeof(SchDlSlotInfo*));
513 if(!cell->schDlSlotInfo)
515 DU_LOG("\nERROR --> SCH : Memory allocation failed in schInitCellCb for schDlSlotInfo");
519 SCH_ALLOC(cell->schUlSlotInfo, cell->numSlots * sizeof(SchUlSlotInfo*));
520 if(!cell->schUlSlotInfo)
522 DU_LOG("\nERROR --> SCH : Memory allocation failed in schInitCellCb for schUlSlotInfo");
526 for(uint8_t idx=0; idx<cell->numSlots; idx++)
528 SchDlSlotInfo *schDlSlotInfo;
529 SchUlSlotInfo *schUlSlotInfo;
532 SCH_ALLOC(schDlSlotInfo, sizeof(SchDlSlotInfo));
535 DU_LOG("\nERROR --> SCH : Memory allocation failed in schInitCellCb");
540 SCH_ALLOC(schUlSlotInfo, sizeof(SchUlSlotInfo));
543 DU_LOG("\nERROR --> SCH : Memory allocation failed in schInitCellCb");
547 schInitDlSlot(schDlSlotInfo);
548 schInitUlSlot(schUlSlotInfo);
550 cell->schDlSlotInfo[idx] = schDlSlotInfo;
551 cell->schUlSlotInfo[idx] = schUlSlotInfo;
554 cell->firstSsbTransmitted = false;
555 cell->firstSib1Transmitted = false;
556 fillSsbStartSymb(cell);
559 memset(cell->drxCb, 0, MAX_DRX_SIZE*sizeof(SchDrxCb));
561 schCb[inst].cells[inst] = cell;
563 DU_LOG("\nINFO --> SCH : Cell init completed for cellId:%d", cell->cellId);
569 * @brief Fill SIB1 configuration
573 * Function : fillSchSib1Cfg
575 * Fill SIB1 configuration
577 * @param[in] uint8_t bandwidth : total available bandwidth
578 * uint8_t numSlots : total slots per SFN
579 * SchSib1Cfg *sib1SchCfg : cfg to be filled
580 * uint16_t pci : physical cell Id
581 * uint8_t offsetPointA : offset
584 uint8_t fillSchSib1Cfg(uint8_t mu, uint8_t bandwidth, uint8_t numSlots,SchPdcchConfigSib1 *pdcchCfgSib1,\
585 SchSib1Cfg *sib1SchCfg, uint16_t pci, uint8_t offsetPointA, uint16_t sib1PduLen)
587 uint8_t coreset0Idx = 0;
588 uint8_t searchSpace0Idx = 0;
589 //uint8_t ssbMuxPattern = 0;
591 uint8_t numSymbols = 0;
594 //uint8_t numSearchSpacePerSlot = 0;
596 uint8_t firstSymbol = 0; /* need to calculate using formula mentioned in 38.213 */
597 uint8_t slotIndex = 0;
598 uint8_t freqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
605 pdcch = &(sib1SchCfg->sib1PdcchCfg);
606 bwp = &(sib1SchCfg->bwp);
608 coreset0Idx = pdcchCfgSib1->coresetZeroIndex;
609 searchSpace0Idx = pdcchCfgSib1->searchSpaceZeroIndex;
611 /* derive the sib1 coreset0 params from table 13-1 spec 38.213 */
612 //ssbMuxPattern = coresetIdxTable[coreset0Idx][0];
613 numRbs = coresetIdxTable[coreset0Idx][1];
614 numSymbols = coresetIdxTable[coreset0Idx][2];
615 offset = coresetIdxTable[coreset0Idx][3];
617 /* derive the search space params from table 13-11 spec 38.213 */
618 oValue = searchSpaceIdxTable[searchSpace0Idx][0];
619 //numSearchSpacePerSlot = searchSpaceIdxTable[searchSpace0Idx][1];
620 mValue = searchSpaceIdxTable[searchSpace0Idx][2];
621 firstSymbol = searchSpaceIdxTable[searchSpace0Idx][3];
623 /* calculate the n0, need to add the formulae, as of now the value is 0
624 * Need to add the even and odd values of i during configuration
625 * [(O . 2^u + i . M ) ] mod numSlotsPerSubframe
626 * assuming u = 0, i = 0, numSlotsPerSubframe = 10
627 * Also, from this configuration, coreset0 is only on even subframe */
628 slotIndex = (int)((oValue*pow(2, mu)) + floor(ssbIdx*mValue))%numSlots;
629 sib1SchCfg->n0 = slotIndex;
634 case BANDWIDTH_20MHZ:
636 bwp->freqAlloc.numPrb = TOTAL_PRB_20MHZ_MU0;
639 case BANDWIDTH_100MHZ:
641 bwp->freqAlloc.numPrb = TOTAL_PRB_100MHZ_MU1;
645 DU_LOG("\nERROR --> SCH : Bandwidth %d not supported", bandwidth);
648 bwp->freqAlloc.startPrb = 0;
649 bwp->subcarrierSpacing = 0; /* 15Khz */
650 bwp->cyclicPrefix = 0; /* normal */
652 /* fill the PDCCH PDU */
653 pdcch->coresetCfg.coreSetSize = numRbs;
654 pdcch->coresetCfg.startSymbolIndex = firstSymbol;
655 pdcch->coresetCfg.durationSymbols = numSymbols;
657 /* Fill Bitmap for PRBs in coreset */
658 fillCoresetFeqDomAllocMap(((offsetPointA-offset)/6), (numRbs/6), freqDomainResource);
659 memcpy(pdcch->coresetCfg.freqDomainResource, freqDomainResource, FREQ_DOM_RSRC_SIZE);
661 pdcch->coresetCfg.cceRegMappingType = 1; /* coreset0 is always interleaved */
662 pdcch->coresetCfg.regBundleSize = 6; /* spec-38.211 sec 7.3.2.2 */
663 pdcch->coresetCfg.interleaverSize = 2; /* spec-38.211 sec 7.3.2.2 */
664 pdcch->coresetCfg.coreSetType = 0;
665 pdcch->coresetCfg.shiftIndex = pci;
666 pdcch->coresetCfg.precoderGranularity = 0; /* sameAsRegBundle */
668 pdcch->dci.rnti = SI_RNTI;
669 pdcch->dci.scramblingId = pci;
670 pdcch->dci.scramblingRnti = 0;
671 pdcch->dci.cceIndex = 0;
672 pdcch->dci.aggregLevel = 4;
673 pdcch->dci.beamPdcchInfo.numPrgs = 1;
674 pdcch->dci.beamPdcchInfo.prgSize = 1;
675 pdcch->dci.beamPdcchInfo.digBfInterfaces = 0;
676 pdcch->dci.beamPdcchInfo.prg[0].pmIdx = 0;
677 pdcch->dci.beamPdcchInfo.prg[0].beamIdx[0] = 0;
678 pdcch->dci.txPdcchPower.beta_pdcch_1_0= 0;
679 pdcch->dci.txPdcchPower.powerControlOffsetSS = 0;
680 /* Storing pdschCfg pointer here. Required to access pdsch config while
681 fillig up pdcch pdu */
682 pdsch = &pdcch->dci.pdschCfg;
684 /* fill the PDSCH PDU */
686 pdsch->pduBitmap = 0; /* PTRS and CBG params are excluded */
687 pdsch->rnti = 0xFFFF; /* SI-RNTI */
689 pdsch->numCodewords = 1;
690 for(cwCount = 0; cwCount < pdsch->numCodewords; cwCount++)
692 pdsch->codeword[cwCount].targetCodeRate = 308;
693 pdsch->codeword[cwCount].qamModOrder = 2;
694 pdsch->codeword[cwCount].mcsIndex = DEFAULT_MCS;
695 pdsch->codeword[cwCount].mcsTable = 0; /* notqam256 */
696 pdsch->codeword[cwCount].rvIndex = 0;
697 tbSize = schCalcTbSize(sib1PduLen + TX_PAYLOAD_HDR_LEN);
698 pdsch->codeword[cwCount].tbSize = tbSize;
700 pdsch->dataScramblingId = pci;
701 pdsch->numLayers = 1;
702 pdsch->transmissionScheme = 0;
704 pdsch->dmrs.dlDmrsSymbPos = DL_DMRS_SYMBOL_POS;
705 pdsch->dmrs.dmrsConfigType = 0; /* type-1 */
706 pdsch->dmrs.dlDmrsScramblingId = pci;
707 pdsch->dmrs.scid = 0;
708 pdsch->dmrs.numDmrsCdmGrpsNoData = 1;
709 pdsch->dmrs.dmrsPorts = 0x0001;
710 pdsch->dmrs.mappingType = DMRS_MAP_TYPE_A; /* Type-A */
711 pdsch->dmrs.nrOfDmrsSymbols = NUM_DMRS_SYMBOLS;
712 pdsch->dmrs.dmrsAddPos = DMRS_ADDITIONAL_POS;
714 pdsch->pdschFreqAlloc.resourceAllocType = 1; /* RAT type-1 RIV format */
715 /* the RB numbering starts from coreset0, and PDSCH is always above SSB */
716 pdsch->pdschFreqAlloc.startPrb = offsetPointA + SCH_SSB_NUM_PRB;
717 pdsch->pdschFreqAlloc.numPrb = schCalcNumPrb(tbSize, DEFAULT_MCS, NUM_PDSCH_SYMBOL);
718 pdsch->pdschFreqAlloc.vrbPrbMapping = 0; /* non-interleaved */
719 pdsch->pdschTimeAlloc.rowIndex = 1;
720 /* This is Intel's requirement. PDSCH should start after PDSCH DRMS symbol */
721 pdsch->pdschTimeAlloc.startSymb = 3; /* spec-38.214, Table 5.1.2.1-1 */
722 pdsch->pdschTimeAlloc.numSymb = NUM_PDSCH_SYMBOL;
723 pdsch->beamPdschInfo.numPrgs = 1;
724 pdsch->beamPdschInfo.prgSize = 1;
725 pdsch->beamPdschInfo.digBfInterfaces = 0;
726 pdsch->beamPdschInfo.prg[0].pmIdx = 0;
727 pdsch->beamPdschInfo.prg[0].beamIdx[0] = 0;
728 pdsch->txPdschPower.powerControlOffset = 0;
729 pdsch->txPdschPower.powerControlOffsetSS = 0;
735 * @brief cell config from MAC to SCH.
739 * Function : macSchCellCfgReq
741 * This API is invoked by MAC to send cell config to SCH
743 * @param[in] Pst *pst
744 * @param[in] SchCellCfg *schCellCfg
749 uint8_t SchProcCellCfgReq(Pst *pst, SchCellCfg *schCellCfg)
753 SchCellCfgCfm schCellCfgCfm;
755 Inst inst = pst->dstInst - SCH_INST_START;
756 uint8_t coreset0Idx = 0;
759 uint8_t freqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
760 SchPdschConfig pdschCfg;
762 schInitCellCb(inst, schCellCfg);
763 cellCb = schCb[inst].cells[inst]; //cells is of MAX_CELLS, why inst
764 cellCb->macInst = pst->srcInst;
766 /* derive the SIB1 config parameters */
767 ret = fillSchSib1Cfg(cellCb->numerology, schCellCfg->dlBandwidth, cellCb->numSlots,
768 &(schCellCfg->pdcchCfgSib1), &(cellCb->sib1SchCfg), schCellCfg->phyCellId,
769 schCellCfg->dlCfgCommon.schFreqInfoDlSib.offsetToPointA, schCellCfg->sib1PduLen);
773 DU_LOG("\nERROR --> SCH : Failed to fill sib1 configuration");
776 memcpy(&cellCb->cellCfg, schCellCfg, sizeof(SchCellCfg));
777 schProcPagingCfg(cellCb);
779 /* Fill coreset frequencyDomainResource bitmap */
780 coreset0Idx = cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdcchCommon.commonSearchSpace.coresetId;
781 numRbs = coresetIdxTable[coreset0Idx][1];
782 offset = coresetIdxTable[coreset0Idx][3];
783 fillCoresetFeqDomAllocMap(((cellCb->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA - offset)/6), \
784 (numRbs/6), freqDomainResource);
785 memcpy(cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdcchCommon.commonSearchSpace.freqDomainRsrc,\
786 freqDomainResource,FREQ_DOM_RSRC_SIZE);
787 /* Fill K0 - K1 table for common cfg*/
788 BuildK0K1Table(cellCb, &cellCb->k0K1InfoTbl, true, cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdschCommon,
789 pdschCfg, DEFAULT_UL_ACK_LIST_COUNT, defaultUlAckTbl);
791 BuildK2InfoTable(cellCb, cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList,\
792 cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.numTimeDomRsrcAlloc, &cellCb->msg3K2InfoTbl, \
795 /*As per Spec 38.211, Sec 6.3.3.2; RootSeq Len(Lra) where Lra=839 or Lra=139,
796 *depending on the PRACH preamble format as given by Tables 6.3.3.1-1 and 6.3.3.1-2.*/
797 if(prachCfgIdxTable[cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.prachCfgIdx][0] <= 3)
799 cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.rootSeqLen = ROOT_SEQ_LEN_1;
803 cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.rootSeqLen = ROOT_SEQ_LEN_2;
805 /* Initializing global variables */
806 cellCb->actvUeBitMap = 0;
807 cellCb->boIndBitMap = 0;
809 cellCb->schHqCfg.maxDlDataHqTx = SCH_MAX_NUM_DL_HQ_TX;
810 cellCb->schHqCfg.maxMsg4HqTx = SCH_MAX_NUM_MSG4_TX;
811 cellCb->schHqCfg.maxUlDataHqTx = SCH_MAX_NUM_UL_HQ_TX;
812 cellCb->maxMsg3Tx = SCH_MAX_NUM_MSG3_TX;
814 cellCb->schAlgoType = SCH_FCFS;
815 cellCb->api = &schCb[inst].allApis[cellCb->schAlgoType]; /* For FCFS */
816 cellCb->api->SchCellCfgReq(cellCb);
818 /* Fill and send Cell config confirm */
819 memset(&rspPst, 0, sizeof(Pst));
820 FILL_PST_SCH_TO_MAC(rspPst, pst->dstInst);
821 rspPst.event = EVENT_SCH_CELL_CFG_CFM;
823 schCellCfgCfm.cellId = schCellCfg->cellId;
824 schCellCfgCfm.rsp = RSP_OK;
826 ret = MacMessageRouter(&rspPst, (void *)&schCellCfgCfm);
831 /*******************************************************************
833 * @brief Fill and send Cell delete response to MAC
837 * Function : SchSendCellDeleteRspToMac
839 * Functionality: Fill and send Cell delete response to MAC
841 * @params[in] SchCellDelete *ueDelete, Inst inst, SchMacRsp result
842 * @return ROK - success
845 * ****************************************************************/
846 uint8_t SchSendCellDeleteRspToMac(SchCellDeleteReq *ueDelete, Inst inst, SchMacRsp result)
851 SchCellDeleteRsp delRsp;
853 DU_LOG("\nINFO --> SCH : Filling Cell Delete response");
854 memset(&delRsp, 0, sizeof(SchCellDeleteRsp));
855 delRsp.cellId = ueDelete->cellId;
858 /* Filling response post */
859 memset(&rspPst, 0, sizeof(Pst));
860 FILL_PST_SCH_TO_MAC(rspPst, inst);
861 rspPst.event = EVENT_CELL_DELETE_RSP_TO_MAC;
862 ret = MacMessageRouter(&rspPst, (void *)&delRsp);
865 DU_LOG("\nERROR --> SCH : SchSendCellDeleteRspToMac(): failed to send the Cell Delete response");
871 /*******************************************************************
873 * @brief Function for cellCb Deletion
877 * Function : deleteSchCellCb
879 * Functionality: Function for cellCb Deletion
881 * @params[in] SchCellDelete *cellDelete
882 * @return ROK - success
885 * ****************************************************************/
886 void deleteSchCellCb(SchCellCb *cellCb)
888 uint8_t sliceIdx=0, slotIdx=0, plmnIdx = 0;
889 CmLListCp *list=NULL;
890 CmLList *node=NULL, *next=NULL;
891 SchPageInfo *tempNode = NULLP;
893 if(cellCb->schDlSlotInfo)
895 for(slotIdx=0; slotIdx<cellCb->numSlots; slotIdx++)
897 list = &cellCb->schDlSlotInfo[slotIdx]->prbAlloc.freePrbBlockList;
902 SCH_FREE(node->node, sizeof(FreePrbBlock));
903 deleteNodeFromLList(list, node);
906 SCH_FREE(cellCb->schDlSlotInfo[slotIdx], sizeof(SchDlSlotInfo));
908 SCH_FREE(cellCb->schDlSlotInfo, cellCb->numSlots *sizeof(SchDlSlotInfo*));
911 if(cellCb->schUlSlotInfo)
913 for(slotIdx=0; slotIdx<cellCb->numSlots; slotIdx++)
915 list = &cellCb->schUlSlotInfo[slotIdx]->prbAlloc.freePrbBlockList;
920 SCH_FREE(node->node, sizeof(FreePrbBlock));
921 deleteNodeFromLList(list, node);
924 SCH_FREE(cellCb->schUlSlotInfo[slotIdx], sizeof(SchUlSlotInfo));
926 SCH_FREE(cellCb->schUlSlotInfo, cellCb->numSlots * sizeof(SchUlSlotInfo*));
929 for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
931 if(cellCb->cellCfg.plmnInfoList[plmnIdx].snssai)
933 for(sliceIdx=0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].numSliceSupport; sliceIdx++)
935 SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].snssai[sliceIdx], sizeof(Snssai));
937 SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].numSliceSupport*sizeof(Snssai*));
941 for(uint16_t idx =0; idx<MAX_SFN; idx++)
943 list = &cellCb->pageCb.pageIndInfoRecord[idx];
950 tempNode = (SchPageInfo*)(node->node);
951 SCH_FREE(tempNode->pagePdu, tempNode->msgLen);
952 SCH_FREE(node->node, sizeof(SchPageInfo));
954 deleteNodeFromLList(list, node);
959 cellCb->api->SchCellDeleteReq(cellCb);
961 memset(cellCb, 0, sizeof(SchCellCb));
964 /*******************************************************************
966 * @brief Function for cell Delete request from MAC to SCH
970 * Function : SchProcCellDeleteReq
972 * Functionality: Function for cell Delete request from MAC to SCH
974 * @params[in] Pst *pst, SchCellDelete *cellDelete
975 * @return ROK - success
978 * ****************************************************************/
979 uint8_t SchProcCellDeleteReq(Pst *pst, SchCellDeleteReq *cellDelete)
981 uint8_t cellIdx=0, ret = RFAILED;
982 Inst inst = pst->dstInst - SCH_INST_START;
983 SchMacRsp result= RSP_OK;
987 DU_LOG("\nERROR --> SCH : SchProcCellDeleteReq(): Ue Delete request failed");
991 GET_CELL_IDX(cellDelete->cellId, cellIdx);
992 if(schCb[inst].cells[cellIdx] == NULLP)
994 DU_LOG("\nERROR --> SCH : SchProcCellDeleteReq(): cell Id[%d] is not available", cellDelete->cellId);
999 if(schCb[inst].cells[cellIdx]->cellId == cellDelete->cellId)
1001 deleteSchCellCb(schCb[inst].cells[cellIdx]);
1004 SCH_FREE(schCb[inst].cells[cellIdx], sizeof(SchCellCb));
1005 DU_LOG("\nINFO --> SCH : Sending Cell Delete response to MAC");
1009 DU_LOG("\nERROR --> SCH : SchProcCellDeleteReq(): cell Id[%d] is not available",cellDelete->cellId);
1014 if(SchSendCellDeleteRspToMac(cellDelete, inst, result)!=ROK)
1016 DU_LOG("\nERROR --> SCH : SchProcCellDeleteReq(): failed to send Cell Delete response");
1023 /*******************************************************************
1025 * @brief Processes DL RLC BO info from MAC
1029 * Function : SchProcDlRlcBoInfo
1032 * Processes DL RLC BO info from MAC
1035 * @return ROK - success
1038 * ****************************************************************/
1039 uint8_t SchProcDlRlcBoInfo(Pst *pst, DlRlcBoInfo *dlBoInfo)
1043 bool isLcIdValid = false;
1044 SchUeCb *ueCb = NULLP;
1045 SchCellCb *cell = NULLP;
1046 Inst inst = pst->dstInst-SCH_INST_START;
1048 DU_LOG("\nDEBUG --> SCH : Received RLC BO Status indication LCId [%d] BO [%d]", dlBoInfo->lcId, dlBoInfo->dataVolume);
1049 cell = schCb[inst].cells[inst];
1053 DU_LOG("\nERROR --> SCH : SchProcDlRlcBoInfo(): Cell does not exists");
1057 GET_UE_ID(dlBoInfo->crnti, ueId);
1058 ueCb = &cell->ueCb[ueId-1];
1059 if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1061 DU_LOG("INFO --> SCH : DL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1065 lcId = dlBoInfo->lcId;
1066 CHECK_LCID(lcId, isLcIdValid);
1067 if(isLcIdValid == FALSE)
1069 DU_LOG("ERROR --> SCH: LCID:%d is not valid", lcId);
1073 /*Expected when theres a case of Retransmission Failure or Resetablishment
1074 *By Zero BO, the RLC is informing that previous data can be cleared out
1075 *Thus clearing out the LC from the Lc priority list*/
1076 if(dlBoInfo->dataVolume == 0)
1078 /* TODO : Check the LC is Dedicated or default and accordingly LCList
1083 if(lcId == SRB0_LCID)
1085 cell->raCb[ueId -1].msg4recvd = true;
1086 cell->raCb[ueId -1].dlMsgPduLen = dlBoInfo->dataVolume;
1090 /* TODO : These part of changes will be corrected during DL scheduling as
1091 * per K0 - K1 -K2 */
1092 SET_ONE_BIT(ueId, cell->boIndBitMap);
1093 if(ueCb->dlInfo.dlLcCtxt[lcId].lcId == lcId)
1095 ueCb->dlInfo.dlLcCtxt[lcId].bo = dlBoInfo->dataVolume;
1099 DU_LOG("ERROR --> SCH: LCID:%d is not configured in SCH Cb",lcId);
1103 /* Adding UE Id to list of pending UEs to be scheduled */
1104 cell->api->SchDlRlcBoInfo(cell, ueId);
1108 /*******************************************************************
1110 * @brief Processes BSR indiation from MAC
1114 * Function : SchProcBsr
1117 * Processes DL BSR from MAC
1119 * @params[in] Pst pst
1120 * UlBufferStatusRptInd bsrInd
1121 * @return ROK - success
1124 * ****************************************************************/
1125 uint8_t SchProcBsr(Pst *pst, UlBufferStatusRptInd *bsrInd)
1127 Inst schInst = pst->dstInst-SCH_INST_START;
1128 SchCellCb *cellCb = NULLP;
1129 SchUeCb *ueCb = NULLP;
1132 DU_LOG("\nDEBUG --> SCH : Received BSR");
1135 DU_LOG("\nERROR --> SCH : BSR Ind is empty");
1138 cellCb = schCb[schInst].cells[schInst];
1141 DU_LOG("\nERROR --> SCH : CellCb is empty");
1144 ueCb = schGetUeCb(cellCb, bsrInd->crnti);
1148 DU_LOG("\nERROR --> SCH : UeCB is empty");
1152 if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1154 DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1158 ueCb->bsrRcvd = true;
1159 /* store dataVolume per lcg in uecb */
1160 for(lcgIdx = 0; lcgIdx < bsrInd->numLcg; lcgIdx++)
1162 ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].priority = 1; //TODO: determining LCG priority?
1163 ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].dataVol = bsrInd->dataVolInfo[lcgIdx].dataVol;
1166 /* Adding UE Id to list of pending UEs to be scheduled */
1167 cellCb->api->SchBsr(cellCb, ueCb->ueId);
1171 /*******************************************************************
1173 * @brief Processes SR UCI indication from MAC
1177 * Function : SchProcSrUciInd
1180 * Processes SR UCI indication from MAC
1182 * @params[in] Post structure
1184 * @return ROK - success
1187 * ****************************************************************/
1188 uint8_t SchProcSrUciInd(Pst *pst, SrUciIndInfo *uciInd)
1190 Inst inst = pst->dstInst-SCH_INST_START;
1193 SchCellCb *cellCb = schCb[inst].cells[inst];
1195 DU_LOG("\nDEBUG --> SCH : Received SR");
1197 ueCb = schGetUeCb(cellCb, uciInd->crnti);
1199 if(ueCb->state == SCH_UE_STATE_INACTIVE)
1201 DU_LOG("\nERROR --> SCH : Crnti %d is inactive", uciInd->crnti);
1204 if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1206 DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1209 if(uciInd->numSrBits)
1211 ueCb->srRcvd = true;
1212 /* Adding UE Id to list of pending UEs to be scheduled */
1213 cellCb->api->SchSrUciInd(cellCb, ueCb->ueId);
1218 /*******************************************************************
1220 * @brief Processes DL HARQ indication from MAC
1224 * Function : SchProcDlHarqInd
1227 * Processes DL HARQ indication from MAC
1229 * @params[in] Post structure
1230 * DL HARQ Indication
1231 * @return ROK - success
1234 * ****************************************************************/
1235 uint8_t SchProcDlHarqInd(Pst *pst, DlHarqInd *dlHarqInd)
1237 Inst inst = pst->dstInst-SCH_INST_START;
1239 SchCellCb *cellCb = schCb[inst].cells[inst];
1241 DU_LOG("\nDEBUG --> SCH : Received HARQ");
1243 ueCb = schGetUeCb(cellCb, dlHarqInd->crnti);
1245 if(ueCb->state == SCH_UE_STATE_INACTIVE)
1247 DU_LOG("\nERROR --> SCH : Crnti %d is inactive", dlHarqInd->crnti);
1251 schUpdateHarqFdbk(ueCb, dlHarqInd->numHarq, dlHarqInd->harqPayload, &dlHarqInd->slotInd);
1256 /*******************************************************************
1258 * @brief Allocates requested PRBs for DL
1262 * Function : allocatePrbDl
1265 * Allocates requested PRBs in DL
1266 * Keeps track of allocated PRB (using bitmap) and remaining PRBs
1268 * @params[in] prbAlloc table
1274 * @return ROK - success
1277 * ****************************************************************/
1278 uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
1279 uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1282 uint16_t broadcastPrbStart=0, broadcastPrbEnd=0;
1283 FreePrbBlock *freePrbBlock = NULLP;
1284 CmLList *freePrbNode = NULLP;
1285 PduTxOccsaion ssbOccasion=0, sib1Occasion=0;
1286 SchDlSlotInfo *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1287 SchPrbAlloc *prbAlloc = &schDlSlotInfo->prbAlloc;
1289 /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1290 * Search for an appropriate location in PRB grid and allocate requested resources */
1291 if(*startPrb == MAX_NUM_RB)
1293 /* Check if SSB/SIB1 is also scheduled in this slot */
1294 ssbOccasion = schCheckSsbOcc(cell, slotTime);
1295 sib1Occasion = schCheckSib1Occ(cell, slotTime);
1297 if(ssbOccasion && sib1Occasion)
1299 broadcastPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1300 broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.numPrb -1;
1302 else if(ssbOccasion)
1304 broadcastPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1305 broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB -1;
1307 else if(sib1Occasion)
1309 broadcastPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.startPrb;
1310 broadcastPrbEnd = broadcastPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.numPrb -1;
1313 /* Iterate through all free PRB blocks */
1314 freePrbNode = prbAlloc->freePrbBlockList.first;
1317 freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1319 /* If broadcast message is scheduled in this slot, then check if its PRBs belong to the current free block.
1320 * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1321 if((ssbOccasion || sib1Occasion) &&
1322 ((broadcastPrbStart >= freePrbBlock->startPrb) && (broadcastPrbStart <= freePrbBlock->endPrb)) && \
1323 ((broadcastPrbEnd >= freePrbBlock->startPrb) && (broadcastPrbEnd <= freePrbBlock->endPrb)))
1325 /* Implmentation is done such that highest-numbered free-RB is allocated first */
1326 if((freePrbBlock->endPrb > broadcastPrbEnd) && ((freePrbBlock->endPrb - broadcastPrbEnd) >= numPrb))
1328 /* If sufficient free PRBs are available above bradcast message then,
1329 * endPrb = freePrbBlock->endPrb
1330 * startPrb = endPrb - numPrb +1;
1332 *startPrb = freePrbBlock->endPrb - numPrb +1;
1335 else if((broadcastPrbStart > freePrbBlock->startPrb) && ((broadcastPrbStart - freePrbBlock->startPrb) >= numPrb))
1337 /* If free PRBs are available below broadcast message then,
1338 * endPrb = broadcastPrbStart - 1
1339 * startPrb = endPrb - numPrb +1
1341 *startPrb = broadcastPrbStart - numPrb;
1346 freePrbNode = freePrbNode->next;
1352 /* Check if requested number of blocks can be allocated from the current block */
1353 if (freePrbBlock->numFreePrb < numPrb)
1355 freePrbNode = freePrbNode->next;
1358 *startPrb = freePrbBlock->endPrb - numPrb +1;
1363 /* If no free block can be used to allocated request number of RBs */
1364 if(*startPrb == MAX_NUM_RB)
1368 /* If startPrb is known already, check if requested PRBs are available for allocation */
1371 freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1374 DU_LOG("\nERROR --> SCH: Requested DL PRB unavailable");
1379 /* Update bitmap to allocate PRBs */
1380 for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1382 if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1384 DU_LOG("\nERROR --> SCH: fillPrbBitmap() failed for symbol [%d] in DL", symbol);
1389 /* Update statistics of PRB usage if stats calculation is enabled */
1390 if(schCb[cell->instIdx].statistics.activeKpiList.dlTotPrbUseList.count)
1391 prbAlloc->numPrbAlloc += numPrb;
1393 /* Update the remaining number for free PRBs */
1394 removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1399 /*******************************************************************
1401 * @brief Allocates requested PRBs for UL
1405 * Function : allocatePrbUl
1408 * Allocates requested PRBs in UL
1409 * Keeps track of allocated PRB (using bitmap) and remaining PRBs
1411 * @params[in] prbAlloc table
1417 * @return ROK - success
1420 * ****************************************************************/
1421 uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
1422 uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1425 uint16_t prachStartPrb, prachNumPrb, prachEndPrb;
1426 bool isPrachOccasion;
1427 FreePrbBlock *freePrbBlock = NULLP;
1428 CmLList *freePrbNode = NULLP;
1429 SchPrbAlloc *prbAlloc = NULLP;
1433 DU_LOG("\nERROR --> SCH : allocatePrbUl(): Received cellCb is null");
1437 prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1438 /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1439 * Search for an appropriate location in PRB grid and allocate requested resources */
1440 if(*startPrb == MAX_NUM_RB)
1442 /* Check if PRACH is also scheduled in this slot */
1443 isPrachOccasion = schCheckPrachOcc(cell, slotTime);
1446 prachStartPrb = cell->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.msg1FreqStart;
1447 prachNumPrb = schCalcPrachNumRb(cell);
1448 prachEndPrb = prachStartPrb + prachNumPrb -1;
1451 /* Iterate through all free PRB blocks */
1452 freePrbNode = prbAlloc->freePrbBlockList.first;
1455 freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1457 /* If PRACH is scheduled in this slot, then check if its PRBs belong to the current free block.
1458 * PRBs required for PRACH cannot be allocated to any other message */
1459 if((isPrachOccasion) &&
1460 ((prachStartPrb >= freePrbBlock->startPrb) && (prachStartPrb <= freePrbBlock->endPrb)) &&
1461 ((prachEndPrb >= freePrbBlock->startPrb) && (prachEndPrb <= freePrbBlock->endPrb)))
1463 /* Implmentation is done such that highest-numbered free-RB is allocated first */
1464 if((freePrbBlock->endPrb > prachEndPrb) && ((freePrbBlock->endPrb - prachEndPrb) >= numPrb))
1466 /* If sufficient free PRBs are available above PRACH message then,
1467 * endPrb = freePrbBlock->endPrb
1468 * startPrb = endPrb - numPrb +1;
1470 *startPrb = freePrbBlock->endPrb - numPrb +1;
1473 else if((prachStartPrb > freePrbBlock->startPrb) && ((prachStartPrb - freePrbBlock->startPrb) >= numPrb))
1475 /* If free PRBs are available below PRACH message then,
1476 * endPrb = prachStartPrb - 1
1477 * startPrb = endPrb - numPrb +1
1479 *startPrb = prachStartPrb - numPrb;
1484 freePrbNode = freePrbNode->next;
1490 /* Check if requested number of PRBs can be allocated from currect block */
1491 if(freePrbBlock->numFreePrb < numPrb)
1493 freePrbNode = freePrbNode->next;
1496 *startPrb = freePrbBlock->endPrb - numPrb +1;
1501 /* If no free block can be used to allocated requested number of RBs */
1502 if(*startPrb == MAX_NUM_RB)
1507 /* If startPrb is known already, check if requested PRBs are available for allocation */
1508 freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1511 DU_LOG("\nERROR --> SCH: Requested UL PRB unavailable");
1516 /* Update bitmap to allocate PRBs */
1517 for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1519 if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1521 DU_LOG("\nERROR --> SCH: fillPrbBitmap() failed for symbol [%d] in UL", symbol);
1526 /* Update statistics of PRB usage if stats calculation is enabled */
1527 if(schCb[cell->instIdx].statistics.activeKpiList.ulTotPrbUseList.count)
1528 prbAlloc->numPrbAlloc += numPrb;
1530 /* Update the remaining number for free PRBs */
1531 removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1536 /*******************************************************************************
1538 * @brief Try to find Best Free Block with Max Num PRB
1542 * Function : searchLargestFreeBlock
1545 * Finds the FreeBlock with MaxNum of FREE PRB considering SSB/SIB1 ocassions.
1547 * @params[in] I/P > prbAlloc table (FreeBlock list)
1548 * I/P > Slot timing Info
1550 * I/P > Direction (UL/DL)
1553 * @return Max Number of Free PRB
1554 * If 0, then no Suitable Free Block
1556 * ********************************************************************************/
1558 uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_t *startPrb, Direction dir)
1560 uint16_t reservedPrbStart=0, reservedPrbEnd=0, maxFreePRB = 0;
1561 FreePrbBlock *freePrbBlock = NULLP;
1562 CmLList *freePrbNode = NULLP;
1563 SchPrbAlloc *prbAlloc = NULLP;
1564 bool checkOccasion = FALSE;
1566 *startPrb = 0; /*Initialize the StartPRB to zero*/
1568 /*Based on Direction, Reserved Messsages will differi.e.
1569 * DL >> SSB and SIB1 ocassions wheres for UL, PRACH ocassions to be checked
1570 * and reserved before allocation for dedicated DL/UL msg*/
1573 SchDlSlotInfo *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1574 PduTxOccsaion ssbOccasion=0, sib1Occasion=0;
1576 prbAlloc = &schDlSlotInfo->prbAlloc;
1578 ssbOccasion = schCheckSsbOcc(cell, slotTime);
1579 sib1Occasion = schCheckSib1Occ(cell, slotTime);
1581 checkOccasion = TRUE;
1582 if(ssbOccasion && sib1Occasion)
1584 reservedPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1585 reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB + \
1586 cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.numPrb -1;
1588 else if(ssbOccasion)
1590 reservedPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1591 reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB -1;
1593 else if(sib1Occasion)
1595 reservedPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.startPrb;
1596 reservedPrbEnd = reservedPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.numPrb -1;
1600 checkOccasion = FALSE;
1603 else if(dir == DIR_UL)
1605 prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1607 /* Check if PRACH is also scheduled in this slot */
1608 checkOccasion = schCheckPrachOcc(cell, slotTime);
1611 reservedPrbStart = cell->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.msg1FreqStart;
1612 reservedPrbEnd = reservedPrbStart + (schCalcPrachNumRb(cell)) -1;
1617 DU_LOG("\nERROR --> SCH: Invalid Direction!");
1618 return (maxFreePRB);
1621 freePrbNode = prbAlloc->freePrbBlockList.first;
1624 freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1626 /*For block with same numFreeBlocks, choose the one with HighestPRB range
1627 *Since FreeBLockList are arranged in Descending order of PRB range thus Skipping this block*/
1628 if(maxFreePRB >= freePrbBlock->numFreePrb)
1631 freePrbNode = freePrbNode->next;
1635 /* If Broadcast/Prach message is scheduled in this slot, then check if its PRBs belong to the current free block.
1636 * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1638 ((reservedPrbStart >= freePrbBlock->startPrb) && (reservedPrbStart <= freePrbBlock->endPrb)) && \
1639 ((reservedPrbEnd >= freePrbBlock->startPrb) && (reservedPrbEnd <= freePrbBlock->endPrb)))
1642 /* Implmentation is done such that highest-numbered free-RB is Checked first
1643 and freePRB in this block is greater than Max till now */
1644 if((freePrbBlock->endPrb > reservedPrbEnd) && ((freePrbBlock->endPrb - reservedPrbEnd) > maxFreePRB))
1646 /* If sufficient free PRBs are available above reserved message*/
1647 *startPrb = reservedPrbEnd + 1;
1648 maxFreePRB = (freePrbBlock->endPrb - reservedPrbEnd);
1650 /*Also check the other freeBlock (i.e. Above the reserved message) for MAX FREE PRB*/
1651 if((reservedPrbStart > freePrbBlock->startPrb) && ((reservedPrbStart - freePrbBlock->startPrb) > maxFreePRB))
1653 /* If free PRBs are available below reserved message*/
1654 *startPrb = freePrbBlock->startPrb;
1655 maxFreePRB = (reservedPrbStart - freePrbBlock->startPrb);
1660 if(maxFreePRB < freePrbBlock->numFreePrb)
1662 *startPrb = freePrbBlock->startPrb;
1663 maxFreePRB = freePrbBlock->numFreePrb;
1667 freePrbNode = freePrbNode->next;
1672 /*******************************************************************************
1674 * @brief This function is used to send Slice Cfg rsp to MAC
1678 * Function : SchSendSliceCfgRspToMac
1681 * function is used to send Slice Cfg rsp to MAC
1683 * @params[in] Pst *pst, SchSliceCfgRsp sliceCfgRsp
1687 * ********************************************************************************/
1688 void SchSendSliceCfgRspToMac(Inst inst, SchSliceCfgRsp sliceCfgRsp)
1692 memset(&rspPst, 0, sizeof(Pst));
1693 FILL_PST_SCH_TO_MAC(rspPst, inst);
1694 rspPst.event = EVENT_SLICE_CFG_RSP_TO_MAC;
1696 MacMessageRouter(&rspPst, (void *)&sliceCfgRsp);
1700 /*******************************************************************************
1702 * @brief This function is used to store or modify the slice configuration Sch DB
1706 * Function : addOrModifySliceCfgInSchDb
1709 * function is used to store or modify the slice configuration Sch DB
1711 * @params[in] SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq,
1712 * SchSliceCfgRsp cfgRsp, uint8_t count
1718 * ********************************************************************************/
1719 uint8_t addSliceCfgInSchDb(CmLListCp *sliceCfgInDb, SchRrmPolicyOfSlice *cfgReq)
1721 SchRrmPolicyOfSlice *sliceToStore;
1723 SCH_ALLOC(sliceToStore, sizeof(SchRrmPolicyOfSlice));
1726 memcpy(&sliceToStore->snssai, &cfgReq->snssai, sizeof(Snssai));
1727 memcpy(&sliceToStore->rrmPolicyRatioInfo, &cfgReq->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1728 addNodeToLList(sliceCfgInDb, sliceToStore, NULL);
1732 DU_LOG("\nERROR --> SCH : Memory allocation failed in addOrModifySliceCfgInSchDb");
1738 /*******************************************************************************
1740 * @brief fill slice configuration response
1744 * Function : fillSliceCfgRsp
1747 * fill slice configuration response
1749 * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t count
1755 * ********************************************************************************/
1756 uint8_t fillSliceCfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchCellCb *cellCb, SchSliceCfgReq *schSliceCfgReq)
1758 SchMacRsp sliceFound;
1759 uint8_t cfgIdx = 0, sliceIdx = 0, plmnIdx = 0, ret =ROK;
1760 SchSliceCfgRsp schSliceCfgRsp;
1762 for(cfgIdx = 0; cfgIdx<schSliceCfgReq->numOfConfiguredSlice; cfgIdx++)
1764 sliceFound = RSP_NOK;
1765 /* Here comparing the slice cfg request with the slice stored in cellCfg */
1766 for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
1768 for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].numSliceSupport; sliceIdx++)
1770 /* 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. */
1771 if(!memcmp(&schSliceCfgReq->listOfSlices[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].snssai[sliceIdx], sizeof(Snssai)))
1773 if(addSliceCfgInSchDb(storedSliceCfg, schSliceCfgReq->listOfSlices[cfgIdx]) == ROK)
1775 sliceFound = RSP_OK;
1776 schSliceCfgRsp.cause = SUCCESSFUL;
1780 DU_LOG("\nERROR --> SCH : Failed to store slice configuration in SchDb");
1781 schSliceCfgRsp.cause = RESOURCE_UNAVAILABLE;
1790 if((sliceFound == RSP_NOK) && (schSliceCfgRsp.cause != RESOURCE_UNAVAILABLE))
1791 schSliceCfgRsp.cause = SLICE_NOT_FOUND;
1793 schSliceCfgRsp.snssai = schSliceCfgReq->listOfSlices[cfgIdx]->snssai;
1794 schSliceCfgRsp.rsp = sliceFound;
1795 SchSendSliceCfgRspToMac(inst, schSliceCfgRsp);
1800 /*******************************************************************************
1802 * @brief This function is used to free the slice cfg and re cfg request pointer
1806 * Function : freeSchSliceCfgReq
1809 * function is used to free the slice cfg and re cfg request pointer
1811 * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1816 * ********************************************************************************/
1817 void freeSchSliceCfgReq(SchSliceCfgReq *sliceCfgReq)
1823 if(sliceCfgReq->numOfConfiguredSlice)
1825 for(cfgIdx = 0; cfgIdx<sliceCfgReq->numOfConfiguredSlice; cfgIdx++)
1827 if(sliceCfgReq->listOfSlices[cfgIdx])
1829 SCH_FREE(sliceCfgReq->listOfSlices[cfgIdx], sizeof(SchRrmPolicyOfSlice));
1832 SCH_FREE(sliceCfgReq->listOfSlices, sliceCfgReq->numOfConfiguredSlice * sizeof(SchRrmPolicyOfSlice*));
1834 SCH_FREE(sliceCfgReq, sizeof(SchSliceCfgReq));
1837 /*******************************************************************************
1839 * @brief This function is used to store the slice configuration Sch DB
1843 * Function : SchProcSliceCfgReq
1846 * function is used to store the slice configuration Sch DB
1848 * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1854 * ********************************************************************************/
1855 uint8_t SchProcSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
1858 Inst inst = pst->dstInst - SCH_INST_START;
1860 DU_LOG("\nINFO --> SCH : Received Slice Cfg request from MAC");
1863 if(schSliceCfgReq->listOfSlices)
1865 /* filling the slice configuration response of each slice */
1866 if(fillSliceCfgRsp(inst, &schCb[inst].sliceCfg, schCb[inst].cells[0], schSliceCfgReq) != ROK)
1868 DU_LOG("\nERROR --> SCH : Failed to fill the slice cfg rsp");
1871 freeSchSliceCfgReq(schSliceCfgReq);
1876 DU_LOG("\nERROR --> SCH : Received SchSliceCfgReq is NULL");
1882 /*******************************************************************************
1884 * @brief This function is used to send Slice re Cfg rsp to MAC
1888 * Function : SchSendSliceRecfgRspToMac
1891 * function is used to send Slice re Cfg rsp to MAC
1893 * @params[in] Pst *pst, SchSliceRecfgRsp schSliceRecfgRsp
1897 * ********************************************************************************/
1898 void SchSendSliceRecfgRspToMac(Inst inst, SchSliceRecfgRsp schSliceRecfgRsp)
1902 memset(&rspPst, 0, sizeof(Pst));
1903 FILL_PST_SCH_TO_MAC(rspPst, inst);
1904 rspPst.event = EVENT_SLICE_RECFG_RSP_TO_MAC;
1906 MacMessageRouter(&rspPst, (void *)&schSliceRecfgRsp);
1909 /*******************************************************************************
1911 * @brief fill slice configuration response
1915 * Function : fillSliceRecfgRsp
1917 * Functionality: fill slice reconfiguration response
1919 * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t count
1925 * ********************************************************************************/
1927 uint8_t fillSliceRecfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchSliceRecfgReq *schSliceRecfgReq)
1929 SchMacRsp sliceFound;
1931 SchRrmPolicyOfSlice *rrmPolicyOfSlices;
1932 SchSliceRecfgRsp schSliceRecfgRsp;
1934 for(cfgIdx = 0; cfgIdx<schSliceRecfgReq->numOfConfiguredSlice; cfgIdx++)
1936 sliceFound = RSP_NOK;
1937 /* Here comparing the slice recfg request with the StoredSliceCfg */
1938 CmLList *sliceCfg = storedSliceCfg->first;
1942 rrmPolicyOfSlices = (SchRrmPolicyOfSlice*)sliceCfg->node;
1944 if(rrmPolicyOfSlices && (memcmp(&schSliceRecfgReq->listOfSlices[cfgIdx]->snssai, &(rrmPolicyOfSlices->snssai), sizeof(Snssai)) == 0))
1946 memcpy(&rrmPolicyOfSlices->rrmPolicyRatioInfo, &schSliceRecfgReq->listOfSlices[cfgIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1947 sliceFound = RSP_OK;
1950 sliceCfg = sliceCfg->next;
1953 schSliceRecfgRsp.snssai = schSliceRecfgReq->listOfSlices[cfgIdx]->snssai;
1954 schSliceRecfgRsp.rsp = sliceFound;
1955 if(schSliceRecfgRsp.rsp == RSP_OK)
1956 schSliceRecfgRsp.cause = SUCCESSFUL;
1958 schSliceRecfgRsp.cause = SLICE_NOT_FOUND;
1959 SchSendSliceRecfgRspToMac(inst, schSliceRecfgRsp);
1963 /*******************************************************************************
1965 * @brief This function is used to store the slice reconfiguration Sch DB
1969 * Function : SchProcSliceRecfgReq
1972 * function is used to store the slice re configuration Sch DB
1974 * @params[in] Pst *pst, SchSliceRecfgReq *schSliceRecfgReq
1980 * ********************************************************************************/
1981 uint8_t SchProcSliceRecfgReq(Pst *pst, SchSliceRecfgReq *schSliceRecfgReq)
1984 Inst inst = pst->dstInst - SCH_INST_START;
1986 DU_LOG("\nINFO --> SCH : Received Slice ReCfg request from MAC");
1987 if(schSliceRecfgReq)
1989 if(schSliceRecfgReq->listOfSlices)
1991 /* filling the slice configuration response of each slice */
1992 if(fillSliceRecfgRsp(inst, &schCb[inst].sliceCfg, schSliceRecfgReq) != ROK)
1994 DU_LOG("\nERROR --> SCH : Failed to fill sch slice cfg response");
1997 freeSchSliceCfgReq(schSliceRecfgReq);
2002 DU_LOG("\nERROR --> SCH : Received SchSliceRecfgReq is NULL");
2008 /****************************************************************************
2010 * @brief Stores the Paging Configuration from DU APP in CellCb
2014 * Function : schProcPagingParam
2017 * Process the Paging Configuration when FirstPDCCHMonitoring for
2018 * Paging Ocassion is not present.
2020 * As per 38.304 Sec 7.1,
2021 * "When firstPDCCH-MonitoringOccasionOfPO is present, the
2022 * starting PDCCH monitoring occasion number of (i_s + 1)th PO is the
2023 * (i_s + 1)th value of the firstPDCCHMonitoringOccasionOfPO
2024 * parameter; otherwise, it is equal to i_s * S."
2025 * "S = number of actual transmitted SSBs determined according
2026 * to ssb-PositionsInBurst in SIB1"
2028 * @params[in] SchCellCb *cell
2032 *************************************************************************/
2033 void schProcPagingCfg(SchCellCb *cell)
2035 SchPcchCfg *pageCfgRcvd = NULL;
2038 pageCfgRcvd = &(cell->cellCfg.dlCfgCommon.schPcchCfg);
2040 if(pageCfgRcvd->poPresent == TRUE)
2042 /*Fetching first Pdcch Monitoring Occasion for SFN (i_s + 1)th*/
2043 for(i_sIdx = 0; i_sIdx < pageCfgRcvd->numPO; i_sIdx++)
2045 cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pageCfgRcvd->pagingOcc[i_sIdx] / MAX_SYMB_PER_SLOT ;
2046 if ((pageCfgRcvd->pagingOcc[i_sIdx] % MAX_SYMB_PER_SLOT) != 0 )
2048 cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot++;
2051 cell->pageCb.pagMonOcc[i_sIdx].frameOffset = 0;
2057 schCfgPdcchMonOccOfPO(cell);
2061 /****************************************************************************
2063 * @brief Calculate PO if not present in Configuration
2067 * Function : schCfgPdcchMonOccOfPO
2069 * Functionality: In this function, PO are calculated i_s * S because
2070 * FirstPDCCHMonitoring_ForPO is not present.
2072 * @params[in] SchCellCb *cellCb
2076 *************************************************************************/
2077 void schCfgPdcchMonOccOfPO(SchCellCb *cell)
2079 uint8_t cnt = 0, incr = 1, i_sIdx = 0, frameOffSet = 0;
2080 uint8_t nsValue = cell->cellCfg.dlCfgCommon.schPcchCfg.numPO;
2081 uint8_t totalNumSsb = countSetBits(cell->cellCfg.ssbPosInBurst[0]);
2082 SlotTimingInfo tmpTimingInfo, pdcchTime;
2084 /*Starting with First Sfn and slot*/
2085 tmpTimingInfo.sfn = 0;
2086 tmpTimingInfo.slot = 0;
2088 pdcchTime = tmpTimingInfo;
2090 while(i_sIdx < nsValue)
2092 /*Increment frame Offset if PO falls on next SFN*/
2093 if(pdcchTime.sfn != tmpTimingInfo.sfn)
2097 pdcchTime = tmpTimingInfo;
2098 schIncrSlot(&(tmpTimingInfo), incr, cell->numSlots);
2102 cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2103 cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2109 if((cnt == totalNumSsb) && (i_sIdx < MAX_PO_PER_PF))
2111 cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2112 cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2120 /****************************************************************************
2122 * @brief Storing the paging information in SCH database
2126 * Function : schAddPagingIndtoList
2128 * Functionality: Storing the paging information in SCH database
2130 * @params[in] CmLListCp *storedPageList, CmLList *pageIndInfo
2132 * @return ROK - sucess
2135 *************************************************************************/
2136 uint8_t schAddPagingIndtoList(CmLListCp *storedPageList,void * pageIndInfo)
2138 CmLList *firstNodeOfList = NULLP;
2139 CmLList *currentNodeInfo = NULLP;
2140 SchPageInfo *tempNode = NULLP, *recvdNode = NULLP;
2142 recvdNode = (SchPageInfo*) pageIndInfo;
2143 CM_LLIST_FIRST_NODE(storedPageList,firstNodeOfList);
2145 SCH_ALLOC(currentNodeInfo, sizeof(CmLList));
2146 if(!currentNodeInfo)
2148 DU_LOG("\nERROR --> SCH : schAddPagingIndtoList() : Memory allocation failed");
2152 currentNodeInfo->node = (PTR)pageIndInfo;
2153 while(firstNodeOfList)
2155 tempNode = (SchPageInfo*)(firstNodeOfList->node);
2156 if ((recvdNode->pageTxTime.slot < tempNode->pageTxTime.slot))
2158 cmLListInsCrnt(storedPageList, currentNodeInfo);
2161 else if ((recvdNode->pageTxTime.slot == tempNode->pageTxTime.slot))
2163 DU_LOG("\nERROR --> SCH : schAddPagingIndtoList() : Slot[%d] is already present in the list", recvdNode->pageTxTime.slot);
2168 CM_LLIST_NEXT_NODE(storedPageList, firstNodeOfList);
2172 if(!firstNodeOfList)
2174 cmLListAdd2Tail(storedPageList, currentNodeInfo);
2176 DU_LOG("\nDEBUG --> SCH : Paging information is stored successfully for PF:%d, Slot:%d",\
2177 recvdNode->pageTxTime.sfn, recvdNode->pageTxTime.slot);
2181 /****************************************************************************
2183 * @brief Process paging indication at SCH recevied form MAC
2187 * Function : SchProcPagingInd
2189 * Functionality: Process paging indication at SCH recevied form MAC
2191 * @params[in] Pst *pst, SchPageInd *pageInd
2195 *************************************************************************/
2196 uint8_t SchProcPagingInd(Pst *pst, SchPageInd *pageInd)
2198 uint8_t ret = RFAILED;
2199 uint16_t cellIdx = 0;
2200 Inst inst = pst->dstInst - SCH_INST_START;
2201 SchCellCb *cellCb = NULLP;
2202 SchPageInfo *pageInfo = NULLP;
2206 DU_LOG("\nDEBUG --> SCH : Received paging indication from MAC for cellId[%d]",\
2210 for(cellIdx = 0; cellIdx < MAX_NUM_CELL; cellIdx++)
2212 if((schCb[inst].cells[cellIdx]) && (schCb[inst].cells[cellIdx]->cellId == pageInd->cellId))
2214 cellCb = schCb[inst].cells[cellIdx];
2220 if(pageInd->i_s > cellCb->cellCfg.dlCfgCommon.schPcchCfg.numPO)
2222 DU_LOG("\nERROR --> SCH : SchProcPagingInd(): i_s should not be greater than number of paging occasion");
2226 SCH_ALLOC(pageInfo, sizeof(SchPageInfo));
2229 pageInfo->pf = pageInd->pf;
2230 pageInfo->i_s = pageInd->i_s;
2231 pageInfo->pageTxTime.cellId = pageInd->cellId;
2232 pageInfo->pageTxTime.sfn = (pageInd->pf + cellCb->pageCb.pagMonOcc[pageInd->i_s].frameOffset) % MAX_SFN;
2233 pageInfo->pageTxTime.slot = cellCb->pageCb.pagMonOcc[pageInd->i_s].pagingOccSlot;
2234 pageInfo->mcs = DEFAULT_MCS;
2235 pageInfo->msgLen = pageInd->pduLen;
2236 SCH_ALLOC(pageInfo->pagePdu, pageInfo->msgLen);
2237 if(!pageInfo->pagePdu)
2239 DU_LOG("\nERROR --> SCH : SchProcPagingInd(): Failed to allocate memory");
2243 memcpy(pageInfo->pagePdu, pageInd->pagePdu, pageInfo->msgLen);
2244 ret = schAddPagingIndtoList(&cellCb->pageCb.pageIndInfoRecord[pageInfo->pageTxTime.sfn], pageInfo);
2247 DU_LOG("\nERROR --> SCH : SchProcPagingInd(): Failed to store paging record");
2253 DU_LOG("\nERROR --> SCH : SchProcPagingInd(): Failed to allocate memory");
2259 DU_LOG("\nERROR --> SCH : Cell ID [%d] not found", pageInd->cellId);
2261 SCH_FREE(pageInd->pagePdu, pageInd->pduLen);
2262 SCH_FREE(pageInd, sizeof(SchPageInd));
2266 DU_LOG("\nERROR --> SCH : SchProcPagingInd(): Received null pointer");
2272 /***********************************************************
2274 * Func : SchFillCfmPst
2277 * Desc : Fills the Confirmation Post Structure cfmPst using the reqPst
2278 * and the cfm->hdr.response.
2285 * File : rg_sch_lmm.c
2287 **********************************************************/
2297 inst = (reqPst->dstInst - SCH_INST_START);
2299 cfmPst->srcEnt = ENTMAC;
2300 cfmPst->srcInst = (Inst) 1;
2301 cfmPst->srcProcId = schCb[inst].schInit.procId;
2302 cfmPst->dstEnt = ENTMAC;
2303 cfmPst->dstInst = (Inst) 0;
2304 cfmPst->dstProcId = reqPst->srcProcId;
2306 cfmPst->selector = cfm->hdr.response.selector;
2307 cfmPst->region = cfm->hdr.response.mem.region;
2308 cfmPst->pool = cfm->hdr.response.mem.pool;
2313 /*******************************************************************
2315 * @brief Processes DL CQI ind from MAC
2319 * Function : SchProcDlCqiInd
2322 * Processes DL CQI ind from MAC
2325 * @return ROK - success
2328 * ****************************************************************/
2329 uint8_t SchProcDlCqiInd(Pst *pst, SchDlCqiInd *dlCqiInd)
2332 uint16_t ueId = 0, cellIdx = 0;
2333 SchUeCb *ueCb = NULLP;
2334 SchCellCb *cell = NULLP;
2335 Inst inst = pst->dstInst-SCH_INST_START;
2339 DU_LOG("\nERROR --> SCH : SchProcDlCqiInd(): CQI Ind is empty");
2344 GET_CELL_IDX(dlCqiInd->cellId, cellIdx);
2345 cell = schCb[inst].cells[cellIdx];
2348 DU_LOG("\nERROR --> SCH : SchProcDlCqiInd(): cell Id[%d] not found", dlCqiInd->cellId);
2353 if(cell->cellId == dlCqiInd->cellId)
2355 GET_UE_ID(dlCqiInd->crnti, ueId);
2356 ueCb = &cell->ueCb[ueId-1];
2357 if(ueCb->crnti != dlCqiInd->crnti)
2359 DU_LOG("\nERROR --> SCH : SchProcDlCqiInd(): UeCb for received crnti[%d] not found", dlCqiInd->crnti);
2364 /*TODO: complete the processing of DL CQI Ind*/
2369 DU_LOG("\nERROR --> SCH : SchProcDlCqiInd(): Received cell Id[%d] from MAC is not matching with CellID[%d] in SCH Cb",\
2370 dlCqiInd->cellId, cell->cellId);
2378 /*******************************************************************
2380 * @brief Processes UL CQI ind from MAC
2384 * Function : SchProcUlCqiInd
2387 * Processes UL CQI ind from MAC
2390 * @return ROK - success
2393 * ****************************************************************/
2394 uint8_t SchProcUlCqiInd(Pst *pst, SchUlCqiInd *ulCqiInd)
2397 uint16_t ueId = 0, cellIdx = 0;
2398 SchUeCb *ueCb = NULLP;
2399 SchCellCb *cell = NULLP;
2400 Inst inst = pst->dstInst-SCH_INST_START;
2404 DU_LOG("\nERROR --> SCH : SchProcUlCqiInd(): CQI Ind is empty");
2409 GET_CELL_IDX(ulCqiInd->cellId, cellIdx);
2410 cell = schCb[inst].cells[cellIdx];
2413 DU_LOG("\nERROR --> SCH : SchProcUlCqiInd(): cell Id[%d] not found", ulCqiInd->cellId);
2418 if(cell->cellId == ulCqiInd->cellId)
2420 GET_UE_ID(ulCqiInd->crnti, ueId);
2421 ueCb = &cell->ueCb[ueId-1];
2422 if(ueCb->crnti != ulCqiInd->crnti)
2424 DU_LOG("\nERROR --> SCH : SchProcUlCqiInd(): UeCb for received crnti[%d] not found",ulCqiInd->crnti);
2429 /*TODO: complete the processing of UL CQI Ind*/
2434 DU_LOG("\nERROR --> SCH : SchProcUlCqiInd(): Received cell Id[%d] from MAC is not matching with CellId[%d] in SCH Cb",\
2435 ulCqiInd->cellId, cell->cellId);
2443 /*******************************************************************
2445 * @brief Processes PHR ind from MAC
2449 * Function : SchProcPhrInd
2452 * Processes PHR ind from MAC
2455 * @return ROK - success
2458 * ****************************************************************/
2459 uint8_t SchProcPhrInd(Pst *pst, SchPwrHeadroomInd *schPhrInd)
2462 uint16_t ueId = 0, cellIdx = 0;
2463 SchUeCb *ueCb = NULLP;
2464 SchCellCb *cell = NULLP;
2465 Inst inst = pst->dstInst-SCH_INST_START;
2469 DU_LOG("\nERROR --> SCH : SchProcPhrInd(): PHR is empty");
2474 GET_CELL_IDX(schPhrInd->cellId, cellIdx);
2475 cell = schCb[inst].cells[cellIdx];
2478 DU_LOG("\nERROR --> SCH : schProcPhrInd(): cell Id[%d] is not found", schPhrInd->cellId);
2483 if(cell->cellId == schPhrInd->cellId)
2485 GET_UE_ID(schPhrInd->crnti, ueId);
2486 ueCb = &cell->ueCb[ueId-1];
2487 if(ueCb->crnti != schPhrInd->crnti)
2489 DU_LOG("\nERROR --> SCH : SchProcPhrInd(): UeCb for received crnti[%d] not found",schPhrInd->crnti);
2494 /*TODO: complete the processing of PHR Ind*/
2499 DU_LOG("\nERROR --> SCH : SchProcPhrInd(): Mismatch between Received cell Id[%d] from MAC and CellID[%d] in SCH CB ",\
2500 schPhrInd->cellId, cell->cellId);
2508 /*******************************************************************
2510 * @brief Fill and send statistics response to MAC
2514 * Function : SchSendStatsRspToMac
2516 * Functionality: Fill and send statistics response to MAC
2518 * @params[in] Inst inst, SchMacRsp result
2519 * @return ROK - success
2522 * ****************************************************************/
2523 uint8_t SchSendStatsRspToMac(SchStatsRsp *statsRsp)
2527 SchStatsRsp *schStatsRsp;
2529 DU_LOG("\nINFO --> SCH : Filling statistics response");
2530 SCH_ALLOC(schStatsRsp, sizeof(SchStatsRsp));
2531 if(schStatsRsp == NULLP)
2533 DU_LOG("\nERROR --> SCH : Failed to allocate memory in SchSendStatsRspToMac()");
2537 memcpy(schStatsRsp, statsRsp, sizeof(SchStatsRsp));
2538 memset(statsRsp, 0, sizeof(SchStatsRsp));
2540 /* Filling response post */
2541 memset(&rspPst, 0, sizeof(Pst));
2542 FILL_PST_SCH_TO_MAC(rspPst, inst);
2543 rspPst.event = EVENT_STATISTICS_RSP_TO_MAC;
2545 ret = MacMessageRouter(&rspPst, (void *)schStatsRsp);
2548 DU_LOG("\nERROR --> SCH : SchSendStatsRspToMac(): Failed to send Statistics Response");
2554 /*******************************************************************
2556 * @brief Rejects all statistics group requested by MAC
2560 * Function : SchRejectAllStats
2562 * Functionality: Add all statistics group received in statistics
2563 * request from MAC, to Reject-Stats-Group-List in statistics
2566 * @params[in] Statistics request from MAC
2567 * Cause of rejection
2568 * @return ROK - success
2571 * ****************************************************************/
2572 uint8_t SchRejectAllStats(SchStatsReq *schStatsReq, CauseOfResult cause)
2575 SchStatsRsp schStatsRsp;
2577 memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
2579 /* Copying all stats group from stats request to stats response */
2580 schStatsRsp.subscriptionId = schStatsReq->subscriptionId;
2581 for(grpIdx = 0; grpIdx < schStatsReq->numStatsGroup; grpIdx++)
2583 schStatsRsp.statsGrpRejectedList[grpIdx].groupId = schStatsReq->statsGrpList[grpIdx].groupId;
2584 schStatsRsp.statsGrpRejectedList[grpIdx].cause = cause;
2586 schStatsRsp.numGrpRejected = schStatsReq->numStatsGroup;
2588 return SchSendStatsRspToMac(&schStatsRsp);
2591 /*******************************************************************
2593 * @brief Add active KPI pointers to KPI-Active-List
2597 * Function : schAddToKpiActiveList
2599 * Functionality: For each active statistics group for which timer
2600 * is running, add its KPI pointer to KPI-Active-List.
2602 * When it is needed to update a KPI parameters, we need not
2603 * traverse all statistics group and all KPIs within a group
2604 * to get the specific KPI pointer to be updated.
2605 * Instead, we can traverse through KPI-Active-List and update
2606 * all entries in this list.
2608 * @params[in] Pointer to the prb usage info link list
2609 * Pointer to the stats ccnfig which we need to add
2610 * @return ROK - success
2613 * ****************************************************************/
2614 uint8_t schAddToKpiActiveList(CmLListCp *kpiList, PTR kpiStatsInfo)
2616 CmLList *node = NULLP;
2618 SCH_ALLOC(node, sizeof(CmLList));
2621 node->node = kpiStatsInfo;
2622 cmLListAdd2Tail(kpiList, node);
2625 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2629 /*******************************************************************
2631 * @brief add the stats group information in statistics's statsGrpList
2635 * Function : schAddToStatsGrpList
2637 * Functionality: add the stats group information in statsGrpList
2638 * [Step 1] - Allocating the memory for the stats group in which
2639 * we need to fill into the list as a node.
2640 * [Step 2] - If allocation is successful then start traversing
2641 * each measurment cfg index of received group info.
2642 * [Step 2.1] Validate all measurements. If validation succeeds, go
2643 * to [step 2.2]. Otherwise, reject the stats group and go to step 3.
2644 * [Step 2.2] Add each KPI/measurementCfg into activeKpiList one by one.
2645 * If it fails for any KPI, reject the whole statsGrp and go to step 3..
2646 * [Step 2.3] Fill other group related information
2647 * [Step 2.4] Initialise and start timer
2648 * [Step 2.5] Once all validation and configuration is successful, add
2649 * statsGrp node into statistic's StatsGrpList.
2650 * [Step 2.5.1] If node successfully added to the list, then
2651 * fill the group related info in stats rsp's accepted list.
2652 * [Step 2.5.2] Else goto step 3
2653 * [Step 3] - If failed fill the group related info in stats rsp's
2658 * Pointer to the stats rsp
2660 * Stats Grp Info which needs to be store in the list
2661 * @return ROK - success
2664 * ****************************************************************/
2666 uint8_t schAddToStatsGrpList(Inst inst, struct schStatsRsp *statsRsp, uint64_t subscriptionId, SchStatsGrpInfo *grpInfo)
2670 uint8_t reqMeasIdx=0;
2671 CauseOfResult cause;
2672 bool measTypeInvalid=false;
2673 CmLList *statsGrpNode=NULLP;
2674 SchStatsGrp *grpInfoDb = NULLP;
2677 SCH_ALLOC(grpInfoDb, sizeof(SchStatsGrp));
2678 if(grpInfoDb == NULLP)
2680 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2681 cause = RESOURCE_UNAVAILABLE;
2687 for(reqMeasIdx = 0; reqMeasIdx < grpInfo->numStats; reqMeasIdx++)
2690 switch(grpInfo->statsList[reqMeasIdx])
2692 case SCH_DL_TOTAL_PRB_USAGE:
2694 SCH_ALLOC(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
2695 if(!grpInfoDb->kpiStats.dlTotalPrbUsage)
2697 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2698 measTypeInvalid = true;
2699 cause = RESOURCE_UNAVAILABLE;
2705 case SCH_UL_TOTAL_PRB_USAGE:
2707 SCH_ALLOC(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
2708 if(!grpInfoDb->kpiStats.ulTotalPrbUsage)
2710 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2711 measTypeInvalid = true;
2712 cause = RESOURCE_UNAVAILABLE;
2720 DU_LOG("\nERROR --> SCH : SchProcStatsReq: Invalid measurement type [%d]", \
2721 grpInfo->statsList[reqMeasIdx]);
2722 measTypeInvalid = true;
2723 cause = PARAM_INVALID;
2735 while(measTypeInvalid==false)
2737 if(grpInfoDb->kpiStats.dlTotalPrbUsage)
2740 if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, (PTR)grpInfoDb->kpiStats.dlTotalPrbUsage)!=ROK)
2742 DU_LOG("\nERROR --> E2AP : KPI addition failed in %s at %d",__func__,__LINE__);
2743 cause = RESOURCE_UNAVAILABLE;
2749 if(grpInfoDb->kpiStats.ulTotalPrbUsage)
2752 if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR)grpInfoDb->kpiStats.ulTotalPrbUsage) != ROK)
2754 DU_LOG("\nERROR --> E2AP : KPI addition failed in %s at %d",__func__,__LINE__);
2755 cause = RESOURCE_UNAVAILABLE;
2762 grpInfoDb->schInst = inst;
2763 grpInfoDb->groupId = grpInfo->groupId;
2764 grpInfoDb->periodicity = grpInfo->periodicity;
2765 grpInfoDb->subscriptionId = subscriptionId;
2768 cmInitTimers(&(grpInfoDb->periodTimer), 1);
2769 schStartTmr(&schCb[inst], (PTR)(grpInfoDb), EVENT_STATISTICS_TMR, grpInfoDb->periodicity);
2772 SCH_ALLOC(statsGrpNode, sizeof(CmLList));
2776 statsGrpNode->node = (PTR) grpInfoDb;
2777 cmLListAdd2Tail(&schCb[inst].statistics.statsGrpList, statsGrpNode);
2778 statsRsp->statsGrpAcceptedList[statsRsp->numGrpAccepted] = grpInfo->groupId;
2779 statsRsp->numGrpAccepted++;
2787 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at %d",__func__,__LINE__);
2788 cause = RESOURCE_UNAVAILABLE;
2800 deleteStatsGrpInfo(inst, grpInfoDb);
2801 SCH_FREE(grpInfoDb, sizeof(SchStatsGrp));
2803 statsRsp->statsGrpRejectedList[statsRsp->numGrpRejected].groupId = grpInfo->groupId;
2804 statsRsp->statsGrpRejectedList[statsRsp->numGrpRejected].cause = cause;
2805 statsRsp->numGrpRejected++;
2811 /*******************************************************************
2813 * @brief Processes Statistics Request from MAC
2817 * Function : SchProcStatsReq
2821 * This function process the statistics request from MAC:
2822 * [Step 1] Basic validation. If fails, all stats group in stats request are
2824 * [Step 2] If basic validations passed, traverse all stats group and
2825 * validate each measurement types in each group.
2826 * [Step 3] If any measurement type validation fails in a group, that group
2827 * is not configured and it is added to stats-group-rejected-list in
2828 * sch-stats-response message.
2829 * [Step 4] If a group passes all validation, it is added to SCH database.
2830 * And the group is added to stats-group-accepted-list in sch-stats-response message.
2831 * [Step 5] sch-stats-response is sent to du app with stats-group-rejected-list
2832 * and stats-group-accepted-list.
2834 * @params[in] Post structure
2835 * Statistics Request from MAC
2836 * @return ROK - success
2839 * ****************************************************************/
2840 uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq)
2842 bool allocFailed = false;
2843 uint8_t grpIdx = 0, reqGrpIdx = 0;
2844 SchStatsGrpInfo *grpInfo = NULLP;
2845 SchStatsRsp schStatsRsp;
2846 Inst inst = pst->dstInst - SCH_INST_START;
2848 DU_LOG("\nINFO --> SCH : Received Statistics Request from MAC");
2850 if(statsReq == NULLP)
2852 DU_LOG("\nERROR --> SCH : SchProcStatsReq(): Received Null pointer");
2857 if(schCb[inst].statistics.statsGrpList.count >= MAX_NUM_STATS_GRP)
2859 DU_LOG("\nERROR --> SCH : SchProcStatsReq: Maximum number of statistics configured. \
2860 Cannot process new request.");
2861 SchRejectAllStats(statsReq, RESOURCE_UNAVAILABLE);
2862 SCH_FREE(statsReq, sizeof(SchStatsReq));
2866 memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
2869 for(reqGrpIdx=0; reqGrpIdx<statsReq->numStatsGroup && grpIdx<MAX_NUM_STATS; reqGrpIdx++)
2871 grpInfo = &statsReq->statsGrpList[reqGrpIdx];
2873 if(allocFailed == true)
2875 schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].groupId = grpInfo->groupId;
2876 schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].cause = RESOURCE_UNAVAILABLE;
2877 schStatsRsp.numGrpRejected++;
2882 if(schAddToStatsGrpList(inst, &schStatsRsp, statsReq->subscriptionId, grpInfo) != ROK)
2884 DU_LOG("\nERROR --> SCH : SchProcStatsReq(): Failed to fill the stats group list");
2885 if((schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected-1].groupId == grpInfo->groupId &&\
2886 (schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected-1].cause == RESOURCE_UNAVAILABLE)))
2894 schStatsRsp.subscriptionId = statsReq->subscriptionId;
2895 SCH_FREE(statsReq, sizeof(SchStatsReq));
2898 SchSendStatsRspToMac(&schStatsRsp);
2903 /*******************************************************************
2905 * @brief Fill and send statistics indication to MAC
2909 * Function : SchSendStatsIndToMac
2911 * Functionality: Fill and send statistics indication to MAC
2913 * @params[in] SCH Instance
2916 * Size of value parameter
2917 * @return ROK - success
2920 * ****************************************************************/
2921 uint8_t SchSendStatsIndToMac(Inst inst, SchStatsInd *statsInd)
2927 DU_LOG("\nDEBUG --> SCH : Filling statistics indication");
2930 /* Filling post structure */
2931 memset(&pst, 0, sizeof(Pst));
2932 FILL_PST_SCH_TO_MAC(pst, inst);
2933 pst.event = EVENT_STATISTICS_IND_TO_MAC;
2935 ret = MacMessageRouter(&pst, (void *)statsInd);
2938 DU_LOG("\nERROR --> SCH : SchSendStatsIndToMac(): Failed to send Statistics Indication");
2944 * @brief Handler to process Timer expiry of DL Total PRB Usage calculation
2946 * @param[in] cb Control block depending on the type of the timer event.
2947 * @param[in] tmrEvnt Timer event to be started
2949 * @return Bool indicating whether the timer is running or not
2953 double calcDlTotalPrbUsage(TotalPrbUsage *dlTotalPrbUsage)
2955 double percentageOfTotalPrbUsed = 0;
2957 if(dlTotalPrbUsage->totalPrbAvailForTx)
2958 percentageOfTotalPrbUsed = ((100.0 * dlTotalPrbUsage->numPrbUsedForTx) / dlTotalPrbUsage->totalPrbAvailForTx);
2960 memset(dlTotalPrbUsage, 0, sizeof(TotalPrbUsage));
2962 return percentageOfTotalPrbUsed;
2966 * @brief Handler to check if the timer is running
2968 * @param[in] cb Control block depending on the type of the timer event.
2969 * @param[in] tmrEvnt Timer event to be started
2971 * @return Bool indicating whether the timer is running or not
2975 uint8_t calcUlTotalPrbUsage(TotalPrbUsage *ulTotalPrbUsage)
2977 double percentageOfTotalPrbUsed = 0;
2979 if(ulTotalPrbUsage->totalPrbAvailForTx)
2980 percentageOfTotalPrbUsed = ((100.0 * ulTotalPrbUsage->numPrbUsedForTx) / ulTotalPrbUsage->totalPrbAvailForTx);
2982 memset(ulTotalPrbUsage, 0, sizeof(TotalPrbUsage));
2984 return percentageOfTotalPrbUsed;
2988 * @brief Calculates statistics in a group and sends
2989 * statistics indication for this group
2991 * @param[in] Statistics group info
2997 uint8_t schCalcAndSendGrpStats(SchStatsGrp *grpInfo)
2999 uint8_t measStatsIdx = 0;
3000 SchStatsInd statsInd;
3002 memset(&statsInd, 0, sizeof(SchStatsInd));
3003 statsInd.subscriptionId = grpInfo->subscriptionId;
3004 statsInd.groupId = grpInfo->groupId;
3006 if(grpInfo->kpiStats.dlTotalPrbUsage)
3008 statsInd.measuredStatsList[measStatsIdx].type = SCH_DL_TOTAL_PRB_USAGE;
3009 statsInd.measuredStatsList[measStatsIdx].value = calcDlTotalPrbUsage(grpInfo->kpiStats.dlTotalPrbUsage);
3013 if(grpInfo->kpiStats.ulTotalPrbUsage)
3015 statsInd.measuredStatsList[measStatsIdx].type = SCH_UL_TOTAL_PRB_USAGE;
3016 statsInd.measuredStatsList[measStatsIdx].value = calcUlTotalPrbUsage(grpInfo->kpiStats.ulTotalPrbUsage);
3020 statsInd.numStats = measStatsIdx;
3022 return SchSendStatsIndToMac(grpInfo->schInst, &statsInd);
3025 /*******************************************************************
3027 * @brief Delete node from active kpi list
3031 * Function :deleteNodeFrmKpiList
3034 * Delete statistics group
3037 * Kpi list from which a node needs to be deleted
3038 * Nodes info which a node needs to be deleted
3040 * ****************************************************************/
3042 void deleteNodeFrmKpiList(CmLListCp *kpiList, PTR kpiNodeInfoToDel)
3044 CmLList *kpiNode=NULLP;
3046 CM_LLIST_FIRST_NODE(kpiList, kpiNode);
3049 if(kpiNode->node == kpiNodeInfoToDel)
3051 cmLListDelFrm(kpiList, kpiNode);
3052 SCH_FREE(kpiNode, sizeof(CmLList));
3055 kpiNode = kpiNode->next;
3060 /*******************************************************************
3062 * @brief Delete statistics group info
3066 * Function : deleteStatsGrpInfo
3069 * Delete statistics group info
3076 * ****************************************************************/
3077 void deleteStatsGrpInfo(Inst inst, SchStatsGrp *statsGrpInfo)
3081 if(statsGrpInfo->kpiStats.dlTotalPrbUsage)
3083 deleteNodeFrmKpiList(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, (PTR) statsGrpInfo->kpiStats.dlTotalPrbUsage);
3084 SCH_FREE(statsGrpInfo->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
3087 if(statsGrpInfo->kpiStats.ulTotalPrbUsage)
3089 deleteNodeFrmKpiList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR) statsGrpInfo->kpiStats.ulTotalPrbUsage);
3090 SCH_FREE(statsGrpInfo->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
3093 if(schChkTmr((PTR)statsGrpInfo, EVENT_STATISTICS_TMR) == true)
3095 schStopTmr(&schCb[inst], (PTR)statsGrpInfo, EVENT_STATISTICS_TMR);
3098 memset(statsGrpInfo, 0, sizeof(SchStatsGrp));
3102 /*******************************************************************
3104 * @brief Delete statistics group Node
3108 * Function : deleteStatsGrpNode
3111 * Delete statistics group node
3118 * ****************************************************************/
3119 void deleteStatsGrpNode(Inst inst, CmLList *grpNode)
3121 SchStatsGrp *statsGrpInfo=NULLP;
3125 statsGrpInfo = (SchStatsGrp*)grpNode->node;
3126 deleteStatsGrpInfo(inst, statsGrpInfo);
3127 memset(statsGrpInfo, 0, sizeof(SchStatsGrp));
3128 SCH_FREE(grpNode->node, sizeof(SchStatsGrp));
3129 SCH_FREE(grpNode, sizeof(CmLList));
3133 /******************************************************************
3135 * @brief Deletion of node from statistics group list
3139 * Function : deleteFromStatsGrpList
3141 * Functionality: Deletion of node from statistics group list
3142 * [Step 1]: Traverse each and every node of stats group list
3143 * stored in the database
3144 * [Step 2]: Check if the node's subscription id is same
3145 * as the subscription id received. If same then go to step 3
3146 * else move to the next node of the list.
3147 * [Step 3]: If deleteAllGrp == true, then delete the node and
3148 * move to the next node of the list.
3149 * [Step 4]: If deleteAllGrp != true, then check if the node's group
3150 * id is same as group id received then delete the node and mark the
3151 * status found true else move to the next node of the list.
3152 * [Step 5]: Once the traversing complete,
3153 * if deleteAllGrp is true, then return successful rsp;
3154 * else if status found is true, then return successful rsp;
3155 * else return failure.
3161 * boolen of deleteAllGrp
3164 * ****************************************************************/
3165 uint8_t deleteFromStatsGrpList(Inst inst, CmLListCp *statsGrpList, uint64_t subscriptionId, uint8_t groupId, bool deleteAllGrp)
3167 bool statsFound=false;
3168 SchStatsGrp *statsGrpInfo=NULLP;
3169 CmLList *grpNode=NULLP;
3172 CM_LLIST_FIRST_NODE(statsGrpList, grpNode);
3175 statsGrpInfo = (SchStatsGrp*)grpNode->node;
3178 if(statsGrpInfo->subscriptionId== subscriptionId)
3180 if(deleteAllGrp == true)
3183 cmLListDelFrm(statsGrpList, grpNode);
3184 deleteStatsGrpNode(inst, grpNode);
3189 if(statsGrpInfo->groupId== groupId)
3191 cmLListDelFrm(statsGrpList, grpNode);
3192 deleteStatsGrpNode(inst, grpNode);
3197 CM_LLIST_FIRST_NODE(statsGrpList, grpNode);
3201 if(deleteAllGrp == true)
3207 if(statsFound == true)
3213 /*******************************************************************
3215 * @brief Delete statistics information
3219 * Function : deleteStatsInfo
3222 * Delete statistics information base on numStatsGroup
3223 * Info- If numStatsGroup = 0' indicates the Deletion procedure triggered by
3224 * 'SUBS_DELETION_REQ' wherein all the groups of this particular
3225 * Subscription has to be removed
3226 * else when numStatsGroup != 0 then this is
3227 * for SUBS_MOD_REQ's actionToBeDeleted wherein particular action(s) has
3228 * to be removed thus need to pass groupId belonging to that subscription
3229 * which has to be deleted.'
3231 * [Step-1] If numStatsGroup = 0, Deletion of all stats group belonging to
3232 * received subscription Id.
3233 * [Step-2] Else if numStatsGroup > 0, Deletion of individual stats group
3234 * from list whose information are present in stats delete request.
3235 * [Step-3] Fill the result of the stats deletion in the SCH stats delete
3239 * Subscription delete req
3240 * Subscription delete rsp
3241 * @return ROK - success
3244 * ****************************************************************/
3245 uint8_t deleteStatsInfo(Inst inst, SchStatsDeleteReq *statsDeleteReq, SchStatsDeleteRsp *schStatsDeleteRsp)
3247 uint8_t statsGrpIdx=0;
3248 CmLListCp *statsGrpList =NULLP;
3250 statsGrpList = &schCb[inst].statistics.statsGrpList;
3252 if(!statsDeleteReq->numStatsGroupToBeDeleted)
3255 if(deleteFromStatsGrpList(inst,statsGrpList, statsDeleteReq->subscriptionId, 0, true) == ROK)
3258 schStatsDeleteRsp->subsDelRsp = RSP_OK;
3259 schStatsDeleteRsp->subsDelCause = SUCCESSFUL;
3264 schStatsDeleteRsp->subsDelRsp = RSP_NOK;
3265 schStatsDeleteRsp->subsDelCause = STATS_ID_NOT_FOUND;
3270 for(statsGrpIdx=0; statsGrpIdx<statsDeleteReq->numStatsGroupToBeDeleted; statsGrpIdx++)
3273 if(deleteFromStatsGrpList(inst, statsGrpList, statsDeleteReq->subscriptionId,\
3274 statsDeleteReq->statsGrpIdToBeDelList[statsGrpIdx], false) == ROK)
3277 schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelRsp = RSP_OK;
3278 schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelCause = SUCCESSFUL;
3283 schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelRsp = RSP_NOK;
3284 schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelCause = STATS_ID_NOT_FOUND;
3287 schStatsDeleteRsp->numStatsGroupDeleted = statsDeleteReq->numStatsGroupToBeDeleted;
3292 /*******************************************************************
3294 * @brief Processes Statistics Delete Request from MAC
3298 * Function : SchProcStatsDeleteReq
3301 * This function process the statistics delete request from MAC:
3303 * @params[in] Post structure
3304 * Statistics Delete Request from MAC
3305 * @return ROK - success
3308 * ****************************************************************/
3309 uint8_t SchProcStatsDeleteReq(Pst *pst, SchStatsDeleteReq *statsDeleteReq)
3313 SchStatsDeleteRsp *schStatsDeleteRsp;
3314 Inst inst = pst->dstInst - SCH_INST_START;
3316 DU_LOG("\nINFO --> SCH : Received Statistics Delete Request from MAC");
3318 if(statsDeleteReq == NULLP)
3320 DU_LOG("\nERROR --> SCH : SchProcStatsDeleteReq(): Received Null pointer");
3324 /* Process Stats delete request and fill stats delete response simultaneously */
3325 SCH_ALLOC(schStatsDeleteRsp, sizeof(SchStatsDeleteRsp));
3326 if(schStatsDeleteRsp == NULLP)
3328 DU_LOG("\nERROR --> SCH : Failed to allocate memory in SchProcStatsDeleteReq()");
3331 schStatsDeleteRsp->subscriptionId=statsDeleteReq->subscriptionId;
3332 deleteStatsInfo(inst, statsDeleteReq, schStatsDeleteRsp);
3334 memset(&rspPst, 0, sizeof(Pst));
3335 FILL_PST_SCH_TO_MAC(rspPst, inst);
3336 rspPst.event = EVENT_STATISTICS_DELETE_RSP_TO_MAC;
3338 ret = MacMessageRouter(&rspPst, (void *)schStatsDeleteRsp);
3341 DU_LOG("\nERROR --> SCH : SchProcStatsDeleteReq(): Failed to send Statistics Response");
3343 SCH_FREE(statsDeleteReq, sizeof(SchStatsDeleteReq));
3346 } /* End of SchProcStatsDeleteReq */
3348 /*******************************************************************
3350 * @brief Fill and send statistics modification response to MAC
3354 * Function : SchSendStatsRspToMac
3356 * Functionality: Fill and send statistics
3357 * modification response to MAC
3359 * @params[in] Inst inst, SchMacRsp result
3360 * @return ROK - success
3363 * ****************************************************************/
3364 uint8_t SchSendStatsModificationRspToMac(SchStatsModificationRsp *tmpSchStatsModRsp)
3368 SchStatsModificationRsp *schStatsModificationRsp=NULLP;
3370 DU_LOG("\nINFO --> SCH : Filling statistics modification response");
3371 SCH_ALLOC(schStatsModificationRsp, sizeof(SchStatsModificationRsp));
3372 if(schStatsModificationRsp == NULLP)
3374 DU_LOG("\nERROR --> SCH : Failed to allocate memory in SchSendStatsModificationRspToMac()");
3378 memcpy(schStatsModificationRsp, tmpSchStatsModRsp, sizeof(SchStatsModificationRsp));
3379 memset(tmpSchStatsModRsp, 0, sizeof(SchStatsModificationRsp));
3381 /* Filling response post */
3382 memset(&rspPst, 0, sizeof(Pst));
3383 FILL_PST_SCH_TO_MAC(rspPst, inst);
3384 rspPst.event = EVENT_STATISTICS_MODIFY_RSP_TO_MAC;
3386 ret = MacMessageRouter(&rspPst, (void *)schStatsModificationRsp);
3389 DU_LOG("\nERROR --> SCH : SchSendStatsModificationRspToMac(): Failed to send Statistics Modification Response");
3395 /*******************************************************************
3397 * @brief Rejects all statistics modification group requested by MAC
3401 * Function : SchRejectAllStatsModification
3403 * Functionality: Add all statistics modification group received in statistics
3404 * request from MAC, to Reject-StatsModification-Group-List in statistics
3407 * @params[in] Statistics request from MAC
3408 * Cause of rejection
3409 * @return ROK - success
3412 * ****************************************************************/
3413 uint8_t SchRejectAllStatsModification(SchStatsModificationReq *statsModificationReq, CauseOfResult cause)
3416 SchStatsModificationRsp statsModificationRsp;
3418 memset(&statsModificationRsp, 0, sizeof(SchStatsModificationRsp));
3420 /* fill the subscriptionId and the rejected list in stats modification rsp */
3421 statsModificationRsp.subscriptionId = statsModificationReq->subscriptionId;
3422 for(grpIdx = 0; grpIdx < statsModificationReq->numStatsGroup; grpIdx++)
3424 statsModificationRsp.statsGrpRejectedList[grpIdx].groupId = statsModificationReq->statsGrpList[grpIdx].groupId;
3425 statsModificationRsp.statsGrpRejectedList[grpIdx].cause = cause;
3427 statsModificationRsp.numGrpRejected = statsModificationReq->numStatsGroup;
3429 return SchSendStatsModificationRspToMac(&statsModificationRsp);
3432 /****************************************************************************************
3434 * @brief Processes Statistics modification Request from MAC
3438 * Function :SchProcStatsModificationReq
3441 * This function process the statistics modification request from MAC:
3442 * [Step -1] Check the stored stats group list empty.
3443 * [Step - 1.1] If empty Send the rejected group list to MAC as a stats
3444 * modification response.
3445 * [Step - 1.2] Else go to step 2.
3446 * [Step -2] Traverse all stats group and validate each measurement types in
3448 * [Step -3] Check for any failure and if failed fill the remaining group's
3449 * info in rejected list.
3450 * [Step -4] Else Check if the received subscriptionId and groupId match the
3451 * values with the database node.
3452 * [Step -4.1] If matches then follow the below mentioned steps.
3453 * [Step -4.1.1] Stop the timer.
3454 * [Step -4.1.2] Reconfigure stats group by adding a new entry for this
3455 * statsGroup with updated configuration in database.
3456 * [Step -4.1.3] if configured successfully, store stats info into
3457 * stats mod rsp's accepted list, restart timer and go to step 4.1.4
3458 * [Step -4.1.4] Delete the old entry of this stats group..
3459 * [Step -4.2] Else fill the group related info in stats modification rsp's
3461 * [Step -5] Send the stats modification rsp to MAC
3462 * @params[in] Post structure
3463 * Statistics modification Request from MAC
3464 * @return ROK - success
3467 * *******************************************************************************************/
3468 uint8_t SchProcStatsModificationReq(Pst *pst, SchStatsModificationReq *statsModificationReq)
3471 uint8_t reqGrpIdx=0;
3472 uint64_t subscriptionId =0;
3473 bool allocFailed = false;
3474 bool statsGrpFound= false;
3475 CmLList *grpNode = NULLP;
3476 SchStatsGrp *statsGrpInfo=NULLP;
3477 SchStatsGrpInfo statsGrpToModify;
3478 SchStatsModificationRsp statsModificationRsp;
3480 inst=pst->dstInst - SCH_INST_START;
3482 DU_LOG("\nINFO --> SCH : Received Statistics modification request from MAC");
3484 if(statsModificationReq == NULLP)
3486 DU_LOG("\nERROR --> SCH : SchProcStatsModificationReq(): Received Null pointer");
3489 memset(&statsModificationRsp, 0, sizeof(SchStatsRsp));
3492 if(schCb[inst].statistics.statsGrpList.count)
3495 subscriptionId = statsModificationReq->subscriptionId;
3498 for(reqGrpIdx=0; reqGrpIdx<statsModificationReq->numStatsGroup; reqGrpIdx++)
3501 statsGrpToModify = statsModificationReq->statsGrpList[reqGrpIdx];
3502 if(allocFailed != true)
3504 CM_LLIST_FIRST_NODE(&schCb[inst].statistics.statsGrpList, grpNode);
3508 statsGrpInfo = (SchStatsGrp*)grpNode->node;
3509 if((statsGrpInfo->subscriptionId== subscriptionId) && (statsGrpInfo->groupId== statsGrpToModify.groupId))
3511 statsGrpFound= true;
3514 grpNode = grpNode->next;
3518 if(statsGrpFound== true)
3520 /* [Step - 4.1.1] */
3521 if(schChkTmr((PTR)statsGrpInfo, EVENT_STATISTICS_TMR) == true)
3523 schStopTmr(&schCb[inst], (PTR)statsGrpInfo, EVENT_STATISTICS_TMR);
3526 /* [Step - 4.1.2] */
3527 if(schAddToStatsGrpList(inst, &statsModificationRsp, subscriptionId, &statsGrpToModify) != ROK)
3529 DU_LOG("\nERROR --> SCH : SchProcStatsReq(): Failed to fill the stats group list");
3530 if(statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected-1].groupId == statsGrpToModify.groupId)
3532 /* [Step - 4.1.3] */
3533 schStartTmr(&schCb[inst], (PTR)(statsGrpInfo), EVENT_STATISTICS_TMR, statsGrpInfo->periodicity);
3534 if(statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected-1].cause == RESOURCE_UNAVAILABLE)
3543 /* [Step - 4.1.4] */
3544 deleteStatsGrpNode(inst, grpNode);
3550 statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].groupId = statsGrpToModify.groupId;
3551 statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].cause = STATS_ID_NOT_FOUND;
3552 statsModificationRsp.numGrpRejected++;
3557 statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].groupId = statsGrpToModify.groupId;
3558 statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].cause = RESOURCE_UNAVAILABLE;
3559 statsModificationRsp.numGrpRejected++;
3563 statsModificationRsp.subscriptionId = statsModificationReq->subscriptionId;
3564 SchSendStatsModificationRspToMac(&statsModificationRsp);
3569 SchRejectAllStatsModification(statsModificationReq, STATS_ID_NOT_FOUND);
3571 SCH_FREE(statsModificationReq, sizeof(SchStatsModificationReq));
3574 /**********************************************************************
3576 **********************************************************************/