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[0].rnti = SI_RNTI;
669 pdcch->dci[0].scramblingId = pci;
670 pdcch->dci[0].scramblingRnti = 0;
671 pdcch->dci[0].cceIndex = 0;
672 pdcch->dci[0].aggregLevel = 4;
673 pdcch->dci[0].beamPdcchInfo.numPrgs = 1;
674 pdcch->dci[0].beamPdcchInfo.prgSize = 1;
675 pdcch->dci[0].beamPdcchInfo.digBfInterfaces = 0;
676 pdcch->dci[0].beamPdcchInfo.prg[0].pmIdx = 0;
677 pdcch->dci[0].beamPdcchInfo.prg[0].beamIdx[0] = 0;
678 pdcch->dci[0].txPdcchPower.beta_pdcch_1_0= 0;
679 pdcch->dci[0].txPdcchPower.powerControlOffsetSS = 0;
680 /* Storing pdschCfg pointer here. Required to access pdsch config while
681 fillig up pdcch pdu */
682 pdsch = &pdcch->dci[0].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;
890 CmLListCp *list=NULL;
891 CmLList *node=NULL, *next=NULL;
892 SchPageInfo *tempNode = NULLP;
894 if(cellCb->schDlSlotInfo)
896 for(slotIdx=0; slotIdx<cellCb->numSlots; slotIdx++)
898 list = &cellCb->schDlSlotInfo[slotIdx]->prbAlloc.freePrbBlockList;
903 SCH_FREE(node->node, sizeof(FreePrbBlock));
904 deleteNodeFromLList(list, node);
907 for(ueIdx = 0; ueIdx< MAX_NUM_UE; ueIdx++)
909 SCH_FREE(cellCb->schDlSlotInfo[slotIdx]->rarAlloc[ueIdx], sizeof(RarAlloc));
910 SCH_FREE(cellCb->schDlSlotInfo[slotIdx]->dlMsgAlloc[ueIdx], sizeof(DlMsgSchInfo));
912 SCH_FREE(cellCb->schDlSlotInfo[slotIdx]->ulGrant, sizeof(DciInfo));
913 SCH_FREE(cellCb->schDlSlotInfo[slotIdx], sizeof(SchDlSlotInfo));
915 SCH_FREE(cellCb->schDlSlotInfo, cellCb->numSlots *sizeof(SchDlSlotInfo*));
918 if(cellCb->schUlSlotInfo)
920 for(slotIdx=0; slotIdx<cellCb->numSlots; slotIdx++)
922 list = &cellCb->schUlSlotInfo[slotIdx]->prbAlloc.freePrbBlockList;
927 SCH_FREE(node->node, sizeof(FreePrbBlock));
928 deleteNodeFromLList(list, node);
931 for(ueIdx = 0; ueIdx< MAX_NUM_UE; ueIdx++)
933 SCH_FREE(cellCb->schUlSlotInfo[slotIdx]->schPuschInfo[ueIdx], sizeof(SchPuschInfo));
935 SCH_FREE(cellCb->schUlSlotInfo[slotIdx], sizeof(SchUlSlotInfo));
937 SCH_FREE(cellCb->schUlSlotInfo, cellCb->numSlots * sizeof(SchUlSlotInfo*));
940 for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
942 if(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai)
944 for(sliceIdx=0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices; sliceIdx++)
946 SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai[sliceIdx], sizeof(Snssai));
948 SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices*sizeof(Snssai*));
952 for(uint16_t idx =0; idx<MAX_SFN; idx++)
954 list = &cellCb->pageCb.pageIndInfoRecord[idx];
961 tempNode = (SchPageInfo*)(node->node);
962 SCH_FREE(tempNode->pagePdu, tempNode->msgLen);
963 SCH_FREE(node->node, sizeof(SchPageInfo));
965 deleteNodeFromLList(list, node);
970 cellCb->api->SchCellDeleteReq(cellCb);
972 memset(cellCb, 0, sizeof(SchCellCb));
975 /*******************************************************************
977 * @brief Function for cell Delete request from MAC to SCH
981 * Function : SchProcCellDeleteReq
983 * Functionality: Function for cell Delete request from MAC to SCH
985 * @params[in] Pst *pst, SchCellDelete *cellDelete
986 * @return ROK - success
989 * ****************************************************************/
990 uint8_t SchProcCellDeleteReq(Pst *pst, SchCellDeleteReq *cellDelete)
992 uint8_t cellIdx=0, ret = RFAILED;
993 Inst inst = pst->dstInst - SCH_INST_START;
994 SchMacRsp result= RSP_OK;
998 DU_LOG("\nERROR --> SCH : SchProcCellDeleteReq(): Ue Delete request failed");
1002 GET_CELL_IDX(cellDelete->cellId, cellIdx);
1003 if(schCb[inst].cells[cellIdx] == NULLP)
1005 DU_LOG("\nERROR --> SCH : SchProcCellDeleteReq(): cell Id[%d] is not available", cellDelete->cellId);
1010 if(schCb[inst].cells[cellIdx]->cellId == cellDelete->cellId)
1012 deleteSchCellCb(schCb[inst].cells[cellIdx]);
1015 SCH_FREE(schCb[inst].cells[cellIdx], sizeof(SchCellCb));
1016 DU_LOG("\nINFO --> SCH : Sending Cell Delete response to MAC");
1020 DU_LOG("\nERROR --> SCH : SchProcCellDeleteReq(): cell Id[%d] is not available",cellDelete->cellId);
1025 if(SchSendCellDeleteRspToMac(cellDelete, inst, result)!=ROK)
1027 DU_LOG("\nERROR --> SCH : SchProcCellDeleteReq(): failed to send Cell Delete response");
1034 /*******************************************************************
1036 * @brief Processes DL RLC BO info from MAC
1040 * Function : SchProcDlRlcBoInfo
1043 * Processes DL RLC BO info from MAC
1046 * @return ROK - success
1049 * ****************************************************************/
1050 uint8_t SchProcDlRlcBoInfo(Pst *pst, DlRlcBoInfo *dlBoInfo)
1054 bool isLcIdValid = false;
1055 SchUeCb *ueCb = NULLP;
1056 SchCellCb *cell = NULLP;
1057 Inst inst = pst->dstInst-SCH_INST_START;
1059 DU_LOG("\nDEBUG --> SCH : Received RLC BO Status indication LCId [%d] BO [%d]", dlBoInfo->lcId, dlBoInfo->dataVolume);
1060 cell = schCb[inst].cells[inst];
1064 DU_LOG("\nERROR --> SCH : SchProcDlRlcBoInfo(): Cell does not exists");
1068 GET_UE_ID(dlBoInfo->crnti, ueId);
1069 ueCb = &cell->ueCb[ueId-1];
1070 if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1072 DU_LOG("INFO --> SCH : DL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1076 lcId = dlBoInfo->lcId;
1077 CHECK_LCID(lcId, isLcIdValid);
1078 if(isLcIdValid == FALSE)
1080 DU_LOG("ERROR --> SCH: LCID:%d is not valid", lcId);
1084 /*Expected when theres a case of Retransmission Failure or Resetablishment
1085 *By Zero BO, the RLC is informing that previous data can be cleared out
1086 *Thus clearing out the LC from the Lc priority list*/
1087 if(dlBoInfo->dataVolume == 0)
1089 /* TODO : Check the LC is Dedicated or default and accordingly LCList
1094 if(lcId == SRB0_LCID)
1096 cell->raCb[ueId -1].msg4recvd = true;
1097 cell->raCb[ueId -1].dlMsgPduLen = dlBoInfo->dataVolume;
1101 /* TODO : These part of changes will be corrected during DL scheduling as
1102 * per K0 - K1 -K2 */
1103 SET_ONE_BIT(ueId, cell->boIndBitMap);
1104 if(ueCb->dlInfo.dlLcCtxt[lcId].lcId == lcId)
1106 ueCb->dlInfo.dlLcCtxt[lcId].bo = dlBoInfo->dataVolume;
1110 DU_LOG("ERROR --> SCH: LCID:%d is not configured in SCH Cb",lcId);
1114 /* Adding UE Id to list of pending UEs to be scheduled */
1115 cell->api->SchDlRlcBoInfo(cell, ueId);
1119 /*******************************************************************
1121 * @brief Processes BSR indiation from MAC
1125 * Function : SchProcBsr
1128 * Processes DL BSR from MAC
1130 * @params[in] Pst pst
1131 * UlBufferStatusRptInd bsrInd
1132 * @return ROK - success
1135 * ****************************************************************/
1136 uint8_t SchProcBsr(Pst *pst, UlBufferStatusRptInd *bsrInd)
1138 Inst schInst = pst->dstInst-SCH_INST_START;
1139 SchCellCb *cellCb = NULLP;
1140 SchUeCb *ueCb = NULLP;
1143 DU_LOG("\nDEBUG --> SCH : Received BSR");
1146 DU_LOG("\nERROR --> SCH : BSR Ind is empty");
1149 cellCb = schCb[schInst].cells[schInst];
1152 DU_LOG("\nERROR --> SCH : CellCb is empty");
1155 ueCb = schGetUeCb(cellCb, bsrInd->crnti);
1159 DU_LOG("\nERROR --> SCH : UeCB is empty");
1163 if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1165 DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1169 ueCb->bsrRcvd = true;
1170 /* store dataVolume per lcg in uecb */
1171 for(lcgIdx = 0; lcgIdx < bsrInd->numLcg; lcgIdx++)
1173 ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].priority = 1; //TODO: determining LCG priority?
1174 ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].dataVol = bsrInd->dataVolInfo[lcgIdx].dataVol;
1177 /* Adding UE Id to list of pending UEs to be scheduled */
1178 cellCb->api->SchBsr(cellCb, ueCb->ueId);
1182 /*******************************************************************
1184 * @brief Processes SR UCI indication from MAC
1188 * Function : SchProcSrUciInd
1191 * Processes SR UCI indication from MAC
1193 * @params[in] Post structure
1195 * @return ROK - success
1198 * ****************************************************************/
1199 uint8_t SchProcSrUciInd(Pst *pst, SrUciIndInfo *uciInd)
1201 Inst inst = pst->dstInst-SCH_INST_START;
1204 SchCellCb *cellCb = schCb[inst].cells[inst];
1206 DU_LOG("\nDEBUG --> SCH : Received SR");
1208 ueCb = schGetUeCb(cellCb, uciInd->crnti);
1210 if(ueCb->state == SCH_UE_STATE_INACTIVE)
1212 DU_LOG("\nERROR --> SCH : Crnti %d is inactive", uciInd->crnti);
1215 if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1217 DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1220 if(uciInd->numSrBits)
1222 ueCb->srRcvd = true;
1223 /* Adding UE Id to list of pending UEs to be scheduled */
1224 cellCb->api->SchSrUciInd(cellCb, ueCb->ueId);
1229 /*******************************************************************
1231 * @brief Processes DL HARQ indication from MAC
1235 * Function : SchProcDlHarqInd
1238 * Processes DL HARQ indication from MAC
1240 * @params[in] Post structure
1241 * DL HARQ Indication
1242 * @return ROK - success
1245 * ****************************************************************/
1246 uint8_t SchProcDlHarqInd(Pst *pst, DlHarqInd *dlHarqInd)
1248 Inst inst = pst->dstInst-SCH_INST_START;
1250 SchCellCb *cellCb = schCb[inst].cells[inst];
1252 DU_LOG("\nDEBUG --> SCH : Received HARQ");
1254 ueCb = schGetUeCb(cellCb, dlHarqInd->crnti);
1256 if(ueCb->state == SCH_UE_STATE_INACTIVE)
1258 DU_LOG("\nERROR --> SCH : Crnti %d is inactive", dlHarqInd->crnti);
1262 schUpdateHarqFdbk(ueCb, dlHarqInd->numHarq, dlHarqInd->harqPayload, &dlHarqInd->slotInd);
1267 /*******************************************************************
1269 * @brief Allocates requested PRBs for DL
1273 * Function : allocatePrbDl
1276 * Allocates requested PRBs in DL
1277 * Keeps track of allocated PRB (using bitmap) and remaining PRBs
1279 * @params[in] prbAlloc table
1285 * @return ROK - success
1288 * ****************************************************************/
1289 uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
1290 uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1293 uint16_t broadcastPrbStart=0, broadcastPrbEnd=0;
1294 FreePrbBlock *freePrbBlock = NULLP;
1295 CmLList *freePrbNode = NULLP;
1296 PduTxOccsaion ssbOccasion=0, sib1Occasion=0;
1297 SchDlSlotInfo *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1298 SchPrbAlloc *prbAlloc = &schDlSlotInfo->prbAlloc;
1300 /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1301 * Search for an appropriate location in PRB grid and allocate requested resources */
1302 if(*startPrb == MAX_NUM_RB)
1304 /* Check if SSB/SIB1 is also scheduled in this slot */
1305 ssbOccasion = schCheckSsbOcc(cell, slotTime);
1306 sib1Occasion = schCheckSib1Occ(cell, slotTime);
1308 if(ssbOccasion && sib1Occasion)
1310 broadcastPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1311 broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1313 else if(ssbOccasion)
1315 broadcastPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1316 broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB -1;
1318 else if(sib1Occasion)
1320 broadcastPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.startPrb;
1321 broadcastPrbEnd = broadcastPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1324 /* Iterate through all free PRB blocks */
1325 freePrbNode = prbAlloc->freePrbBlockList.first;
1328 freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1330 /* If broadcast message is scheduled in this slot, then check if its PRBs belong to the current free block.
1331 * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1332 if((ssbOccasion || sib1Occasion) &&
1333 ((broadcastPrbStart >= freePrbBlock->startPrb) && (broadcastPrbStart <= freePrbBlock->endPrb)) && \
1334 ((broadcastPrbEnd >= freePrbBlock->startPrb) && (broadcastPrbEnd <= freePrbBlock->endPrb)))
1336 /* Implmentation is done such that highest-numbered free-RB is allocated first */
1337 if((freePrbBlock->endPrb > broadcastPrbEnd) && ((freePrbBlock->endPrb - broadcastPrbEnd) >= numPrb))
1339 /* If sufficient free PRBs are available above bradcast message then,
1340 * endPrb = freePrbBlock->endPrb
1341 * startPrb = endPrb - numPrb +1;
1343 *startPrb = freePrbBlock->endPrb - numPrb +1;
1346 else if((broadcastPrbStart > freePrbBlock->startPrb) && ((broadcastPrbStart - freePrbBlock->startPrb) >= numPrb))
1348 /* If free PRBs are available below broadcast message then,
1349 * endPrb = broadcastPrbStart - 1
1350 * startPrb = endPrb - numPrb +1
1352 *startPrb = broadcastPrbStart - numPrb;
1357 freePrbNode = freePrbNode->next;
1363 /* Check if requested number of blocks can be allocated from the current block */
1364 if (freePrbBlock->numFreePrb < numPrb)
1366 freePrbNode = freePrbNode->next;
1369 *startPrb = freePrbBlock->endPrb - numPrb +1;
1374 /* If no free block can be used to allocated request number of RBs */
1375 if(*startPrb == MAX_NUM_RB)
1379 /* If startPrb is known already, check if requested PRBs are available for allocation */
1382 freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1385 DU_LOG("\nERROR --> SCH: Requested DL PRB unavailable");
1390 /* Update bitmap to allocate PRBs */
1391 for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1393 if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1395 DU_LOG("\nERROR --> SCH: fillPrbBitmap() failed for symbol [%d] in DL", symbol);
1400 /* Update statistics of PRB usage if stats calculation is enabled */
1401 if(schCb[cell->instIdx].statistics.activeKpiList.dlTotPrbUseList.count)
1402 prbAlloc->numPrbAlloc += numPrb;
1404 /* Update the remaining number for free PRBs */
1405 removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1410 /*******************************************************************
1412 * @brief Allocates requested PRBs for UL
1416 * Function : allocatePrbUl
1419 * Allocates requested PRBs in UL
1420 * Keeps track of allocated PRB (using bitmap) and remaining PRBs
1422 * @params[in] prbAlloc table
1428 * @return ROK - success
1431 * ****************************************************************/
1432 uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
1433 uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1436 uint16_t prachStartPrb, prachNumPrb, prachEndPrb;
1437 bool isPrachOccasion;
1438 FreePrbBlock *freePrbBlock = NULLP;
1439 CmLList *freePrbNode = NULLP;
1440 SchPrbAlloc *prbAlloc = NULLP;
1444 DU_LOG("\nERROR --> SCH : allocatePrbUl(): Received cellCb is null");
1448 prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1449 /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1450 * Search for an appropriate location in PRB grid and allocate requested resources */
1451 if(*startPrb == MAX_NUM_RB)
1453 /* Check if PRACH is also scheduled in this slot */
1454 isPrachOccasion = schCheckPrachOcc(cell, slotTime);
1457 prachStartPrb = cell->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.msg1FreqStart;
1458 prachNumPrb = schCalcPrachNumRb(cell);
1459 prachEndPrb = prachStartPrb + prachNumPrb -1;
1462 /* Iterate through all free PRB blocks */
1463 freePrbNode = prbAlloc->freePrbBlockList.first;
1466 freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1468 /* If PRACH is scheduled in this slot, then check if its PRBs belong to the current free block.
1469 * PRBs required for PRACH cannot be allocated to any other message */
1470 if((isPrachOccasion) &&
1471 ((prachStartPrb >= freePrbBlock->startPrb) && (prachStartPrb <= freePrbBlock->endPrb)) &&
1472 ((prachEndPrb >= freePrbBlock->startPrb) && (prachEndPrb <= freePrbBlock->endPrb)))
1474 /* Implmentation is done such that highest-numbered free-RB is allocated first */
1475 if((freePrbBlock->endPrb > prachEndPrb) && ((freePrbBlock->endPrb - prachEndPrb) >= numPrb))
1477 /* If sufficient free PRBs are available above PRACH message then,
1478 * endPrb = freePrbBlock->endPrb
1479 * startPrb = endPrb - numPrb +1;
1481 *startPrb = freePrbBlock->endPrb - numPrb +1;
1484 else if((prachStartPrb > freePrbBlock->startPrb) && ((prachStartPrb - freePrbBlock->startPrb) >= numPrb))
1486 /* If free PRBs are available below PRACH message then,
1487 * endPrb = prachStartPrb - 1
1488 * startPrb = endPrb - numPrb +1
1490 *startPrb = prachStartPrb - numPrb;
1495 freePrbNode = freePrbNode->next;
1501 /* Check if requested number of PRBs can be allocated from currect block */
1502 if(freePrbBlock->numFreePrb < numPrb)
1504 freePrbNode = freePrbNode->next;
1507 *startPrb = freePrbBlock->endPrb - numPrb +1;
1512 /* If no free block can be used to allocated requested number of RBs */
1513 if(*startPrb == MAX_NUM_RB)
1518 /* If startPrb is known already, check if requested PRBs are available for allocation */
1519 freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1522 DU_LOG("\nERROR --> SCH: Requested UL PRB unavailable");
1527 /* Update bitmap to allocate PRBs */
1528 for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1530 if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1532 DU_LOG("\nERROR --> SCH: fillPrbBitmap() failed for symbol [%d] in UL", symbol);
1537 /* Update statistics of PRB usage if stats calculation is enabled */
1538 if(schCb[cell->instIdx].statistics.activeKpiList.ulTotPrbUseList.count)
1539 prbAlloc->numPrbAlloc += numPrb;
1541 /* Update the remaining number for free PRBs */
1542 removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1547 /*******************************************************************************
1549 * @brief Try to find Best Free Block with Max Num PRB
1553 * Function : searchLargestFreeBlock
1556 * Finds the FreeBlock with MaxNum of FREE PRB considering SSB/SIB1 ocassions.
1558 * @params[in] I/P > prbAlloc table (FreeBlock list)
1559 * I/P > Slot timing Info
1561 * I/P > Direction (UL/DL)
1564 * @return Max Number of Free PRB
1565 * If 0, then no Suitable Free Block
1567 * ********************************************************************************/
1569 uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_t *startPrb, Direction dir)
1571 uint16_t reservedPrbStart=0, reservedPrbEnd=0, maxFreePRB = 0;
1572 FreePrbBlock *freePrbBlock = NULLP;
1573 CmLList *freePrbNode = NULLP;
1574 SchPrbAlloc *prbAlloc = NULLP;
1575 bool checkOccasion = FALSE;
1577 *startPrb = 0; /*Initialize the StartPRB to zero*/
1579 /*Based on Direction, Reserved Messsages will differi.e.
1580 * DL >> SSB and SIB1 ocassions wheres for UL, PRACH ocassions to be checked
1581 * and reserved before allocation for dedicated DL/UL msg*/
1584 SchDlSlotInfo *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1585 PduTxOccsaion ssbOccasion=0, sib1Occasion=0;
1587 prbAlloc = &schDlSlotInfo->prbAlloc;
1589 ssbOccasion = schCheckSsbOcc(cell, slotTime);
1590 sib1Occasion = schCheckSib1Occ(cell, slotTime);
1592 checkOccasion = TRUE;
1593 if(ssbOccasion && sib1Occasion)
1595 reservedPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1596 reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB + \
1597 cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1599 else if(ssbOccasion)
1601 reservedPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1602 reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB -1;
1604 else if(sib1Occasion)
1606 reservedPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.startPrb;
1607 reservedPrbEnd = reservedPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1611 checkOccasion = FALSE;
1614 else if(dir == DIR_UL)
1616 prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1618 /* Check if PRACH is also scheduled in this slot */
1619 checkOccasion = schCheckPrachOcc(cell, slotTime);
1622 reservedPrbStart = cell->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.msg1FreqStart;
1623 reservedPrbEnd = reservedPrbStart + (schCalcPrachNumRb(cell)) -1;
1628 DU_LOG("\nERROR --> SCH: Invalid Direction!");
1629 return (maxFreePRB);
1632 freePrbNode = prbAlloc->freePrbBlockList.first;
1635 freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1637 /*For block with same numFreeBlocks, choose the one with HighestPRB range
1638 *Since FreeBLockList are arranged in Descending order of PRB range thus Skipping this block*/
1639 if(maxFreePRB >= freePrbBlock->numFreePrb)
1642 freePrbNode = freePrbNode->next;
1646 /* If Broadcast/Prach message is scheduled in this slot, then check if its PRBs belong to the current free block.
1647 * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1649 ((reservedPrbStart >= freePrbBlock->startPrb) && (reservedPrbStart <= freePrbBlock->endPrb)) && \
1650 ((reservedPrbEnd >= freePrbBlock->startPrb) && (reservedPrbEnd <= freePrbBlock->endPrb)))
1653 /* Implmentation is done such that highest-numbered free-RB is Checked first
1654 and freePRB in this block is greater than Max till now */
1655 if((freePrbBlock->endPrb > reservedPrbEnd) && ((freePrbBlock->endPrb - reservedPrbEnd) > maxFreePRB))
1657 /* If sufficient free PRBs are available above reserved message*/
1658 *startPrb = reservedPrbEnd + 1;
1659 maxFreePRB = (freePrbBlock->endPrb - reservedPrbEnd);
1661 /*Also check the other freeBlock (i.e. Above the reserved message) for MAX FREE PRB*/
1662 if((reservedPrbStart > freePrbBlock->startPrb) && ((reservedPrbStart - freePrbBlock->startPrb) > maxFreePRB))
1664 /* If free PRBs are available below reserved message*/
1665 *startPrb = freePrbBlock->startPrb;
1666 maxFreePRB = (reservedPrbStart - freePrbBlock->startPrb);
1671 if(maxFreePRB < freePrbBlock->numFreePrb)
1673 *startPrb = freePrbBlock->startPrb;
1674 maxFreePRB = freePrbBlock->numFreePrb;
1678 freePrbNode = freePrbNode->next;
1683 /*******************************************************************************
1685 * @brief This function is used to send Slice Cfg rsp to MAC
1689 * Function : SchSendSliceCfgRspToMac
1692 * function is used to send Slice Cfg rsp to MAC
1694 * @params[in] Pst *pst, SchSliceCfgRsp sliceCfgRsp
1698 * ********************************************************************************/
1699 void SchSendSliceCfgRspToMac(Inst inst, SchSliceCfgRsp sliceCfgRsp)
1703 memset(&rspPst, 0, sizeof(Pst));
1704 FILL_PST_SCH_TO_MAC(rspPst, inst);
1705 rspPst.event = EVENT_SLICE_CFG_RSP_TO_MAC;
1707 MacMessageRouter(&rspPst, (void *)&sliceCfgRsp);
1711 /*******************************************************************************
1713 * @brief This function is used to store or modify the slice configuration Sch DB
1717 * Function : addOrModifySliceCfgInSchDb
1720 * function is used to store or modify the slice configuration Sch DB
1722 * @params[in] SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq,
1723 * SchSliceCfgRsp cfgRsp, uint8_t count
1729 * ********************************************************************************/
1730 uint8_t addSliceCfgInSchDb(CmLListCp *sliceCfgInDb, SchRrmPolicyOfSlice *cfgReq)
1732 SchRrmPolicyOfSlice *sliceToStore;
1734 SCH_ALLOC(sliceToStore, sizeof(SchRrmPolicyOfSlice));
1737 memcpy(&sliceToStore->snssai, &cfgReq->snssai, sizeof(Snssai));
1738 memcpy(&sliceToStore->rrmPolicyRatioInfo, &cfgReq->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1739 addNodeToLList(sliceCfgInDb, sliceToStore, NULL);
1743 DU_LOG("\nERROR --> SCH : Memory allocation failed in addOrModifySliceCfgInSchDb");
1749 /*******************************************************************************
1751 * @brief fill slice configuration response
1755 * Function : fillSliceCfgRsp
1758 * fill slice configuration response
1760 * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t count
1766 * ********************************************************************************/
1767 uint8_t fillSliceCfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchCellCb *cellCb, SchSliceCfgReq *schSliceCfgReq)
1769 SchMacRsp sliceFound;
1770 uint8_t cfgIdx = 0, sliceIdx = 0, plmnIdx = 0, ret =ROK;
1771 SchSliceCfgRsp schSliceCfgRsp;
1773 for(cfgIdx = 0; cfgIdx<schSliceCfgReq->numOfConfiguredSlice; cfgIdx++)
1775 sliceFound = RSP_NOK;
1776 /* Here comparing the slice cfg request with the slice stored in cellCfg */
1777 for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
1779 for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices; sliceIdx++)
1781 /* 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. */
1782 if(!memcmp(&schSliceCfgReq->listOfSlices[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai[sliceIdx], sizeof(Snssai)))
1784 if(addSliceCfgInSchDb(storedSliceCfg, schSliceCfgReq->listOfSlices[cfgIdx]) == ROK)
1786 sliceFound = RSP_OK;
1787 schSliceCfgRsp.cause = SUCCESSFUL;
1791 DU_LOG("\nERROR --> SCH : Failed to store slice configuration in SchDb");
1792 schSliceCfgRsp.cause = RESOURCE_UNAVAILABLE;
1801 if((sliceFound == RSP_NOK) && (schSliceCfgRsp.cause != RESOURCE_UNAVAILABLE))
1802 schSliceCfgRsp.cause = SLICE_NOT_FOUND;
1804 schSliceCfgRsp.snssai = schSliceCfgReq->listOfSlices[cfgIdx]->snssai;
1805 schSliceCfgRsp.rsp = sliceFound;
1806 SchSendSliceCfgRspToMac(inst, schSliceCfgRsp);
1811 /*******************************************************************************
1813 * @brief This function is used to free the slice cfg and re cfg request pointer
1817 * Function : freeSchSliceCfgReq
1820 * function is used to free the slice cfg and re cfg request pointer
1822 * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1827 * ********************************************************************************/
1828 void freeSchSliceCfgReq(SchSliceCfgReq *sliceCfgReq)
1834 if(sliceCfgReq->numOfConfiguredSlice)
1836 for(cfgIdx = 0; cfgIdx<sliceCfgReq->numOfConfiguredSlice; cfgIdx++)
1838 if(sliceCfgReq->listOfSlices[cfgIdx])
1840 SCH_FREE(sliceCfgReq->listOfSlices[cfgIdx], sizeof(SchRrmPolicyOfSlice));
1843 SCH_FREE(sliceCfgReq->listOfSlices, sliceCfgReq->numOfConfiguredSlice * sizeof(SchRrmPolicyOfSlice*));
1845 SCH_FREE(sliceCfgReq, sizeof(SchSliceCfgReq));
1848 /*******************************************************************************
1850 * @brief This function is used to store the slice configuration Sch DB
1854 * Function : SchProcSliceCfgReq
1857 * function is used to store the slice configuration Sch DB
1859 * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1865 * ********************************************************************************/
1866 uint8_t SchProcSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
1869 Inst inst = pst->dstInst - SCH_INST_START;
1871 DU_LOG("\nINFO --> SCH : Received Slice Cfg request from MAC");
1874 if(schSliceCfgReq->listOfSlices)
1876 /* filling the slice configuration response of each slice */
1877 if(fillSliceCfgRsp(inst, &schCb[inst].sliceCfg, schCb[inst].cells[0], schSliceCfgReq) != ROK)
1879 DU_LOG("\nERROR --> SCH : Failed to fill the slice cfg rsp");
1882 freeSchSliceCfgReq(schSliceCfgReq);
1887 DU_LOG("\nERROR --> SCH : Received SchSliceCfgReq is NULL");
1893 /*******************************************************************************
1895 * @brief This function is used to send Slice re Cfg rsp to MAC
1899 * Function : SchSendSliceRecfgRspToMac
1902 * function is used to send Slice re Cfg rsp to MAC
1904 * @params[in] Pst *pst, SchSliceRecfgRsp schSliceRecfgRsp
1908 * ********************************************************************************/
1909 void SchSendSliceRecfgRspToMac(Inst inst, SchSliceRecfgRsp schSliceRecfgRsp)
1913 memset(&rspPst, 0, sizeof(Pst));
1914 FILL_PST_SCH_TO_MAC(rspPst, inst);
1915 rspPst.event = EVENT_SLICE_RECFG_RSP_TO_MAC;
1917 MacMessageRouter(&rspPst, (void *)&schSliceRecfgRsp);
1920 /*******************************************************************************
1922 * @brief fill slice configuration response
1926 * Function : fillSliceRecfgRsp
1928 * Functionality: fill slice reconfiguration response
1930 * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t count
1936 * ********************************************************************************/
1938 uint8_t fillSliceRecfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchSliceRecfgReq *schSliceRecfgReq)
1940 SchMacRsp sliceFound;
1942 SchRrmPolicyOfSlice *rrmPolicyOfSlices;
1943 SchSliceRecfgRsp schSliceRecfgRsp;
1945 for(cfgIdx = 0; cfgIdx<schSliceRecfgReq->numOfConfiguredSlice; cfgIdx++)
1947 sliceFound = RSP_NOK;
1948 /* Here comparing the slice recfg request with the StoredSliceCfg */
1949 CmLList *sliceCfg = storedSliceCfg->first;
1953 rrmPolicyOfSlices = (SchRrmPolicyOfSlice*)sliceCfg->node;
1955 if(rrmPolicyOfSlices && (memcmp(&schSliceRecfgReq->listOfSlices[cfgIdx]->snssai, &(rrmPolicyOfSlices->snssai), sizeof(Snssai)) == 0))
1957 memcpy(&rrmPolicyOfSlices->rrmPolicyRatioInfo, &schSliceRecfgReq->listOfSlices[cfgIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1958 sliceFound = RSP_OK;
1961 sliceCfg = sliceCfg->next;
1964 schSliceRecfgRsp.snssai = schSliceRecfgReq->listOfSlices[cfgIdx]->snssai;
1965 schSliceRecfgRsp.rsp = sliceFound;
1966 if(schSliceRecfgRsp.rsp == RSP_OK)
1967 schSliceRecfgRsp.cause = SUCCESSFUL;
1969 schSliceRecfgRsp.cause = SLICE_NOT_FOUND;
1970 SchSendSliceRecfgRspToMac(inst, schSliceRecfgRsp);
1974 /*******************************************************************************
1976 * @brief This function is used to store the slice reconfiguration Sch DB
1980 * Function : SchProcSliceRecfgReq
1983 * function is used to store the slice re configuration Sch DB
1985 * @params[in] Pst *pst, SchSliceRecfgReq *schSliceRecfgReq
1991 * ********************************************************************************/
1992 uint8_t SchProcSliceRecfgReq(Pst *pst, SchSliceRecfgReq *schSliceRecfgReq)
1995 Inst inst = pst->dstInst - SCH_INST_START;
1997 DU_LOG("\nINFO --> SCH : Received Slice ReCfg request from MAC");
1998 if(schSliceRecfgReq)
2000 if(schSliceRecfgReq->listOfSlices)
2002 /* filling the slice configuration response of each slice */
2003 if(fillSliceRecfgRsp(inst, &schCb[inst].sliceCfg, schSliceRecfgReq) != ROK)
2005 DU_LOG("\nERROR --> SCH : Failed to fill sch slice cfg response");
2008 freeSchSliceCfgReq(schSliceRecfgReq);
2013 DU_LOG("\nERROR --> SCH : Received SchSliceRecfgReq is NULL");
2019 /****************************************************************************
2021 * @brief Stores the Paging Configuration from DU APP in CellCb
2025 * Function : schProcPagingParam
2028 * Process the Paging Configuration when FirstPDCCHMonitoring for
2029 * Paging Ocassion is not present.
2031 * As per 38.304 Sec 7.1,
2032 * "When firstPDCCH-MonitoringOccasionOfPO is present, the
2033 * starting PDCCH monitoring occasion number of (i_s + 1)th PO is the
2034 * (i_s + 1)th value of the firstPDCCHMonitoringOccasionOfPO
2035 * parameter; otherwise, it is equal to i_s * S."
2036 * "S = number of actual transmitted SSBs determined according
2037 * to ssb-PositionsInBurst in SIB1"
2039 * @params[in] SchCellCb *cell
2043 *************************************************************************/
2044 void schProcPagingCfg(SchCellCb *cell)
2046 SchPcchCfg *pageCfgRcvd = NULL;
2049 pageCfgRcvd = &(cell->cellCfg.dlCfgCommon.schPcchCfg);
2051 if(pageCfgRcvd->poPresent == TRUE)
2053 /*Fetching first Pdcch Monitoring Occasion for SFN (i_s + 1)th*/
2054 for(i_sIdx = 0; i_sIdx < pageCfgRcvd->numPO; i_sIdx++)
2056 cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pageCfgRcvd->pagingOcc[i_sIdx] / MAX_SYMB_PER_SLOT ;
2057 if ((pageCfgRcvd->pagingOcc[i_sIdx] % MAX_SYMB_PER_SLOT) != 0 )
2059 cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot++;
2062 cell->pageCb.pagMonOcc[i_sIdx].frameOffset = 0;
2068 schCfgPdcchMonOccOfPO(cell);
2072 /****************************************************************************
2074 * @brief Calculate PO if not present in Configuration
2078 * Function : schCfgPdcchMonOccOfPO
2080 * Functionality: In this function, PO are calculated i_s * S because
2081 * FirstPDCCHMonitoring_ForPO is not present.
2083 * @params[in] SchCellCb *cellCb
2087 *************************************************************************/
2088 void schCfgPdcchMonOccOfPO(SchCellCb *cell)
2090 uint8_t cnt = 0, incr = 1, i_sIdx = 0, frameOffSet = 0;
2091 uint8_t nsValue = cell->cellCfg.dlCfgCommon.schPcchCfg.numPO;
2092 uint8_t totalNumSsb = countSetBits(cell->cellCfg.ssbPosInBurst[0]);
2093 SlotTimingInfo tmpTimingInfo, pdcchTime;
2095 /*Starting with First Sfn and slot*/
2096 tmpTimingInfo.sfn = 0;
2097 tmpTimingInfo.slot = 0;
2099 pdcchTime = tmpTimingInfo;
2101 while(i_sIdx < nsValue)
2103 /*Increment frame Offset if PO falls on next SFN*/
2104 if(pdcchTime.sfn != tmpTimingInfo.sfn)
2108 pdcchTime = tmpTimingInfo;
2109 schIncrSlot(&(tmpTimingInfo), incr, cell->numSlots);
2113 cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2114 cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2120 if((cnt == totalNumSsb) && (i_sIdx < MAX_PO_PER_PF))
2122 cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2123 cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2131 /****************************************************************************
2133 * @brief Storing the paging information in SCH database
2137 * Function : schAddPagingIndtoList
2139 * Functionality: Storing the paging information in SCH database
2141 * @params[in] CmLListCp *storedPageList, CmLList *pageIndInfo
2143 * @return ROK - sucess
2146 *************************************************************************/
2147 uint8_t schAddPagingIndtoList(CmLListCp *storedPageList,void * pageIndInfo)
2149 CmLList *firstNodeOfList = NULLP;
2150 CmLList *currentNodeInfo = NULLP;
2151 SchPageInfo *tempNode = NULLP, *recvdNode = NULLP;
2153 recvdNode = (SchPageInfo*) pageIndInfo;
2154 CM_LLIST_FIRST_NODE(storedPageList,firstNodeOfList);
2156 SCH_ALLOC(currentNodeInfo, sizeof(CmLList));
2157 if(!currentNodeInfo)
2159 DU_LOG("\nERROR --> SCH : schAddPagingIndtoList() : Memory allocation failed");
2163 currentNodeInfo->node = (PTR)pageIndInfo;
2164 while(firstNodeOfList)
2166 tempNode = (SchPageInfo*)(firstNodeOfList->node);
2167 if ((recvdNode->pageTxTime.slot < tempNode->pageTxTime.slot))
2169 cmLListInsCrnt(storedPageList, currentNodeInfo);
2172 else if ((recvdNode->pageTxTime.slot == tempNode->pageTxTime.slot))
2174 DU_LOG("\nERROR --> SCH : schAddPagingIndtoList() : Slot[%d] is already present in the list", recvdNode->pageTxTime.slot);
2179 CM_LLIST_NEXT_NODE(storedPageList, firstNodeOfList);
2183 if(!firstNodeOfList)
2185 cmLListAdd2Tail(storedPageList, currentNodeInfo);
2187 DU_LOG("\nDEBUG --> SCH : Paging information is stored successfully for PF:%d, Slot:%d",\
2188 recvdNode->pageTxTime.sfn, recvdNode->pageTxTime.slot);
2192 /****************************************************************************
2194 * @brief Process paging indication at SCH recevied form MAC
2198 * Function : SchProcPagingInd
2200 * Functionality: Process paging indication at SCH recevied form MAC
2202 * @params[in] Pst *pst, SchPageInd *pageInd
2206 *************************************************************************/
2207 uint8_t SchProcPagingInd(Pst *pst, SchPageInd *pageInd)
2209 uint8_t ret = RFAILED;
2210 uint16_t cellIdx = 0;
2211 Inst inst = pst->dstInst - SCH_INST_START;
2212 SchCellCb *cellCb = NULLP;
2213 SchPageInfo *pageInfo = NULLP;
2217 DU_LOG("\nDEBUG --> SCH : Received paging indication from MAC for cellId[%d]",\
2221 for(cellIdx = 0; cellIdx < MAX_NUM_CELL; cellIdx++)
2223 if((schCb[inst].cells[cellIdx]) && (schCb[inst].cells[cellIdx]->cellId == pageInd->cellId))
2225 cellCb = schCb[inst].cells[cellIdx];
2231 if(pageInd->i_s > cellCb->cellCfg.dlCfgCommon.schPcchCfg.numPO)
2233 DU_LOG("\nERROR --> SCH : SchProcPagingInd(): i_s should not be greater than number of paging occasion");
2237 SCH_ALLOC(pageInfo, sizeof(SchPageInfo));
2240 pageInfo->pf = pageInd->pf;
2241 pageInfo->i_s = pageInd->i_s;
2242 pageInfo->pageTxTime.cellId = pageInd->cellId;
2243 pageInfo->pageTxTime.sfn = (pageInd->pf + cellCb->pageCb.pagMonOcc[pageInd->i_s].frameOffset) % MAX_SFN;
2244 pageInfo->pageTxTime.slot = cellCb->pageCb.pagMonOcc[pageInd->i_s].pagingOccSlot;
2245 pageInfo->mcs = DEFAULT_MCS;
2246 pageInfo->msgLen = pageInd->pduLen;
2247 SCH_ALLOC(pageInfo->pagePdu, pageInfo->msgLen);
2248 if(!pageInfo->pagePdu)
2250 DU_LOG("\nERROR --> SCH : SchProcPagingInd(): Failed to allocate memory");
2254 memcpy(pageInfo->pagePdu, pageInd->pagePdu, pageInfo->msgLen);
2255 ret = schAddPagingIndtoList(&cellCb->pageCb.pageIndInfoRecord[pageInfo->pageTxTime.sfn], pageInfo);
2258 DU_LOG("\nERROR --> SCH : SchProcPagingInd(): Failed to store paging record");
2264 DU_LOG("\nERROR --> SCH : SchProcPagingInd(): Failed to allocate memory");
2270 DU_LOG("\nERROR --> SCH : Cell ID [%d] not found", pageInd->cellId);
2272 SCH_FREE(pageInd->pagePdu, pageInd->pduLen);
2273 SCH_FREE(pageInd, sizeof(SchPageInd));
2277 DU_LOG("\nERROR --> SCH : SchProcPagingInd(): Received null pointer");
2283 /***********************************************************
2285 * Func : SchFillCfmPst
2288 * Desc : Fills the Confirmation Post Structure cfmPst using the reqPst
2289 * and the cfm->hdr.response.
2296 * File : rg_sch_lmm.c
2298 **********************************************************/
2308 inst = (reqPst->dstInst - SCH_INST_START);
2310 cfmPst->srcEnt = ENTMAC;
2311 cfmPst->srcInst = (Inst) 1;
2312 cfmPst->srcProcId = schCb[inst].schInit.procId;
2313 cfmPst->dstEnt = ENTMAC;
2314 cfmPst->dstInst = (Inst) 0;
2315 cfmPst->dstProcId = reqPst->srcProcId;
2317 cfmPst->selector = cfm->hdr.response.selector;
2318 cfmPst->region = cfm->hdr.response.mem.region;
2319 cfmPst->pool = cfm->hdr.response.mem.pool;
2324 /*******************************************************************
2326 * @brief Processes DL CQI ind from MAC
2330 * Function : SchProcDlCqiInd
2333 * Processes DL CQI ind from MAC
2336 * @return ROK - success
2339 * ****************************************************************/
2340 uint8_t SchProcDlCqiInd(Pst *pst, SchDlCqiInd *dlCqiInd)
2343 uint16_t ueId = 0, cellIdx = 0;
2344 SchUeCb *ueCb = NULLP;
2345 SchCellCb *cell = NULLP;
2346 Inst inst = pst->dstInst-SCH_INST_START;
2350 DU_LOG("\nERROR --> SCH : SchProcDlCqiInd(): CQI Ind is empty");
2355 GET_CELL_IDX(dlCqiInd->cellId, cellIdx);
2356 cell = schCb[inst].cells[cellIdx];
2359 DU_LOG("\nERROR --> SCH : SchProcDlCqiInd(): cell Id[%d] not found", dlCqiInd->cellId);
2364 if(cell->cellId == dlCqiInd->cellId)
2366 GET_UE_ID(dlCqiInd->crnti, ueId);
2367 ueCb = &cell->ueCb[ueId-1];
2368 if(ueCb->crnti != dlCqiInd->crnti)
2370 DU_LOG("\nERROR --> SCH : SchProcDlCqiInd(): UeCb for received crnti[%d] not found", dlCqiInd->crnti);
2375 /*TODO: complete the processing of DL CQI Ind*/
2380 DU_LOG("\nERROR --> SCH : SchProcDlCqiInd(): Received cell Id[%d] from MAC is not matching with CellID[%d] in SCH Cb",\
2381 dlCqiInd->cellId, cell->cellId);
2389 /*******************************************************************
2391 * @brief Processes UL CQI ind from MAC
2395 * Function : SchProcUlCqiInd
2398 * Processes UL CQI ind from MAC
2401 * @return ROK - success
2404 * ****************************************************************/
2405 uint8_t SchProcUlCqiInd(Pst *pst, SchUlCqiInd *ulCqiInd)
2408 uint16_t ueId = 0, cellIdx = 0;
2409 SchUeCb *ueCb = NULLP;
2410 SchCellCb *cell = NULLP;
2411 Inst inst = pst->dstInst-SCH_INST_START;
2415 DU_LOG("\nERROR --> SCH : SchProcUlCqiInd(): CQI Ind is empty");
2420 GET_CELL_IDX(ulCqiInd->cellId, cellIdx);
2421 cell = schCb[inst].cells[cellIdx];
2424 DU_LOG("\nERROR --> SCH : SchProcUlCqiInd(): cell Id[%d] not found", ulCqiInd->cellId);
2429 if(cell->cellId == ulCqiInd->cellId)
2431 GET_UE_ID(ulCqiInd->crnti, ueId);
2432 ueCb = &cell->ueCb[ueId-1];
2433 if(ueCb->crnti != ulCqiInd->crnti)
2435 DU_LOG("\nERROR --> SCH : SchProcUlCqiInd(): UeCb for received crnti[%d] not found",ulCqiInd->crnti);
2440 /*TODO: complete the processing of UL CQI Ind*/
2445 DU_LOG("\nERROR --> SCH : SchProcUlCqiInd(): Received cell Id[%d] from MAC is not matching with CellId[%d] in SCH Cb",\
2446 ulCqiInd->cellId, cell->cellId);
2454 /*******************************************************************
2456 * @brief Processes PHR ind from MAC
2460 * Function : SchProcPhrInd
2463 * Processes PHR ind from MAC
2466 * @return ROK - success
2469 * ****************************************************************/
2470 uint8_t SchProcPhrInd(Pst *pst, SchPwrHeadroomInd *schPhrInd)
2473 uint16_t ueId = 0, cellIdx = 0;
2474 SchUeCb *ueCb = NULLP;
2475 SchCellCb *cell = NULLP;
2476 Inst inst = pst->dstInst-SCH_INST_START;
2480 DU_LOG("\nERROR --> SCH : SchProcPhrInd(): PHR is empty");
2485 GET_CELL_IDX(schPhrInd->cellId, cellIdx);
2486 cell = schCb[inst].cells[cellIdx];
2489 DU_LOG("\nERROR --> SCH : schProcPhrInd(): cell Id[%d] is not found", schPhrInd->cellId);
2494 if(cell->cellId == schPhrInd->cellId)
2496 GET_UE_ID(schPhrInd->crnti, ueId);
2497 ueCb = &cell->ueCb[ueId-1];
2498 if(ueCb->crnti != schPhrInd->crnti)
2500 DU_LOG("\nERROR --> SCH : SchProcPhrInd(): UeCb for received crnti[%d] not found",schPhrInd->crnti);
2505 /*TODO: complete the processing of PHR Ind*/
2510 DU_LOG("\nERROR --> SCH : SchProcPhrInd(): Mismatch between Received cell Id[%d] from MAC and CellID[%d] in SCH CB ",\
2511 schPhrInd->cellId, cell->cellId);
2519 /*******************************************************************
2521 * @brief Fill and send statistics response to MAC
2525 * Function : SchSendStatsRspToMac
2527 * Functionality: Fill and send statistics response to MAC
2529 * @params[in] Inst inst, SchMacRsp result
2530 * @return ROK - success
2533 * ****************************************************************/
2534 uint8_t SchSendStatsRspToMac(SchStatsRsp *statsRsp)
2538 SchStatsRsp *schStatsRsp;
2540 DU_LOG("\nINFO --> SCH : Filling statistics response");
2541 SCH_ALLOC(schStatsRsp, sizeof(SchStatsRsp));
2542 if(schStatsRsp == NULLP)
2544 DU_LOG("\nERROR --> SCH : Failed to allocate memory in SchSendStatsRspToMac()");
2548 memcpy(schStatsRsp, statsRsp, sizeof(SchStatsRsp));
2549 memset(statsRsp, 0, sizeof(SchStatsRsp));
2551 /* Filling response post */
2552 memset(&rspPst, 0, sizeof(Pst));
2553 FILL_PST_SCH_TO_MAC(rspPst, inst);
2554 rspPst.event = EVENT_STATISTICS_RSP_TO_MAC;
2556 ret = MacMessageRouter(&rspPst, (void *)schStatsRsp);
2559 DU_LOG("\nERROR --> SCH : SchSendStatsRspToMac(): Failed to send Statistics Response");
2565 /*******************************************************************
2567 * @brief Rejects all statistics group requested by MAC
2571 * Function : SchRejectAllStats
2573 * Functionality: Add all statistics group received in statistics
2574 * request from MAC, to Reject-Stats-Group-List in statistics
2577 * @params[in] Statistics request from MAC
2578 * Cause of rejection
2579 * @return ROK - success
2582 * ****************************************************************/
2583 uint8_t SchRejectAllStats(SchStatsReq *schStatsReq, CauseOfResult cause)
2586 SchStatsRsp schStatsRsp;
2588 memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
2590 /* Copying all stats group from stats request to stats response */
2591 schStatsRsp.subscriptionId = schStatsReq->subscriptionId;
2592 for(grpIdx = 0; grpIdx < schStatsReq->numStatsGroup; grpIdx++)
2594 schStatsRsp.statsGrpRejectedList[grpIdx].groupId = schStatsReq->statsGrpList[grpIdx].groupId;
2595 schStatsRsp.statsGrpRejectedList[grpIdx].cause = cause;
2597 schStatsRsp.numGrpRejected = schStatsReq->numStatsGroup;
2599 return SchSendStatsRspToMac(&schStatsRsp);
2602 /*******************************************************************
2604 * @brief Add active KPI pointers to KPI-Active-List
2608 * Function : schAddToKpiActiveList
2610 * Functionality: For each active statistics group for which timer
2611 * is running, add its KPI pointer to KPI-Active-List.
2613 * When it is needed to update a KPI parameters, we need not
2614 * traverse all statistics group and all KPIs within a group
2615 * to get the specific KPI pointer to be updated.
2616 * Instead, we can traverse through KPI-Active-List and update
2617 * all entries in this list.
2619 * @params[in] Pointer to the prb usage info link list
2620 * Pointer to the stats ccnfig which we need to add
2621 * @return ROK - success
2624 * ****************************************************************/
2625 uint8_t schAddToKpiActiveList(CmLListCp *kpiList, PTR kpiStatsInfo)
2627 CmLList *node = NULLP;
2629 SCH_ALLOC(node, sizeof(CmLList));
2632 node->node = kpiStatsInfo;
2633 cmLListAdd2Tail(kpiList, node);
2636 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2640 /*******************************************************************
2642 * @brief add the stats group information in statistics's statsGrpList
2646 * Function : schAddToStatsGrpList
2648 * Functionality: add the stats group information in statsGrpList
2649 * [Step 1] - Allocating the memory for the stats group in which
2650 * we need to fill into the list as a node.
2651 * [Step 2] - If allocation is successful then start traversing
2652 * each measurment cfg index of received group info.
2653 * [Step 2.1] Validate all measurements. If validation succeeds, go
2654 * to [step 2.2]. Otherwise, reject the stats group and go to step 3.
2655 * [Step 2.2] Add each KPI/measurementCfg into activeKpiList one by one.
2656 * If it fails for any KPI, reject the whole statsGrp and go to step 3..
2657 * [Step 2.3] Fill other group related information
2658 * [Step 2.4] Initialise and start timer
2659 * [Step 2.5] Once all validation and configuration is successful, add
2660 * statsGrp node into statistic's StatsGrpList.
2661 * [Step 2.5.1] If node successfully added to the list, then
2662 * fill the group related info in stats rsp's accepted list.
2663 * [Step 2.5.2] Else goto step 3
2664 * [Step 3] - If failed fill the group related info in stats rsp's
2669 * Pointer to the stats rsp
2671 * Stats Grp Info which needs to be store in the list
2672 * @return ROK - success
2675 * ****************************************************************/
2677 uint8_t schAddToStatsGrpList(Inst inst, struct schStatsRsp *statsRsp, uint64_t subscriptionId, SchStatsGrpInfo *grpInfo)
2681 uint8_t reqMeasIdx=0;
2682 CauseOfResult cause;
2683 bool measTypeInvalid=false;
2684 CmLList *statsGrpNode=NULLP;
2685 SchStatsGrp *grpInfoDb = NULLP;
2688 SCH_ALLOC(grpInfoDb, sizeof(SchStatsGrp));
2689 if(grpInfoDb == NULLP)
2691 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2692 cause = RESOURCE_UNAVAILABLE;
2698 for(reqMeasIdx = 0; reqMeasIdx < grpInfo->numStats; reqMeasIdx++)
2701 switch(grpInfo->statsList[reqMeasIdx])
2703 case SCH_DL_TOTAL_PRB_USAGE:
2705 SCH_ALLOC(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
2706 if(!grpInfoDb->kpiStats.dlTotalPrbUsage)
2708 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2709 measTypeInvalid = true;
2710 cause = RESOURCE_UNAVAILABLE;
2716 case SCH_UL_TOTAL_PRB_USAGE:
2718 SCH_ALLOC(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
2719 if(!grpInfoDb->kpiStats.ulTotalPrbUsage)
2721 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2722 measTypeInvalid = true;
2723 cause = RESOURCE_UNAVAILABLE;
2731 DU_LOG("\nERROR --> SCH : SchProcStatsReq: Invalid measurement type [%d]", \
2732 grpInfo->statsList[reqMeasIdx]);
2733 measTypeInvalid = true;
2734 cause = PARAM_INVALID;
2746 while(measTypeInvalid==false)
2748 if(grpInfoDb->kpiStats.dlTotalPrbUsage)
2751 if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, (PTR)grpInfoDb->kpiStats.dlTotalPrbUsage)!=ROK)
2753 DU_LOG("\nERROR --> E2AP : KPI addition failed in %s at %d",__func__,__LINE__);
2754 cause = RESOURCE_UNAVAILABLE;
2760 if(grpInfoDb->kpiStats.ulTotalPrbUsage)
2763 if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR)grpInfoDb->kpiStats.ulTotalPrbUsage) != ROK)
2765 DU_LOG("\nERROR --> E2AP : KPI addition failed in %s at %d",__func__,__LINE__);
2766 cause = RESOURCE_UNAVAILABLE;
2773 grpInfoDb->schInst = inst;
2774 grpInfoDb->groupId = grpInfo->groupId;
2775 grpInfoDb->periodicity = grpInfo->periodicity;
2776 grpInfoDb->subscriptionId = subscriptionId;
2779 cmInitTimers(&(grpInfoDb->periodTimer), 1);
2780 schStartTmr(&schCb[inst], (PTR)(grpInfoDb), EVENT_STATISTICS_TMR, grpInfoDb->periodicity);
2783 SCH_ALLOC(statsGrpNode, sizeof(CmLList));
2787 statsGrpNode->node = (PTR) grpInfoDb;
2788 cmLListAdd2Tail(&schCb[inst].statistics.statsGrpList, statsGrpNode);
2789 statsRsp->statsGrpAcceptedList[statsRsp->numGrpAccepted] = grpInfo->groupId;
2790 statsRsp->numGrpAccepted++;
2798 DU_LOG("\nERROR --> E2AP : Memory allocation failed in %s at %d",__func__,__LINE__);
2799 cause = RESOURCE_UNAVAILABLE;
2811 deleteStatsGrpInfo(inst, grpInfoDb);
2812 SCH_FREE(grpInfoDb, sizeof(SchStatsGrp));
2814 statsRsp->statsGrpRejectedList[statsRsp->numGrpRejected].groupId = grpInfo->groupId;
2815 statsRsp->statsGrpRejectedList[statsRsp->numGrpRejected].cause = cause;
2816 statsRsp->numGrpRejected++;
2822 /*******************************************************************
2824 * @brief Processes Statistics Request from MAC
2828 * Function : SchProcStatsReq
2832 * This function process the statistics request from MAC:
2833 * [Step 1] Basic validation. If fails, all stats group in stats request are
2835 * [Step 2] If basic validations passed, traverse all stats group and
2836 * validate each measurement types in each group.
2837 * [Step 3] If any measurement type validation fails in a group, that group
2838 * is not configured and it is added to stats-group-rejected-list in
2839 * sch-stats-response message.
2840 * [Step 4] If a group passes all validation, it is added to SCH database.
2841 * And the group is added to stats-group-accepted-list in sch-stats-response message.
2842 * [Step 5] sch-stats-response is sent to du app with stats-group-rejected-list
2843 * and stats-group-accepted-list.
2845 * @params[in] Post structure
2846 * Statistics Request from MAC
2847 * @return ROK - success
2850 * ****************************************************************/
2851 uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq)
2853 bool allocFailed = false;
2854 uint8_t grpIdx = 0, reqGrpIdx = 0;
2855 SchStatsGrpInfo *grpInfo = NULLP;
2856 SchStatsRsp schStatsRsp;
2857 Inst inst = pst->dstInst - SCH_INST_START;
2859 DU_LOG("\nINFO --> SCH : Received Statistics Request from MAC");
2861 if(statsReq == NULLP)
2863 DU_LOG("\nERROR --> SCH : SchProcStatsReq(): Received Null pointer");
2868 if(schCb[inst].statistics.statsGrpList.count >= MAX_NUM_STATS_GRP)
2870 DU_LOG("\nERROR --> SCH : SchProcStatsReq: Maximum number of statistics configured. \
2871 Cannot process new request.");
2872 SchRejectAllStats(statsReq, RESOURCE_UNAVAILABLE);
2873 SCH_FREE(statsReq, sizeof(SchStatsReq));
2877 memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
2880 for(reqGrpIdx=0; reqGrpIdx<statsReq->numStatsGroup && grpIdx<MAX_NUM_STATS; reqGrpIdx++)
2882 grpInfo = &statsReq->statsGrpList[reqGrpIdx];
2884 if(allocFailed == true)
2886 schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].groupId = grpInfo->groupId;
2887 schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].cause = RESOURCE_UNAVAILABLE;
2888 schStatsRsp.numGrpRejected++;
2893 if(schAddToStatsGrpList(inst, &schStatsRsp, statsReq->subscriptionId, grpInfo) != ROK)
2895 DU_LOG("\nERROR --> SCH : SchProcStatsReq(): Failed to fill the stats group list");
2896 if((schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected-1].groupId == grpInfo->groupId &&\
2897 (schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected-1].cause == RESOURCE_UNAVAILABLE)))
2905 schStatsRsp.subscriptionId = statsReq->subscriptionId;
2906 SCH_FREE(statsReq, sizeof(SchStatsReq));
2909 SchSendStatsRspToMac(&schStatsRsp);
2914 /*******************************************************************
2916 * @brief Fill and send statistics indication to MAC
2920 * Function : SchSendStatsIndToMac
2922 * Functionality: Fill and send statistics indication to MAC
2924 * @params[in] SCH Instance
2927 * Size of value parameter
2928 * @return ROK - success
2931 * ****************************************************************/
2932 uint8_t SchSendStatsIndToMac(Inst inst, SchStatsInd *statsInd)
2938 DU_LOG("\nDEBUG --> SCH : Filling statistics indication");
2941 /* Filling post structure */
2942 memset(&pst, 0, sizeof(Pst));
2943 FILL_PST_SCH_TO_MAC(pst, inst);
2944 pst.event = EVENT_STATISTICS_IND_TO_MAC;
2946 ret = MacMessageRouter(&pst, (void *)statsInd);
2949 DU_LOG("\nERROR --> SCH : SchSendStatsIndToMac(): Failed to send Statistics Indication");
2955 * @brief Handler to process Timer expiry of DL Total PRB Usage calculation
2957 * @param[in] cb Control block depending on the type of the timer event.
2958 * @param[in] tmrEvnt Timer event to be started
2960 * @return Bool indicating whether the timer is running or not
2964 double calcDlTotalPrbUsage(TotalPrbUsage *dlTotalPrbUsage)
2966 double percentageOfTotalPrbUsed = 0;
2968 if(dlTotalPrbUsage->totalPrbAvailForTx)
2969 percentageOfTotalPrbUsed = ((100.0 * dlTotalPrbUsage->numPrbUsedForTx) / dlTotalPrbUsage->totalPrbAvailForTx);
2971 memset(dlTotalPrbUsage, 0, sizeof(TotalPrbUsage));
2973 return percentageOfTotalPrbUsed;
2977 * @brief Handler to check if the timer is running
2979 * @param[in] cb Control block depending on the type of the timer event.
2980 * @param[in] tmrEvnt Timer event to be started
2982 * @return Bool indicating whether the timer is running or not
2986 uint8_t calcUlTotalPrbUsage(TotalPrbUsage *ulTotalPrbUsage)
2988 double percentageOfTotalPrbUsed = 0;
2990 if(ulTotalPrbUsage->totalPrbAvailForTx)
2991 percentageOfTotalPrbUsed = ((100.0 * ulTotalPrbUsage->numPrbUsedForTx) / ulTotalPrbUsage->totalPrbAvailForTx);
2993 memset(ulTotalPrbUsage, 0, sizeof(TotalPrbUsage));
2995 return percentageOfTotalPrbUsed;
2999 * @brief Calculates statistics in a group and sends
3000 * statistics indication for this group
3002 * @param[in] Statistics group info
3008 uint8_t schCalcAndSendGrpStats(SchStatsGrp *grpInfo)
3010 uint8_t measStatsIdx = 0;
3011 SchStatsInd statsInd;
3013 memset(&statsInd, 0, sizeof(SchStatsInd));
3014 statsInd.subscriptionId = grpInfo->subscriptionId;
3015 statsInd.groupId = grpInfo->groupId;
3017 if(grpInfo->kpiStats.dlTotalPrbUsage)
3019 statsInd.measuredStatsList[measStatsIdx].type = SCH_DL_TOTAL_PRB_USAGE;
3020 statsInd.measuredStatsList[measStatsIdx].value = calcDlTotalPrbUsage(grpInfo->kpiStats.dlTotalPrbUsage);
3024 if(grpInfo->kpiStats.ulTotalPrbUsage)
3026 statsInd.measuredStatsList[measStatsIdx].type = SCH_UL_TOTAL_PRB_USAGE;
3027 statsInd.measuredStatsList[measStatsIdx].value = calcUlTotalPrbUsage(grpInfo->kpiStats.ulTotalPrbUsage);
3031 statsInd.numStats = measStatsIdx;
3033 return SchSendStatsIndToMac(grpInfo->schInst, &statsInd);
3036 /*******************************************************************
3038 * @brief Delete node from active kpi list
3042 * Function :deleteNodeFrmKpiList
3045 * Delete statistics group
3048 * Kpi list from which a node needs to be deleted
3049 * Nodes info which a node needs to be deleted
3051 * ****************************************************************/
3053 void deleteNodeFrmKpiList(CmLListCp *kpiList, PTR kpiNodeInfoToDel)
3055 CmLList *kpiNode=NULLP;
3057 CM_LLIST_FIRST_NODE(kpiList, kpiNode);
3060 if(kpiNode->node == kpiNodeInfoToDel)
3062 cmLListDelFrm(kpiList, kpiNode);
3063 SCH_FREE(kpiNode, sizeof(CmLList));
3066 kpiNode = kpiNode->next;
3071 /*******************************************************************
3073 * @brief Delete statistics group info
3077 * Function : deleteStatsGrpInfo
3080 * Delete statistics group info
3087 * ****************************************************************/
3088 void deleteStatsGrpInfo(Inst inst, SchStatsGrp *statsGrpInfo)
3092 if(statsGrpInfo->kpiStats.dlTotalPrbUsage)
3094 deleteNodeFrmKpiList(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, (PTR) statsGrpInfo->kpiStats.dlTotalPrbUsage);
3095 SCH_FREE(statsGrpInfo->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
3098 if(statsGrpInfo->kpiStats.ulTotalPrbUsage)
3100 deleteNodeFrmKpiList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR) statsGrpInfo->kpiStats.ulTotalPrbUsage);
3101 SCH_FREE(statsGrpInfo->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
3104 if(schChkTmr((PTR)statsGrpInfo, EVENT_STATISTICS_TMR) == true)
3106 schStopTmr(&schCb[inst], (PTR)statsGrpInfo, EVENT_STATISTICS_TMR);
3109 memset(statsGrpInfo, 0, sizeof(SchStatsGrp));
3113 /*******************************************************************
3115 * @brief Delete statistics group Node
3119 * Function : deleteStatsGrpNode
3122 * Delete statistics group node
3129 * ****************************************************************/
3130 void deleteStatsGrpNode(Inst inst, CmLList *grpNode)
3132 SchStatsGrp *statsGrpInfo=NULLP;
3136 statsGrpInfo = (SchStatsGrp*)grpNode->node;
3137 deleteStatsGrpInfo(inst, statsGrpInfo);
3138 memset(statsGrpInfo, 0, sizeof(SchStatsGrp));
3139 SCH_FREE(grpNode->node, sizeof(SchStatsGrp));
3140 SCH_FREE(grpNode, sizeof(CmLList));
3144 /******************************************************************
3146 * @brief Deletion of node from statistics group list
3150 * Function : deleteFromStatsGrpList
3152 * Functionality: Deletion of node from statistics group list
3153 * [Step 1]: Traverse each and every node of stats group list
3154 * stored in the database
3155 * [Step 2]: Check if the node's subscription id is same
3156 * as the subscription id received. If same then go to step 3
3157 * else move to the next node of the list.
3158 * [Step 3]: If deleteAllGrp == true, then delete the node and
3159 * move to the next node of the list.
3160 * [Step 4]: If deleteAllGrp != true, then check if the node's group
3161 * id is same as group id received then delete the node and mark the
3162 * status found true else move to the next node of the list.
3163 * [Step 5]: Once the traversing complete,
3164 * if deleteAllGrp is true, then return successful rsp;
3165 * else if status found is true, then return successful rsp;
3166 * else return failure.
3172 * boolen of deleteAllGrp
3175 * ****************************************************************/
3176 uint8_t deleteFromStatsGrpList(Inst inst, CmLListCp *statsGrpList, uint64_t subscriptionId, uint8_t groupId, bool deleteAllGrp)
3178 bool statsFound=false;
3179 SchStatsGrp *statsGrpInfo=NULLP;
3180 CmLList *grpNode=NULLP;
3183 CM_LLIST_FIRST_NODE(statsGrpList, grpNode);
3186 statsGrpInfo = (SchStatsGrp*)grpNode->node;
3189 if(statsGrpInfo->subscriptionId== subscriptionId)
3191 if(deleteAllGrp == true)
3194 cmLListDelFrm(statsGrpList, grpNode);
3195 deleteStatsGrpNode(inst, grpNode);
3200 if(statsGrpInfo->groupId== groupId)
3202 cmLListDelFrm(statsGrpList, grpNode);
3203 deleteStatsGrpNode(inst, grpNode);
3208 CM_LLIST_FIRST_NODE(statsGrpList, grpNode);
3212 if(deleteAllGrp == true)
3218 if(statsFound == true)
3224 /*******************************************************************
3226 * @brief Delete statistics information
3230 * Function : deleteStatsInfo
3233 * Delete statistics information base on numStatsGroup
3234 * Info- If numStatsGroup = 0' indicates the Deletion procedure triggered by
3235 * 'SUBS_DELETION_REQ' wherein all the groups of this particular
3236 * Subscription has to be removed
3237 * else when numStatsGroup != 0 then this is
3238 * for SUBS_MOD_REQ's actionToBeDeleted wherein particular action(s) has
3239 * to be removed thus need to pass groupId belonging to that subscription
3240 * which has to be deleted.'
3242 * [Step-1] If numStatsGroup = 0, Deletion of all stats group belonging to
3243 * received subscription Id.
3244 * [Step-2] Else if numStatsGroup > 0, Deletion of individual stats group
3245 * from list whose information are present in stats delete request.
3246 * [Step-3] Fill the result of the stats deletion in the SCH stats delete
3250 * Subscription delete req
3251 * Subscription delete rsp
3252 * @return ROK - success
3255 * ****************************************************************/
3256 uint8_t deleteStatsInfo(Inst inst, SchStatsDeleteReq *statsDeleteReq, SchStatsDeleteRsp *schStatsDeleteRsp)
3258 uint8_t statsGrpIdx=0;
3259 CmLListCp *statsGrpList =NULLP;
3261 statsGrpList = &schCb[inst].statistics.statsGrpList;
3263 if(!statsDeleteReq->numStatsGroupToBeDeleted)
3266 if(deleteFromStatsGrpList(inst,statsGrpList, statsDeleteReq->subscriptionId, 0, true) == ROK)
3269 schStatsDeleteRsp->subsDelRsp = RSP_OK;
3270 schStatsDeleteRsp->subsDelCause = SUCCESSFUL;
3275 schStatsDeleteRsp->subsDelRsp = RSP_NOK;
3276 schStatsDeleteRsp->subsDelCause = STATS_ID_NOT_FOUND;
3281 for(statsGrpIdx=0; statsGrpIdx<statsDeleteReq->numStatsGroupToBeDeleted; statsGrpIdx++)
3284 if(deleteFromStatsGrpList(inst, statsGrpList, statsDeleteReq->subscriptionId,\
3285 statsDeleteReq->statsGrpIdToBeDelList[statsGrpIdx], false) == ROK)
3288 schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelRsp = RSP_OK;
3289 schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelCause = SUCCESSFUL;
3294 schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelRsp = RSP_NOK;
3295 schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelCause = STATS_ID_NOT_FOUND;
3298 schStatsDeleteRsp->numStatsGroupDeleted = statsDeleteReq->numStatsGroupToBeDeleted;
3303 /*******************************************************************
3305 * @brief Processes Statistics Delete Request from MAC
3309 * Function : SchProcStatsDeleteReq
3312 * This function process the statistics delete request from MAC:
3314 * @params[in] Post structure
3315 * Statistics Delete Request from MAC
3316 * @return ROK - success
3319 * ****************************************************************/
3320 uint8_t SchProcStatsDeleteReq(Pst *pst, SchStatsDeleteReq *statsDeleteReq)
3324 SchStatsDeleteRsp *schStatsDeleteRsp;
3325 Inst inst = pst->dstInst - SCH_INST_START;
3327 DU_LOG("\nINFO --> SCH : Received Statistics Delete Request from MAC");
3329 if(statsDeleteReq == NULLP)
3331 DU_LOG("\nERROR --> SCH : SchProcStatsDeleteReq(): Received Null pointer");
3335 /* Process Stats delete request and fill stats delete response simultaneously */
3336 SCH_ALLOC(schStatsDeleteRsp, sizeof(SchStatsDeleteRsp));
3337 if(schStatsDeleteRsp == NULLP)
3339 DU_LOG("\nERROR --> SCH : Failed to allocate memory in SchProcStatsDeleteReq()");
3342 schStatsDeleteRsp->subscriptionId=statsDeleteReq->subscriptionId;
3343 deleteStatsInfo(inst, statsDeleteReq, schStatsDeleteRsp);
3345 memset(&rspPst, 0, sizeof(Pst));
3346 FILL_PST_SCH_TO_MAC(rspPst, inst);
3347 rspPst.event = EVENT_STATISTICS_DELETE_RSP_TO_MAC;
3349 ret = MacMessageRouter(&rspPst, (void *)schStatsDeleteRsp);
3352 DU_LOG("\nERROR --> SCH : SchProcStatsDeleteReq(): Failed to send Statistics Response");
3354 SCH_FREE(statsDeleteReq, sizeof(SchStatsDeleteReq));
3357 } /* End of SchProcStatsDeleteReq */
3359 /*******************************************************************
3361 * @brief Fill and send statistics modification response to MAC
3365 * Function : SchSendStatsRspToMac
3367 * Functionality: Fill and send statistics
3368 * modification response to MAC
3370 * @params[in] Inst inst, SchMacRsp result
3371 * @return ROK - success
3374 * ****************************************************************/
3375 uint8_t SchSendStatsModificationRspToMac(SchStatsModificationRsp *tmpSchStatsModRsp)
3379 SchStatsModificationRsp *schStatsModificationRsp=NULLP;
3381 DU_LOG("\nINFO --> SCH : Filling statistics modification response");
3382 SCH_ALLOC(schStatsModificationRsp, sizeof(SchStatsModificationRsp));
3383 if(schStatsModificationRsp == NULLP)
3385 DU_LOG("\nERROR --> SCH : Failed to allocate memory in SchSendStatsModificationRspToMac()");
3389 memcpy(schStatsModificationRsp, tmpSchStatsModRsp, sizeof(SchStatsModificationRsp));
3390 memset(tmpSchStatsModRsp, 0, sizeof(SchStatsModificationRsp));
3392 /* Filling response post */
3393 memset(&rspPst, 0, sizeof(Pst));
3394 FILL_PST_SCH_TO_MAC(rspPst, inst);
3395 rspPst.event = EVENT_STATISTICS_MODIFY_RSP_TO_MAC;
3397 ret = MacMessageRouter(&rspPst, (void *)schStatsModificationRsp);
3400 DU_LOG("\nERROR --> SCH : SchSendStatsModificationRspToMac(): Failed to send Statistics Modification Response");
3406 /*******************************************************************
3408 * @brief Rejects all statistics modification group requested by MAC
3412 * Function : SchRejectAllStatsModification
3414 * Functionality: Add all statistics modification group received in statistics
3415 * request from MAC, to Reject-StatsModification-Group-List in statistics
3418 * @params[in] Statistics request from MAC
3419 * Cause of rejection
3420 * @return ROK - success
3423 * ****************************************************************/
3424 uint8_t SchRejectAllStatsModification(SchStatsModificationReq *statsModificationReq, CauseOfResult cause)
3427 SchStatsModificationRsp statsModificationRsp;
3429 memset(&statsModificationRsp, 0, sizeof(SchStatsModificationRsp));
3431 /* fill the subscriptionId and the rejected list in stats modification rsp */
3432 statsModificationRsp.subscriptionId = statsModificationReq->subscriptionId;
3433 for(grpIdx = 0; grpIdx < statsModificationReq->numStatsGroup; grpIdx++)
3435 statsModificationRsp.statsGrpRejectedList[grpIdx].groupId = statsModificationReq->statsGrpList[grpIdx].groupId;
3436 statsModificationRsp.statsGrpRejectedList[grpIdx].cause = cause;
3438 statsModificationRsp.numGrpRejected = statsModificationReq->numStatsGroup;
3440 return SchSendStatsModificationRspToMac(&statsModificationRsp);
3443 /****************************************************************************************
3445 * @brief Processes Statistics modification Request from MAC
3449 * Function :SchProcStatsModificationReq
3452 * This function process the statistics modification request from MAC:
3453 * [Step -1] Check the stored stats group list empty.
3454 * [Step - 1.1] If empty Send the rejected group list to MAC as a stats
3455 * modification response.
3456 * [Step - 1.2] Else go to step 2.
3457 * [Step -2] Traverse all stats group and validate each measurement types in
3459 * [Step -3] Check for any failure and if failed fill the remaining group's
3460 * info in rejected list.
3461 * [Step -4] Else Check if the received subscriptionId and groupId match the
3462 * values with the database node.
3463 * [Step -4.1] If matches then follow the below mentioned steps.
3464 * [Step -4.1.1] Stop the timer.
3465 * [Step -4.1.2] Reconfigure stats group by adding a new entry for this
3466 * statsGroup with updated configuration in database.
3467 * [Step -4.1.3] if configured successfully, store stats info into
3468 * stats mod rsp's accepted list, restart timer and go to step 4.1.4
3469 * [Step -4.1.4] Delete the old entry of this stats group..
3470 * [Step -4.2] Else fill the group related info in stats modification rsp's
3472 * [Step -5] Send the stats modification rsp to MAC
3473 * @params[in] Post structure
3474 * Statistics modification Request from MAC
3475 * @return ROK - success
3478 * *******************************************************************************************/
3479 uint8_t SchProcStatsModificationReq(Pst *pst, SchStatsModificationReq *statsModificationReq)
3482 uint8_t reqGrpIdx=0;
3483 uint64_t subscriptionId =0;
3484 bool allocFailed = false;
3485 bool statsGrpFound= false;
3486 CmLList *grpNode = NULLP;
3487 SchStatsGrp *statsGrpInfo=NULLP;
3488 SchStatsGrpInfo statsGrpToModify;
3489 SchStatsModificationRsp statsModificationRsp;
3491 inst=pst->dstInst - SCH_INST_START;
3493 DU_LOG("\nINFO --> SCH : Received Statistics modification request from MAC");
3495 if(statsModificationReq == NULLP)
3497 DU_LOG("\nERROR --> SCH : SchProcStatsModificationReq(): Received Null pointer");
3500 memset(&statsModificationRsp, 0, sizeof(SchStatsRsp));
3503 if(schCb[inst].statistics.statsGrpList.count)
3506 subscriptionId = statsModificationReq->subscriptionId;
3509 for(reqGrpIdx=0; reqGrpIdx<statsModificationReq->numStatsGroup; reqGrpIdx++)
3512 statsGrpToModify = statsModificationReq->statsGrpList[reqGrpIdx];
3513 if(allocFailed != true)
3515 CM_LLIST_FIRST_NODE(&schCb[inst].statistics.statsGrpList, grpNode);
3519 statsGrpInfo = (SchStatsGrp*)grpNode->node;
3520 if((statsGrpInfo->subscriptionId== subscriptionId) && (statsGrpInfo->groupId== statsGrpToModify.groupId))
3522 statsGrpFound= true;
3525 grpNode = grpNode->next;
3529 if(statsGrpFound== true)
3531 /* [Step - 4.1.1] */
3532 if(schChkTmr((PTR)statsGrpInfo, EVENT_STATISTICS_TMR) == true)
3534 schStopTmr(&schCb[inst], (PTR)statsGrpInfo, EVENT_STATISTICS_TMR);
3537 /* [Step - 4.1.2] */
3538 if(schAddToStatsGrpList(inst, &statsModificationRsp, subscriptionId, &statsGrpToModify) != ROK)
3540 DU_LOG("\nERROR --> SCH : SchProcStatsReq(): Failed to fill the stats group list");
3541 if(statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected-1].groupId == statsGrpToModify.groupId)
3543 /* [Step - 4.1.3] */
3544 schStartTmr(&schCb[inst], (PTR)(statsGrpInfo), EVENT_STATISTICS_TMR, statsGrpInfo->periodicity);
3545 if(statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected-1].cause == RESOURCE_UNAVAILABLE)
3554 /* [Step - 4.1.4] */
3555 deleteStatsGrpNode(inst, grpNode);
3561 statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].groupId = statsGrpToModify.groupId;
3562 statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].cause = STATS_ID_NOT_FOUND;
3563 statsModificationRsp.numGrpRejected++;
3568 statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].groupId = statsGrpToModify.groupId;
3569 statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].cause = RESOURCE_UNAVAILABLE;
3570 statsModificationRsp.numGrpRejected++;
3574 statsModificationRsp.subscriptionId = statsModificationReq->subscriptionId;
3575 SchSendStatsModificationRspToMac(&statsModificationRsp);
3580 SchRejectAllStatsModification(statsModificationReq, STATS_ID_NOT_FOUND);
3582 SCH_FREE(statsModificationReq, sizeof(SchStatsModificationReq));
3585 /**********************************************************************
3587 **********************************************************************/