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"
49 #include "sch_utils.h"
51 void SchFillCfmPst(Pst *reqPst,Pst *cfmPst,RgMngmt *cfm);
54 SchCellCfgCfmFunc SchCellCfgCfmOpts[] =
56 packSchCellCfgCfm, /* LC */
57 MacProcSchCellCfgCfm, /* TC */
58 packSchCellCfgCfm /* LWLC */
61 SchSliceCfgRspFunc SchSliceCfgRspOpts[] =
63 packSchSliceCfgRsp, /* LC */
64 MacProcSchSliceCfgRsp, /* TC */
65 packSchSliceCfgRsp /* LWLC */
69 SchSliceReCfgRspFunc SchSliceReCfgRspOpts[] =
71 packSchSliceReCfgRsp, /* LC */
72 MacProcSchSliceReCfgRsp, /* TC */
73 packSchSliceReCfgRsp /* LWLC */
77 * @brief Task Initiation function.
81 * Function : schActvInit
83 * This function is supplied as one of parameters during MAC's
84 * task registration. MAC will invoke this function once, after
85 * it creates and attaches this TAPA Task to a system task.
87 * @param[in] Ent Entity, the entity ID of this task.
88 * @param[in] Inst Inst, the instance ID of this task.
89 * @param[in] Region Region, the region ID registered for memory
91 * @param[in] Reason Reason.
95 uint8_t schActvInit(Ent entity, Inst instId, Region region, Reason reason)
97 Inst inst = (instId - SCH_INST_START);
99 /* Initialize the MAC TskInit structure to zero */
100 memset ((uint8_t *)&schCb[inst], 0, sizeof(schCb));
102 /* Initialize the MAC TskInit with received values */
103 schCb[inst].schInit.ent = entity;
104 schCb[inst].schInit.inst = inst;
105 schCb[inst].schInit.region = region;
106 schCb[inst].schInit.pool = 0;
107 schCb[inst].schInit.reason = reason;
108 schCb[inst].schInit.cfgDone = FALSE;
109 schCb[inst].schInit.acnt = FALSE;
110 schCb[inst].schInit.usta = FALSE;
111 schCb[inst].schInit.trc = FALSE;
112 schCb[inst].schInit.procId = ODU_GET_PROCID();
118 * @brief Scheduler instance Configuration Handler.
122 * Function : SchInstCfg
124 * This function in called by SchProcGenCfgReq(). It handles the
125 * general configurations of the scheduler instance. Returns
126 * reason for success/failure of this function.
128 * @param[in] RgCfg *cfg, the Configuaration information
130 * -# LCM_REASON_NOT_APPL
131 * -# LCM_REASON_INVALID_MSGTYPE
132 * -# LCM_REASON_MEM_NOAVAIL
134 uint8_t SchInstCfg(RgCfg *cfg, Inst dInst)
136 uint16_t ret = LCM_REASON_NOT_APPL;
137 Inst inst = (dInst - SCH_INST_START);
139 DU_LOG("\nDEBUG --> SCH : Entered SchInstCfg()");
140 /* Check if Instance Configuration is done already */
141 if (schCb[inst].schInit.cfgDone == TRUE)
143 return LCM_REASON_INVALID_MSGTYPE;
145 /* Update the Pst structure for LM interface */
146 memcpy(&schCb[inst].schInit.lmPst, &cfg->s.schInstCfg.genCfg.lmPst, sizeof(Pst));
148 schCb[inst].schInit.inst = inst;
149 schCb[inst].schInit.lmPst.srcProcId = schCb[inst].schInit.procId;
150 schCb[inst].schInit.lmPst.srcEnt = schCb[inst].schInit.ent;
151 schCb[inst].schInit.lmPst.srcInst = schCb[inst].schInit.inst +
153 schCb[inst].schInit.lmPst.event = EVTNONE;
155 schCb[inst].schInit.region = cfg->s.schInstCfg.genCfg.mem.region;
156 schCb[inst].schInit.pool = cfg->s.schInstCfg.genCfg.mem.pool;
157 schCb[inst].genCfg.tmrRes = cfg->s.schInstCfg.genCfg.tmrRes;
159 schCb[inst].genCfg.forceCntrlSrbBoOnPCel = cfg->s.schInstCfg.genCfg.forceCntrlSrbBoOnPCel;
160 schCb[inst].genCfg.isSCellActDeactAlgoEnable = cfg->s.schInstCfg.genCfg.isSCellActDeactAlgoEnable;
162 schCb[inst].genCfg.startCellId = cfg->s.schInstCfg.genCfg.startCellId;
164 /* Initialzie the timer queue */
165 memset(&schCb[inst].tmrTq, 0, sizeof(CmTqType) * SCH_TQ_SIZE);
166 /* Initialize the timer control point */
167 memset(&schCb[inst].tmrTqCp, 0, sizeof(CmTqCp));
168 schCb[inst].tmrTqCp.tmrLen = RGSCH_TQ_SIZE;
170 /* SS_MT_TMR needs to be enabled as schActvTmr needs instance information */
171 /* Timer Registration request to system services */
172 if (ODU_REG_TMR_MT(schCb[inst].schInit.ent, dInst, (int)schCb[inst].genCfg.tmrRes, schActvTmr) != ROK)
174 DU_LOG("\nERROR --> SCH : SchInstCfg(): Failed to "
176 return (LCM_REASON_MEM_NOAVAIL);
179 /* Set Config done in TskInit */
180 schCb[inst].schInit.cfgDone = TRUE;
181 DU_LOG("\nINFO --> SCH : Scheduler gen config done");
187 * @brief Layer Manager Configuration request handler.
191 * Function : SchProcGenCfgReq
193 * This function handles the configuration
194 * request received at scheduler instance from the Layer Manager.
195 * -# Based on the cfg->hdr.elmId.elmnt value it invokes one of the
196 * functions rgHdlGenCfg() or rgHdlSapCfg().
197 * -# Invokes RgMiLrgSchCfgCfm() to send back the confirmation to the LM.
199 * @param[in] Pst *pst, the post structure
200 * @param[in] RgMngmt *cfg, the configuration parameter's structure
204 uint8_t SchProcGenCfgReq(Pst *pst, RgMngmt *cfg)
206 uint8_t ret = LCM_PRIM_OK;
207 uint16_t reason = LCM_REASON_NOT_APPL;
211 #ifdef CALL_FLOW_DEBUG_LOG
212 DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : GENERAL_CFG_REQ\n");
215 if(pst->dstInst < SCH_INST_START)
217 DU_LOG("\nERROR --> SCH : Invalid inst ID");
218 DU_LOG("\nERROR --> SCH : SchProcGenCfgReq(): "
219 "pst->dstInst=%d SCH_INST_START=%d", pst->dstInst,SCH_INST_START);
222 DU_LOG("\nINFO --> SCH : Received scheduler gen config");
223 /* Fill the post structure for sending the confirmation */
224 memset(&cfmPst, 0 , sizeof(Pst));
225 SchFillCfmPst(pst, &cfmPst, cfg);
227 memset(&cfm, 0, sizeof(RgMngmt));
234 cfm.hdr.elmId.elmnt = cfg->hdr.elmId.elmnt;
235 switch(cfg->hdr.elmId.elmnt)
238 reason = SchInstCfg(&cfg->t.cfg,pst->dstInst );
242 reason = LCM_REASON_INVALID_ELMNT;
243 DU_LOG("\nERROR --> SCH : Invalid Elmnt=%d", cfg->hdr.elmId.elmnt);
247 if (reason != LCM_REASON_NOT_APPL)
252 cfm.cfm.status = ret;
253 cfm.cfm.reason = reason;
255 SchSendCfgCfm(&cfmPst, &cfm);
256 /* SCH_FREE(pst->region, pst->pool, (Data *)cfg, sizeof(RgMngmt)); */
259 }/*-- SchProcGenCfgReq --*/
262 * @brief slot indication from MAC to SCH.
266 * Function : MacSchSlotInd
268 * This API is invoked by PHY to indicate slot indication to Scheduler for
271 * @param[in] Pst *pst
272 * @param[in] SlotTimingInfo *slotInd
277 uint8_t MacSchSlotInd(Pst *pst, SlotTimingInfo *slotInd)
279 Inst inst = pst->dstInst-SCH_INST_START;
281 #ifdef CALL_FLOW_DEBUG_LOG
282 DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_SLOT_IND_TO_SCH\n");
285 schProcessSlotInd(slotInd, inst);
288 } /* MacSchSlotInd */
290 /*******************************************************************
292 * @brief Processes Rach indication from MAC
296 * Function : MacSchRachInd
299 * Processes Rach indication from MAC
302 * @return ROK - success
305 * ****************************************************************/
306 uint8_t MacSchRachInd(Pst *pst, RachIndInfo *rachInd)
308 Inst inst = pst->dstInst-SCH_INST_START;
310 #ifdef CALL_FLOW_DEBUG_LOG
311 DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_RACH_IND_TO_SCH\n");
314 DU_LOG("\nINFO --> SCH : Received Rach indication");
315 schProcessRachInd(rachInd, inst);
319 /*******************************************************************
321 * @brief Processes CRC indication from MAC
325 * Function : MacSchCrcInd
328 * Processes CRC indication from MAC
330 * @params[in] Post structure
332 * @return ROK - success
335 * ****************************************************************/
336 uint8_t MacSchCrcInd(Pst *pst, CrcIndInfo *crcInd)
338 #ifdef CALL_FLOW_DEBUG_LOG
339 DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_CRC_IND_TO_SCH\n");
342 switch(crcInd->crcInd[0])
345 DU_LOG("\nDEBUG --> SCH : Received CRC indication. CRC Status [FAILURE]");
348 DU_LOG("\nDEBUG --> SCH : Received CRC indication. CRC Status [PASS]");
351 DU_LOG("\nDEBUG --> SCH : Invalid CRC state %d", crcInd->crcInd[0]);
359 *@brief Returns TDD periodicity in micro seconds
363 * Function : schGetPeriodicityInMsec
365 * This API retunrs TDD periodicity in micro seconds
367 * @param[in] DlUlTxPeriodicity
368 * @return periodicityInMsec
371 uint16_t schGetPeriodicityInMsec(DlUlTxPeriodicity tddPeriod)
373 uint16_t periodicityInMsec = 0;
376 case TX_PRDCTY_MS_0P5:
378 periodicityInMsec = 500;
381 case TX_PRDCTY_MS_0P625:
383 periodicityInMsec = 625;
388 periodicityInMsec = 1000;
391 case TX_PRDCTY_MS_1P25:
393 periodicityInMsec = 1250;
398 periodicityInMsec = 2000;
401 case TX_PRDCTY_MS_2P5:
403 periodicityInMsec = 2500;
408 periodicityInMsec = 5000;
411 case TX_PRDCTY_MS_10:
413 periodicityInMsec = 10000;
418 DU_LOG("\nERROR --> SCH : Invalid DlUlTxPeriodicity:%d", tddPeriod);
422 return periodicityInMsec;
427 * @brief init TDD slot config
431 * Function : schInitTddSlotCfg
433 * This API is invoked after receiving schCellCfg
435 * @param[in] schCellCb *cell
436 * @param[in] SchCellCfg *schCellCfg
439 void schInitTddSlotCfg(SchCellCb *cell, SchCellCfg *schCellCfg)
441 uint16_t periodicityInMicroSec = 0;
442 int8_t slotIdx, symbIdx;
444 periodicityInMicroSec = schGetPeriodicityInMsec(schCellCfg->tddCfg.tddPeriod);
445 cell->numSlotsInPeriodicity = (periodicityInMicroSec * pow(2, schCellCfg->numerology))/1000;
446 cell->slotFrmtBitMap = 0;
447 cell->symbFrmtBitMap = 0;
448 for(slotIdx = cell->numSlotsInPeriodicity-1; slotIdx >= 0; slotIdx--)
451 /* If the first and last symbol are the same, the entire slot is the same type */
452 if((schCellCfg->tddCfg.slotCfg[slotIdx][symbIdx] == schCellCfg->tddCfg.slotCfg[slotIdx][MAX_SYMB_PER_SLOT-1]) &&
453 schCellCfg->tddCfg.slotCfg[slotIdx][symbIdx] != FLEXI_SLOT)
455 switch(schCellCfg->tddCfg.slotCfg[slotIdx][symbIdx])
459 /*BitMap to be set to 00 */
460 cell->slotFrmtBitMap = (cell->slotFrmtBitMap<<2);
465 /*BitMap to be set to 01 */
466 cell->slotFrmtBitMap = ((cell->slotFrmtBitMap<<2) | (UL_SLOT));
470 DU_LOG("\nERROR --> SCH : Invalid slot Config in schInitTddSlotCfg");
474 /* slot config is flexible. First set slotBitMap to 10 */
475 cell->slotFrmtBitMap = ((cell->slotFrmtBitMap<<2) | (FLEXI_SLOT));
477 /* Now set symbol bitmap */
478 for(symbIdx = MAX_SYMB_PER_SLOT-1; symbIdx >= 0; symbIdx--)
480 switch(schCellCfg->tddCfg.slotCfg[slotIdx][symbIdx])
484 /*symbol BitMap to be set to 00 */
485 cell->symbFrmtBitMap = (cell->symbFrmtBitMap<<2);
490 /*symbol BitMap to be set to 01 */
491 cell->symbFrmtBitMap = ((cell->symbFrmtBitMap<<2) | (UL_SLOT));
496 /*symbol BitMap to be set to 10 */
497 cell->symbFrmtBitMap = ((cell->symbFrmtBitMap<<2) | (FLEXI_SLOT));
501 DU_LOG("\nERROR --> SCH : Invalid slot Config in schInitTddSlotCfg");
509 * @brief Fill SSB start symbol
513 * Function : fillSsbStartSymb
515 * This API stores SSB start index per beam
517 * @param[in] SchCellCb *cellCb
522 void fillSsbStartSymb(SchCellCb *cellCb)
524 uint8_t cnt, scs, symbIdx, ssbStartSymbArr[SCH_MAX_SSB_BEAM];
526 scs = cellCb->cellCfg.ssbSchCfg.scsCommon;
528 memset(ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
530 /* Determine value of "n" based on Section 4.1 of 3GPP TS 38.213 */
535 if(cellCb->cellCfg.dlFreq <= 300000)
536 cnt = 2;/* n = 0, 1 */
538 cnt = 4; /* n = 0, 1, 2, 3 */
539 for(uint8_t idx=0; idx<cnt; idx++)
541 /* start symbol determined using {2, 8} + 14n */
542 ssbStartSymbArr[symbIdx++] = 2 + MAX_SYMB_PER_SLOT*idx;
543 ssbStartSymbArr[symbIdx++] = 8 + MAX_SYMB_PER_SLOT*idx;
549 if(cellCb->cellCfg.dlFreq <= 300000)
552 cnt = 2; /* n = 0, 1 */
553 for(uint8_t idx=0; idx<cnt; idx++)
555 /* start symbol determined using {4, 8, 16, 20} + 28n */
556 ssbStartSymbArr[symbIdx++] = 4 + MAX_SYMB_PER_SLOT*idx;
557 ssbStartSymbArr[symbIdx++] = 8 + MAX_SYMB_PER_SLOT*idx;
558 ssbStartSymbArr[symbIdx++] = 16 + MAX_SYMB_PER_SLOT*idx;
559 ssbStartSymbArr[symbIdx++] = 20 + MAX_SYMB_PER_SLOT*idx;
564 DU_LOG("\nERROR --> SCH : SCS %d is currently not supported", scs);
566 memset(cellCb->ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
567 memcpy(cellCb->ssbStartSymbArr, ssbStartSymbArr, SCH_MAX_SSB_BEAM);
573 * @brief init cellCb based on cellCfg
577 * Function : schInitCellCb
579 * This API is invoked after receiving schCellCfg
581 * @param[in] schCellCb *cell
582 * @param[in] SchCellCfg *schCellCfg
587 uint8_t schInitCellCb(Inst inst, SchCellCfg *schCellCfg)
589 SchCellCb *cell= NULLP;
590 SCH_ALLOC(cell, sizeof(SchCellCb));
593 DU_LOG("\nERROR --> SCH : Memory allocation failed in schInitCellCb");
597 cell->cellId = schCellCfg->cellId;
598 cell->instIdx = inst;
599 switch(schCellCfg->numerology)
601 case SCH_NUMEROLOGY_0:
603 cell->numSlots = SCH_MU0_NUM_SLOTS;
606 case SCH_NUMEROLOGY_1:
608 cell->numSlots = SCH_MU1_NUM_SLOTS;
611 case SCH_NUMEROLOGY_2:
613 cell->numSlots = SCH_MU2_NUM_SLOTS;
616 case SCH_NUMEROLOGY_3:
618 cell->numSlots = SCH_MU3_NUM_SLOTS;
621 case SCH_NUMEROLOGY_4:
623 cell->numSlots = SCH_MU4_NUM_SLOTS;
627 DU_LOG("\nERROR --> SCH : Numerology %d not supported", schCellCfg->numerology);
630 schInitTddSlotCfg(cell, schCellCfg);
633 SCH_ALLOC(cell->schDlSlotInfo, cell->numSlots * sizeof(SchDlSlotInfo*));
634 if(!cell->schDlSlotInfo)
636 DU_LOG("\nERROR --> SCH : Memory allocation failed in schInitCellCb for schDlSlotInfo");
640 SCH_ALLOC(cell->schUlSlotInfo, cell->numSlots * sizeof(SchUlSlotInfo*));
641 if(!cell->schUlSlotInfo)
643 DU_LOG("\nERROR --> SCH : Memory allocation failed in schInitCellCb for schUlSlotInfo");
647 for(uint8_t idx=0; idx<cell->numSlots; idx++)
649 SchDlSlotInfo *schDlSlotInfo;
650 SchUlSlotInfo *schUlSlotInfo;
653 SCH_ALLOC(schDlSlotInfo, sizeof(SchDlSlotInfo));
656 DU_LOG("\nERROR --> SCH : Memory allocation failed in schInitCellCb");
661 SCH_ALLOC(schUlSlotInfo, sizeof(SchUlSlotInfo));
664 DU_LOG("\nERROR --> SCH : Memory allocation failed in schInitCellCb");
668 schInitDlSlot(schDlSlotInfo);
669 schInitUlSlot(schUlSlotInfo);
671 cell->schDlSlotInfo[idx] = schDlSlotInfo;
672 cell->schUlSlotInfo[idx] = schUlSlotInfo;
675 cell->firstSsbTransmitted = false;
676 cell->firstSib1Transmitted = false;
677 fillSsbStartSymb(cell);
678 cmLListInit(&cell->ueToBeScheduled);
679 schCb[inst].cells[inst] = cell;
681 DU_LOG("\nINFO --> SCH : Cell init completed for cellId:%d", cell->cellId);
687 * @brief Fill SIB1 configuration
691 * Function : fillSchSib1Cfg
693 * Fill SIB1 configuration
695 * @param[in] uint8_t bandwidth : total available bandwidth
696 * uint8_t numSlots : total slots per SFN
697 * SchSib1Cfg *sib1SchCfg : cfg to be filled
698 * uint16_t pci : physical cell Id
699 * uint8_t offsetPointA : offset
702 void fillSchSib1Cfg(uint8_t mu, uint8_t bandwidth, uint8_t numSlots, SchSib1Cfg *sib1SchCfg, uint16_t pci, uint8_t offsetPointA)
704 uint8_t coreset0Idx = 0;
705 uint8_t searchSpace0Idx = 0;
706 //uint8_t ssbMuxPattern = 0;
708 uint8_t numSymbols = 0;
711 //uint8_t numSearchSpacePerSlot = 0;
713 uint8_t firstSymbol = 0; /* need to calculate using formula mentioned in 38.213 */
714 uint8_t slotIndex = 0;
715 uint8_t FreqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
719 PdcchCfg *pdcch = &(sib1SchCfg->sib1PdcchCfg);
720 PdschCfg *pdsch = &(sib1SchCfg->sib1PdschCfg);
721 BwpCfg *bwp = &(sib1SchCfg->bwp);
723 coreset0Idx = sib1SchCfg->coresetZeroIndex;
724 searchSpace0Idx = sib1SchCfg->searchSpaceZeroIndex;
726 /* derive the sib1 coreset0 params from table 13-1 spec 38.213 */
727 //ssbMuxPattern = coresetIdxTable[coreset0Idx][0];
728 numRbs = coresetIdxTable[coreset0Idx][1];
729 numSymbols = coresetIdxTable[coreset0Idx][2];
730 offset = coresetIdxTable[coreset0Idx][3];
732 /* derive the search space params from table 13-11 spec 38.213 */
733 oValue = searchSpaceIdxTable[searchSpace0Idx][0];
734 //numSearchSpacePerSlot = searchSpaceIdxTable[searchSpace0Idx][1];
735 mValue = searchSpaceIdxTable[searchSpace0Idx][2];
736 firstSymbol = searchSpaceIdxTable[searchSpace0Idx][3];
738 /* calculate the n0, need to add the formulae, as of now the value is 0
739 * Need to add the even and odd values of i during configuration
740 * [(O . 2^u + i . M ) ] mod numSlotsPerSubframe
741 * assuming u = 0, i = 0, numSlotsPerSubframe = 10
742 * Also, from this configuration, coreset0 is only on even subframe */
743 slotIndex = (int)((oValue*pow(2, mu)) + floor(ssbIdx*mValue))%numSlots;
744 sib1SchCfg->n0 = slotIndex;
749 case BANDWIDTH_20MHZ:
751 bwp->freqAlloc.numPrb = TOTAL_PRB_20MHZ_MU0;
754 case BANDWIDTH_100MHZ:
756 bwp->freqAlloc.numPrb = TOTAL_PRB_100MHZ_MU1;
760 DU_LOG("\nERROR --> SCH : Bandwidth %d not supported", bandwidth);
763 bwp->freqAlloc.startPrb = 0;
764 bwp->subcarrierSpacing = 0; /* 15Khz */
765 bwp->cyclicPrefix = 0; /* normal */
767 /* fill the PDCCH PDU */
768 pdcch->coresetCfg.coreSetSize = numRbs;
769 pdcch->coresetCfg.startSymbolIndex = firstSymbol;
770 pdcch->coresetCfg.durationSymbols = numSymbols;
772 /* Fill Bitmap for PRBs in coreset */
773 fillCoresetFeqDomAllocMap(((offsetPointA-offset)/6), (numRbs/6), FreqDomainResource);
774 covertFreqDomRsrcMapToIAPIFormat(FreqDomainResource, pdcch->coresetCfg.freqDomainResource);
776 pdcch->coresetCfg.cceRegMappingType = 1; /* coreset0 is always interleaved */
777 pdcch->coresetCfg.regBundleSize = 6; /* spec-38.211 sec 7.3.2.2 */
778 pdcch->coresetCfg.interleaverSize = 2; /* spec-38.211 sec 7.3.2.2 */
779 pdcch->coresetCfg.coreSetType = 0;
780 pdcch->coresetCfg.shiftIndex = pci;
781 pdcch->coresetCfg.precoderGranularity = 0; /* sameAsRegBundle */
783 pdcch->dci.rnti = SI_RNTI;
784 pdcch->dci.scramblingId = pci;
785 pdcch->dci.scramblingRnti = 0;
786 pdcch->dci.cceIndex = 0;
787 pdcch->dci.aggregLevel = 4;
788 pdcch->dci.beamPdcchInfo.numPrgs = 1;
789 pdcch->dci.beamPdcchInfo.prgSize = 1;
790 pdcch->dci.beamPdcchInfo.digBfInterfaces = 0;
791 pdcch->dci.beamPdcchInfo.prg[0].pmIdx = 0;
792 pdcch->dci.beamPdcchInfo.prg[0].beamIdx[0] = 0;
793 pdcch->dci.txPdcchPower.powerValue = 0;
794 pdcch->dci.txPdcchPower.powerControlOffsetSS = 0;
795 /* Storing pdschCfg pointer here. Required to access pdsch config while
796 fillig up pdcch pdu */
797 pdcch->dci.pdschCfg = pdsch;
799 /* fill the PDSCH PDU */
801 pdsch->pduBitmap = 0; /* PTRS and CBG params are excluded */
802 pdsch->rnti = 0xFFFF; /* SI-RNTI */
804 pdsch->numCodewords = 1;
805 for(cwCount = 0; cwCount < pdsch->numCodewords; cwCount++)
807 pdsch->codeword[cwCount].targetCodeRate = 308;
808 pdsch->codeword[cwCount].qamModOrder = 2;
809 pdsch->codeword[cwCount].mcsIndex = sib1SchCfg->sib1Mcs;
810 pdsch->codeword[cwCount].mcsTable = 0; /* notqam256 */
811 pdsch->codeword[cwCount].rvIndex = 0;
812 tbSize = schCalcTbSize(sib1SchCfg->sib1PduLen + TX_PAYLOAD_HDR_LEN);
813 pdsch->codeword[cwCount].tbSize = tbSize;
815 pdsch->dataScramblingId = pci;
816 pdsch->numLayers = 1;
817 pdsch->transmissionScheme = 0;
819 pdsch->dmrs.dlDmrsSymbPos = 4; /* Bitmap value 00000000000100 i.e. using 3rd symbol for PDSCH DMRS */
820 pdsch->dmrs.dmrsConfigType = 0; /* type-1 */
821 pdsch->dmrs.dlDmrsScramblingId = pci;
822 pdsch->dmrs.scid = 0;
823 pdsch->dmrs.numDmrsCdmGrpsNoData = 1;
824 pdsch->dmrs.dmrsPorts = 0x0001;
825 pdsch->dmrs.mappingType = DMRS_MAP_TYPE_A; /* Type-A */
826 pdsch->dmrs.nrOfDmrsSymbols = NUM_DMRS_SYMBOLS;
827 pdsch->dmrs.dmrsAddPos = DMRS_ADDITIONAL_POS;
829 pdsch->pdschFreqAlloc.resourceAllocType = 1; /* RAT type-1 RIV format */
830 /* the RB numbering starts from coreset0, and PDSCH is always above SSB */
831 pdsch->pdschFreqAlloc.freqAlloc.startPrb = offsetPointA + SCH_SSB_NUM_PRB;
832 pdsch->pdschFreqAlloc.freqAlloc.numPrb = schCalcNumPrb(tbSize,sib1SchCfg->sib1Mcs, NUM_PDSCH_SYMBOL);
833 pdsch->pdschFreqAlloc.vrbPrbMapping = 0; /* non-interleaved */
834 pdsch->pdschTimeAlloc.rowIndex = 1;
835 /* This is Intel's requirement. PDSCH should start after PDSCH DRMS symbol */
836 pdsch->pdschTimeAlloc.timeAlloc.startSymb = 3; /* spec-38.214, Table 5.1.2.1-1 */
837 pdsch->pdschTimeAlloc.timeAlloc.numSymb = NUM_PDSCH_SYMBOL;
838 pdsch->beamPdschInfo.numPrgs = 1;
839 pdsch->beamPdschInfo.prgSize = 1;
840 pdsch->beamPdschInfo.digBfInterfaces = 0;
841 pdsch->beamPdschInfo.prg[0].pmIdx = 0;
842 pdsch->beamPdschInfo.prg[0].beamIdx[0] = 0;
843 pdsch->txPdschPower.powerControlOffset = 0;
844 pdsch->txPdschPower.powerControlOffsetSS = 0;
849 * @brief cell config from MAC to SCH.
853 * Function : macSchCellCfgReq
855 * This API is invoked by MAC to send cell config to SCH
857 * @param[in] Pst *pst
858 * @param[in] SchCellCfg *schCellCfg
863 uint8_t SchHdlCellCfgReq(Pst *pst, SchCellCfg *schCellCfg)
867 SchCellCfgCfm schCellCfgCfm;
869 Inst inst = pst->dstInst - SCH_INST_START;
870 uint8_t coreset0Idx = 0;
873 uint8_t freqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
874 SchPdschConfig pdschCfg;
876 #ifdef CALL_FLOW_DEBUG_LOG
877 DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_SCH_CELL_CFG\n");
880 schInitCellCb(inst, schCellCfg);
881 cellCb = schCb[inst].cells[inst]; //cells is of MAX_CELLS, why inst
882 cellCb->macInst = pst->srcInst;
884 /* derive the SIB1 config parameters */
885 fillSchSib1Cfg(schCellCfg->numerology, schCellCfg->bandwidth, cellCb->numSlots,
886 &(schCellCfg->sib1SchCfg), schCellCfg->phyCellId,
887 schCellCfg->ssbSchCfg.ssbOffsetPointA);
890 memcpy(&cellCb->cellCfg, schCellCfg, sizeof(SchCellCfg));
891 schProcPagingCfg(cellCb);
893 /* Fill coreset frequencyDomainResource bitmap */
894 coreset0Idx = cellCb->cellCfg.schInitialDlBwp.pdcchCommon.commonSearchSpace.coresetId;
895 numRbs = coresetIdxTable[coreset0Idx][1];
896 offset = coresetIdxTable[coreset0Idx][3];
897 fillCoresetFeqDomAllocMap(((cellCb->cellCfg.ssbSchCfg.ssbOffsetPointA - offset)/6), (numRbs/6), freqDomainResource);
898 covertFreqDomRsrcMapToIAPIFormat(freqDomainResource, \
899 cellCb->cellCfg.schInitialDlBwp.pdcchCommon.commonSearchSpace.freqDomainRsrc);
901 /* Fill K0 - K1 table for common cfg*/
902 BuildK0K1Table(cellCb, &cellCb->cellCfg.schInitialDlBwp.k0K1InfoTbl, true, cellCb->cellCfg.schInitialDlBwp.pdschCommon,
903 pdschCfg, DEFAULT_UL_ACK_LIST_COUNT, defaultUlAckTbl);
905 BuildK2InfoTable(cellCb, cellCb->cellCfg.schInitialUlBwp.puschCommon.timeDomRsrcAllocList,\
906 cellCb->cellCfg.schInitialUlBwp.puschCommon.numTimeDomRsrcAlloc, &cellCb->cellCfg.schInitialUlBwp.msg3K2InfoTbl, \
907 &cellCb->cellCfg.schInitialUlBwp.k2InfoTbl);
908 /* Initializing global variables */
909 cellCb->actvUeBitMap = 0;
910 cellCb->boIndBitMap = 0;
912 /* Fill and send Cell config confirm */
913 memset(&rspPst, 0, sizeof(Pst));
914 FILL_PST_SCH_TO_MAC(rspPst, pst->dstInst);
915 rspPst.event = EVENT_SCH_CELL_CFG_CFM;
917 schCellCfgCfm.cellId = schCellCfg->cellId;
918 schCellCfgCfm.rsp = RSP_OK;
920 ret = (*SchCellCfgCfmOpts[rspPst.selector])(&rspPst, &schCellCfgCfm);
925 /*******************************************************************
927 * @brief Processes DL RLC BO info from MAC
931 * Function : MacSchDlRlcBoInfo
934 * Processes DL RLC BO info from MAC
937 * @return ROK - success
940 * ****************************************************************/
941 uint8_t MacSchDlRlcBoInfo(Pst *pst, DlRlcBoInfo *dlBoInfo)
945 bool isLcIdValid = false;
946 SchUeCb *ueCb = NULLP;
947 SchCellCb *cell = NULLP;
948 Inst inst = pst->dstInst-SCH_INST_START;
949 CmLListCp *lcLL = NULLP;
951 #ifdef CALL_FLOW_DEBUG_LOG
952 DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_DL_RLC_BO_INFO_TO_SCH\n");
955 DU_LOG("\nDEBUG --> SCH : Received RLC BO Status indication LCId [%d] BO [%d]", dlBoInfo->lcId, dlBoInfo->dataVolume);
956 cell = schCb[inst].cells[inst];
960 DU_LOG("\nERROR --> SCH : MacSchDlRlcBoInfo(): Cell does not exists");
964 GET_UE_ID(dlBoInfo->crnti, ueId);
965 ueCb = &cell->ueCb[ueId-1];
966 if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
968 DU_LOG("INFO --> SCH : DL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
972 lcId = dlBoInfo->lcId;
973 CHECK_LCID(lcId, isLcIdValid);
974 if(isLcIdValid == FALSE)
976 DU_LOG("ERROR --> SCH: LCID:%d is not valid", lcId);
980 /*Expected when theres a case of Retransmission Failure or Resetablishment
981 *By Zero BO, the RLC is informing that previous data can be cleared out
982 *Thus clearing out the LC from the Lc priority list*/
983 if(dlBoInfo->dataVolume == 0)
985 /*Check the LC is Dedicated or default and accordingly LCList will
987 if(ueCb->dlInfo.dlLcCtxt[lcId].isDedicated)
989 lcLL = &(ueCb->dlLcPrbEst.dedLcInfo->dedLcList);
993 lcLL = &(ueCb->dlLcPrbEst.defLcList);
995 handleLcLList(lcLL, lcId, DELETE);
999 if(lcId == SRB0_LCID)
1001 cell->raCb[ueId -1].msg4recvd = true;
1002 cell->raCb[ueId -1].dlMsgPduLen = dlBoInfo->dataVolume;
1007 SET_ONE_BIT(ueId, cell->boIndBitMap);
1008 if(ueCb->dlInfo.dlLcCtxt[lcId].lcId == lcId)
1010 ueCb->dlInfo.dlLcCtxt[lcId].bo = dlBoInfo->dataVolume;
1014 DU_LOG("ERROR --> SCH: LCID:%d is not configured in SCH Cb",lcId);
1019 /* Adding UE Id to list of pending UEs to be scheduled */
1020 addUeToBeScheduled(cell, ueId);
1024 /*******************************************************************
1026 * @brief Processes BSR indiation from MAC
1030 * Function : MacSchBsr
1033 * Processes DL BSR from MAC
1035 * @params[in] Pst pst
1036 * UlBufferStatusRptInd bsrInd
1037 * @return ROK - success
1040 * ****************************************************************/
1041 uint8_t MacSchBsr(Pst *pst, UlBufferStatusRptInd *bsrInd)
1043 Inst schInst = pst->dstInst-SCH_INST_START;
1044 SchCellCb *cellCb = NULLP;
1045 SchUeCb *ueCb = NULLP;
1048 #ifdef CALL_FLOW_DEBUG_LOG
1049 DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_SHORT_BSR\n");
1052 DU_LOG("\nDEBUG --> SCH : Received BSR");
1055 DU_LOG("\nERROR --> SCH : BSR Ind is empty");
1058 cellCb = schCb[schInst].cells[schInst];
1061 DU_LOG("\nERROR --> SCH : CellCb is empty");
1064 ueCb = schGetUeCb(cellCb, bsrInd->crnti);
1068 DU_LOG("\nERROR --> SCH : UeCB is empty");
1072 if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1074 DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1078 ueCb->bsrRcvd = true;
1079 /* store dataVolume per lcg in uecb */
1080 for(lcgIdx = 0; lcgIdx < bsrInd->numLcg; lcgIdx++)
1082 ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].priority = 1; //TODO: determining LCG priority?
1083 ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].dataVol = bsrInd->dataVolInfo[lcgIdx].dataVol;
1086 /* Adding UE Id to list of pending UEs to be scheduled */
1087 addUeToBeScheduled(cellCb, ueCb->ueId);
1091 /*******************************************************************
1093 * @brief Processes SR UCI indication from MAC
1097 * Function : MacSchSrUciInd
1100 * Processes SR UCI indication from MAC
1102 * @params[in] Post structure
1104 * @return ROK - success
1107 * ****************************************************************/
1108 uint8_t MacSchSrUciInd(Pst *pst, SrUciIndInfo *uciInd)
1110 Inst inst = pst->dstInst-SCH_INST_START;
1113 SchCellCb *cellCb = schCb[inst].cells[inst];
1115 #ifdef CALL_FLOW_DEBUG_LOG
1116 DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_UCI_IND_TO_SCH\n");
1119 DU_LOG("\nDEBUG --> SCH : Received SR");
1121 ueCb = schGetUeCb(cellCb, uciInd->crnti);
1123 if(ueCb->state == SCH_UE_STATE_INACTIVE)
1125 DU_LOG("\nERROR --> SCH : Crnti %d is inactive", uciInd->crnti);
1128 if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1130 DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1133 if(uciInd->numSrBits)
1135 ueCb->srRcvd = true;
1137 /* Adding UE Id to list of pending UEs to be scheduled */
1138 addUeToBeScheduled(cellCb, ueCb->ueId);
1143 /*******************************************************************
1145 * @brief Allocates requested PRBs for DL
1149 * Function : allocatePrbDl
1152 * Allocates requested PRBs in DL
1153 * Keeps track of allocated PRB (using bitmap) and remaining PRBs
1155 * @params[in] prbAlloc table
1161 * @return ROK - success
1164 * ****************************************************************/
1165 uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
1166 uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1169 uint16_t broadcastPrbStart=0, broadcastPrbEnd=0;
1170 FreePrbBlock *freePrbBlock = NULLP;
1171 CmLList *freePrbNode = NULLP;
1172 PduTxOccsaion ssbOccasion=0, sib1Occasion=0;
1173 SchDlSlotInfo *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1174 SchPrbAlloc *prbAlloc = &schDlSlotInfo->prbAlloc;
1176 /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1177 * Search for an appropriate location in PRB grid and allocate requested resources */
1178 if(*startPrb == MAX_NUM_RB)
1180 /* Check if SSB/SIB1 is also scheduled in this slot */
1181 ssbOccasion = schCheckSsbOcc(cell, slotTime);
1182 sib1Occasion = schCheckSib1Occ(cell, slotTime);
1184 if(ssbOccasion && sib1Occasion)
1186 broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
1187 broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1189 else if(ssbOccasion)
1191 broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
1192 broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB -1;
1194 else if(sib1Occasion)
1196 broadcastPrbStart = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.startPrb;
1197 broadcastPrbEnd = broadcastPrbStart + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1200 /* Iterate through all free PRB blocks */
1201 freePrbNode = prbAlloc->freePrbBlockList.first;
1204 freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1206 /* If broadcast message is scheduled in this slot, then check if its PRBs belong to the current free block.
1207 * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1208 if((ssbOccasion || sib1Occasion) &&
1209 ((broadcastPrbStart >= freePrbBlock->startPrb) && (broadcastPrbStart <= freePrbBlock->endPrb)) && \
1210 ((broadcastPrbEnd >= freePrbBlock->startPrb) && (broadcastPrbEnd <= freePrbBlock->endPrb)))
1212 /* Implmentation is done such that highest-numbered free-RB is allocated first */
1213 if((freePrbBlock->endPrb > broadcastPrbEnd) && ((freePrbBlock->endPrb - broadcastPrbEnd) >= numPrb))
1215 /* If sufficient free PRBs are available above bradcast message then,
1216 * endPrb = freePrbBlock->endPrb
1217 * startPrb = endPrb - numPrb +1;
1219 *startPrb = freePrbBlock->endPrb - numPrb +1;
1222 else if((broadcastPrbStart > freePrbBlock->startPrb) && ((broadcastPrbStart - freePrbBlock->startPrb) >= numPrb))
1224 /* If free PRBs are available below broadcast message then,
1225 * endPrb = broadcastPrbStart - 1
1226 * startPrb = endPrb - numPrb +1
1228 *startPrb = broadcastPrbStart - numPrb;
1233 freePrbNode = freePrbNode->next;
1239 /* Check if requested number of blocks can be allocated from the current block */
1240 if (freePrbBlock->numFreePrb < numPrb)
1242 freePrbNode = freePrbNode->next;
1245 *startPrb = freePrbBlock->endPrb - numPrb +1;
1250 /* If no free block can be used to allocated request number of RBs */
1251 if(*startPrb == MAX_NUM_RB)
1255 /* If startPrb is known already, check if requested PRBs are available for allocation */
1258 freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1261 DU_LOG("\nERROR --> SCH: Requested DL PRB unavailable");
1266 /* Update bitmap to allocate PRBs */
1267 for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1269 if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1271 DU_LOG("\nERROR --> SCH: fillPrbBitmap() failed for symbol [%d] in DL", symbol);
1276 /* Update the remaining number for free PRBs */
1277 removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1282 /*******************************************************************
1284 * @brief Allocates requested PRBs for UL
1288 * Function : allocatePrbUl
1291 * Allocates requested PRBs in UL
1292 * Keeps track of allocated PRB (using bitmap) and remaining PRBs
1294 * @params[in] prbAlloc table
1300 * @return ROK - success
1303 * ****************************************************************/
1304 uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
1305 uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1308 uint16_t prachStartPrb, prachNumPrb, prachEndPrb;
1309 bool isPrachOccasion;
1310 FreePrbBlock *freePrbBlock = NULLP;
1311 CmLList *freePrbNode = NULLP;
1312 SchPrbAlloc *prbAlloc = NULLP;
1316 DU_LOG("\nERROR --> SCH : allocatePrbUl(): Received cellCb is null");
1320 prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1321 /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1322 * Search for an appropriate location in PRB grid and allocate requested resources */
1323 if(*startPrb == MAX_NUM_RB)
1325 /* Check if PRACH is also scheduled in this slot */
1326 isPrachOccasion = schCheckPrachOcc(cell, slotTime);
1329 prachStartPrb = cell->cellCfg.schRachCfg.msg1FreqStart;
1330 prachNumPrb = schCalcPrachNumRb(cell);
1331 prachEndPrb = prachStartPrb + prachNumPrb -1;
1334 /* Iterate through all free PRB blocks */
1335 freePrbNode = prbAlloc->freePrbBlockList.first;
1338 freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1340 /* If PRACH is scheduled in this slot, then check if its PRBs belong to the current free block.
1341 * PRBs required for PRACH cannot be allocated to any other message */
1342 if((isPrachOccasion) &&
1343 ((prachStartPrb >= freePrbBlock->startPrb) && (prachStartPrb <= freePrbBlock->endPrb)) &&
1344 ((prachEndPrb >= freePrbBlock->startPrb) && (prachEndPrb <= freePrbBlock->endPrb)))
1346 /* Implmentation is done such that highest-numbered free-RB is allocated first */
1347 if((freePrbBlock->endPrb > prachEndPrb) && ((freePrbBlock->endPrb - prachEndPrb) >= numPrb))
1349 /* If sufficient free PRBs are available above PRACH message then,
1350 * endPrb = freePrbBlock->endPrb
1351 * startPrb = endPrb - numPrb +1;
1353 *startPrb = freePrbBlock->endPrb - numPrb +1;
1356 else if((prachStartPrb > freePrbBlock->startPrb) && ((prachStartPrb - freePrbBlock->startPrb) >= numPrb))
1358 /* If free PRBs are available below PRACH message then,
1359 * endPrb = prachStartPrb - 1
1360 * startPrb = endPrb - numPrb +1
1362 *startPrb = prachStartPrb - numPrb;
1367 freePrbNode = freePrbNode->next;
1373 /* Check if requested number of PRBs can be allocated from currect block */
1374 if(freePrbBlock->numFreePrb < numPrb)
1376 freePrbNode = freePrbNode->next;
1379 *startPrb = freePrbBlock->endPrb - numPrb +1;
1384 /* If no free block can be used to allocated requested number of RBs */
1385 if(*startPrb == MAX_NUM_RB)
1390 /* If startPrb is known already, check if requested PRBs are available for allocation */
1391 freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1394 DU_LOG("\nERROR --> SCH: Requested UL PRB unavailable");
1399 /* Update bitmap to allocate PRBs */
1400 for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1402 if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1404 DU_LOG("\nERROR --> SCH: fillPrbBitmap() failed for symbol [%d] in UL", symbol);
1409 /* Update the remaining number for free PRBs */
1410 removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1415 /*******************************************************************
1417 * @brief Add UE to ueToBeScheduled List
1421 * Function : addUeToBeScheduled
1424 * Search if UE entry present in the list
1426 * If no, add UE to the list
1428 * @params[in] Cell control block
1429 * Ue Idx to be added
1431 * @return ROK - success
1434 * ****************************************************************/
1435 uint8_t addUeToBeScheduled(SchCellCb *cell, uint8_t ueIdToAdd)
1440 /* Search if UE entry is already present in ueToBeScheduled list.
1441 * If yes, another entry for same UE not needed. Hence, return */
1442 node = cell->ueToBeScheduled.first;
1445 ueId = (uint8_t *)node->node;
1446 if(*ueId == ueIdToAdd)
1451 /* If UE entry not present already, add UE to the end of ueToBeScheduled list */
1452 SCH_ALLOC(ueId, sizeof(uint8_t));
1455 DU_LOG("\nERROR --> SCH : Memory allocation failure in addUeToBeScheduled");
1459 if(addNodeToLList(&cell->ueToBeScheduled, ueId, NULLP) != ROK)
1461 DU_LOG("\nERROR --> SCH : Failed to add ueId [%d] to cell->ueToBeScheduled list", *ueId);
1467 /*******************************************************************************
1469 * @brief Try to find Best Free Block with Max Num PRB
1473 * Function : searchLargestFreeBlock
1476 * Finds the FreeBlock with MaxNum of FREE PRB considering SSB/SIB1 ocassions.
1478 * @params[in] I/P > prbAlloc table (FreeBlock list)
1479 * I/P > Slot timing Info
1481 * I/P > Direction (UL/DL)
1484 * @return Max Number of Free PRB
1485 * If 0, then no Suitable Free Block
1487 * ********************************************************************************/
1489 uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_t *startPrb, Direction dir)
1491 uint16_t reservedPrbStart=0, reservedPrbEnd=0, maxFreePRB = 0;
1492 FreePrbBlock *freePrbBlock = NULLP;
1493 CmLList *freePrbNode = NULLP;
1494 SchPrbAlloc *prbAlloc = NULLP;
1495 bool checkOccasion = FALSE;
1497 *startPrb = 0; /*Initialize the StartPRB to zero*/
1499 /*Based on Direction, Reserved Messsages will differi.e.
1500 * DL >> SSB and SIB1 ocassions wheres for UL, PRACH ocassions to be checked
1501 * and reserved before allocation for dedicated DL/UL msg*/
1504 SchDlSlotInfo *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1505 PduTxOccsaion ssbOccasion=0, sib1Occasion=0;
1507 prbAlloc = &schDlSlotInfo->prbAlloc;
1509 ssbOccasion = schCheckSsbOcc(cell, slotTime);
1510 sib1Occasion = schCheckSib1Occ(cell, slotTime);
1512 checkOccasion = TRUE;
1513 if(ssbOccasion && sib1Occasion)
1515 reservedPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
1516 reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB + \
1517 cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1519 else if(ssbOccasion)
1521 reservedPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
1522 reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB -1;
1524 else if(sib1Occasion)
1526 reservedPrbStart = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.startPrb;
1527 reservedPrbEnd = reservedPrbStart + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
1531 checkOccasion = FALSE;
1534 else if(dir == DIR_UL)
1536 prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1538 /* Check if PRACH is also scheduled in this slot */
1539 checkOccasion = schCheckPrachOcc(cell, slotTime);
1542 reservedPrbStart = cell->cellCfg.schRachCfg.msg1FreqStart;
1543 reservedPrbEnd = reservedPrbStart + (schCalcPrachNumRb(cell)) -1;
1548 DU_LOG("\nERROR --> SCH: Invalid Direction!");
1549 return (maxFreePRB);
1552 freePrbNode = prbAlloc->freePrbBlockList.first;
1555 freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1557 /*For block with same numFreeBlocks, choose the one with HighestPRB range
1558 *Since FreeBLockList are arranged in Descending order of PRB range thus Skipping this block*/
1559 if(maxFreePRB >= freePrbBlock->numFreePrb)
1562 freePrbNode = freePrbNode->next;
1566 /* If Broadcast/Prach message is scheduled in this slot, then check if its PRBs belong to the current free block.
1567 * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1569 ((reservedPrbStart >= freePrbBlock->startPrb) && (reservedPrbStart <= freePrbBlock->endPrb)) && \
1570 ((reservedPrbEnd >= freePrbBlock->startPrb) && (reservedPrbEnd <= freePrbBlock->endPrb)))
1573 /* Implmentation is done such that highest-numbered free-RB is Checked first
1574 and freePRB in this block is greater than Max till now */
1575 if((freePrbBlock->endPrb > reservedPrbEnd) && ((freePrbBlock->endPrb - reservedPrbEnd) > maxFreePRB))
1577 /* If sufficient free PRBs are available above reserved message*/
1578 *startPrb = reservedPrbEnd + 1;
1579 maxFreePRB = (freePrbBlock->endPrb - reservedPrbEnd);
1581 /*Also check the other freeBlock (i.e. Above the reserved message) for MAX FREE PRB*/
1582 if((reservedPrbStart > freePrbBlock->startPrb) && ((reservedPrbStart - freePrbBlock->startPrb) > maxFreePRB))
1584 /* If free PRBs are available below reserved message*/
1585 *startPrb = freePrbBlock->startPrb;
1586 maxFreePRB = (reservedPrbStart - freePrbBlock->startPrb);
1591 if(maxFreePRB < freePrbBlock->numFreePrb)
1593 *startPrb = freePrbBlock->startPrb;
1594 maxFreePRB = freePrbBlock->numFreePrb;
1598 freePrbNode = freePrbNode->next;
1603 /*******************************************************************************
1605 * @brief This function is used to send Slice Cfg rsp to MAC
1609 * Function : SchSendSliceCfgRspToMac
1612 * function is used to send Slice Cfg rsp to MAC
1614 * @params[in] Pst *pst, SchSliceCfgRsp sliceCfgRsp
1618 * ********************************************************************************/
1619 void SchSendSliceCfgRspToMac(Inst inst, SchSliceCfgRsp sliceCfgRsp)
1623 memset(&rspPst, 0, sizeof(Pst));
1624 FILL_PST_SCH_TO_MAC(rspPst, inst);
1625 rspPst.event = EVENT_SLICE_CFG_RSP_TO_MAC;
1627 SchSliceCfgRspOpts[rspPst.selector](&rspPst, &sliceCfgRsp);
1630 /*******************************************************************************
1632 * @brief fill slice configuration response
1636 * Function : fillSliceCfgRsp
1639 * fill slice configuration response
1641 * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t count
1647 * ********************************************************************************/
1648 uint8_t fillSliceCfgRsp(bool sliceReCfg, SchSliceCfg *storedSliceCfg, SchCellCb *cellCb, SchSliceCfgReq *schSliceCfgReq, SchSliceCfgRsp *schSliceCfgRsp, uint8_t *count)
1650 bool sliceFound = false;
1651 uint8_t cfgIdx = 0, sliceIdx = 0;
1653 schSliceCfgRsp->numSliceCfgRsp = schSliceCfgReq->numOfConfiguredSlice;
1654 SCH_ALLOC(schSliceCfgRsp->listOfSliceCfgRsp, schSliceCfgRsp->numSliceCfgRsp * sizeof(SliceRsp*));
1655 if(schSliceCfgRsp->listOfSliceCfgRsp == NULLP)
1657 DU_LOG("\nERROR --> SCH : Memory allocation failed at fillSliceCfgRsp");
1661 for(cfgIdx = 0; cfgIdx<schSliceCfgRsp->numSliceCfgRsp ; cfgIdx++)
1664 /* Here comparing the slice cfg request with the slice stored in cellCfg */
1665 if(sliceReCfg != true)
1667 for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList.numSliceSupport; sliceIdx++)
1669 if(!memcmp(&schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList.snssai[sliceIdx], sizeof(Snssai)))
1679 /* Here comparing the slice cfg request with the slice stored in SchDb */
1680 if(storedSliceCfg->listOfConfirguration)
1682 for(sliceIdx = 0; sliceIdx<storedSliceCfg->numOfSliceConfigured; sliceIdx++)
1684 if(!memcmp(&schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai, &storedSliceCfg->listOfConfirguration[sliceIdx]->snssai,\
1695 SCH_ALLOC(schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx], sizeof(SliceRsp));
1696 if(schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx] == NULLP)
1698 DU_LOG("\nERROR --> SCH : Failed to allocate memory in fillSliceCfgRsp");
1703 schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->snssai = schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai;
1704 if(sliceFound == true)
1705 schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->rsp = RSP_OK;
1708 schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->rsp = RSP_NOK;
1709 schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->cause = SLICE_NOT_FOUND;
1715 /*******************************************************************************
1717 * @brief This function is used to store the slice configuration Sch DB
1721 * Function : addSliceCfgInSchDb
1724 * function is used to store the slice configuration Sch DB
1726 * @params[in] SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq,
1727 * SchSliceCfgRsp cfgRsp, uint8_t count
1733 * ********************************************************************************/
1734 uint8_t addSliceCfgInSchDb(SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq, SchSliceCfgRsp cfgRsp, uint8_t count)
1736 uint8_t cfgIdx = 0, sliceIdx = 0;
1740 storeSliceCfg->numOfSliceConfigured = count;
1741 SCH_ALLOC(storeSliceCfg->listOfConfirguration, storeSliceCfg->numOfSliceConfigured * sizeof(SchRrmPolicyOfSlice*));
1742 if(storeSliceCfg->listOfConfirguration == NULLP)
1744 DU_LOG("\nERROR --> SCH : Failed to allocate memory in addSliceCfgInSchDb");
1748 for(cfgIdx = 0; cfgIdx<storeSliceCfg->numOfSliceConfigured; cfgIdx++)
1750 if(cfgRsp.listOfSliceCfgRsp[cfgIdx]->rsp == RSP_OK)
1752 SCH_ALLOC(storeSliceCfg->listOfConfirguration[sliceIdx], sizeof(SchRrmPolicyOfSlice));
1753 if(storeSliceCfg->listOfConfirguration[sliceIdx] == NULLP)
1755 DU_LOG("\nERROR --> SCH : Failed to allocate memory in addSliceCfgInSchDb");
1759 SCH_ALLOC(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1760 if(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo == NULLP)
1762 DU_LOG("\nERROR --> SCH : Failed to allocate memory in addSliceCfgInSchDb");
1766 memcpy(&storeSliceCfg->listOfConfirguration[sliceIdx]->snssai, &cfgReq->listOfConfirguration[sliceIdx]->snssai, sizeof(Snssai));
1767 memcpy(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo, cfgReq->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo,
1768 sizeof(SchRrmPolicyRatio));
1776 /*******************************************************************************
1778 * @brief This function is used to free the slice cfg and re cfg request pointer
1782 * Function : freeSchSliceCfgReq
1785 * function is used to free the slice cfg and re cfg request pointer
1787 * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1792 * ********************************************************************************/
1793 void freeSchSliceCfgReq(SchSliceCfgReq *cfgReq)
1799 if(cfgReq->numOfConfiguredSlice)
1801 for(cfgIdx = 0; cfgIdx<cfgReq->numOfConfiguredSlice; cfgIdx++)
1803 if(cfgReq->listOfConfirguration[cfgIdx])
1805 SCH_FREE(cfgReq->listOfConfirguration[cfgIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1806 SCH_FREE(cfgReq->listOfConfirguration[cfgIdx], sizeof(SchRrmPolicyOfSlice));
1809 SCH_FREE(cfgReq->listOfConfirguration, cfgReq->numOfConfiguredSlice * sizeof(SchRrmPolicyOfSlice*));
1811 SCH_FREE(cfgReq, sizeof(SchSliceCfgReq));
1814 /*******************************************************************************
1816 * @brief This function is used to store the slice configuration Sch DB
1820 * Function : MacSchSliceCfgReq
1823 * function is used to store the slice configuration Sch DB
1825 * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1831 * ********************************************************************************/
1832 uint8_t MacSchSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
1835 Inst inst = pst->dstInst - SCH_INST_START;
1836 SchSliceCfgRsp sliceCfgRsp;
1838 DU_LOG("\nINFO --> SCH : Received Slice Cfg request from MAC");
1841 if(schSliceCfgReq->listOfConfirguration)
1843 /* filling the slice configuration response of each slice */
1844 if(fillSliceCfgRsp(false, NULLP, schCb[inst].cells[0], schSliceCfgReq, &sliceCfgRsp, &count) != ROK)
1846 DU_LOG("\nERROR --> SCH : Failed to fill the slice cfg rsp");
1850 if(addSliceCfgInSchDb(&schCb[inst].sliceCfg, schSliceCfgReq, sliceCfgRsp, count) != ROK)
1852 DU_LOG("\nERROR --> SCH : Failed to add slice cfg in sch database");
1855 freeSchSliceCfgReq(schSliceCfgReq);
1856 SchSendSliceCfgRspToMac(inst, sliceCfgRsp);
1861 DU_LOG("\nERROR --> SCH : Received SchSliceCfgReq is NULL");
1866 /*******************************************************************************
1868 * @brief This function is used to store the slice reconfiguration Sch DB
1872 * Function : modifySliceCfgInSchDb
1875 * function is used to store the slice re configuration Sch DB
1877 * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1883 * ********************************************************************************/
1884 uint8_t modifySliceCfgInSchDb(SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq, SchSliceCfgRsp cfgRsp, uint8_t count)
1886 uint8_t cfgIdx = 0, sliceIdx = 0;
1890 if(storeSliceCfg->listOfConfirguration == NULLP)
1892 DU_LOG("\nINFO --> SCH : Memory allocation failed in modifySliceCfgInSchDb");
1896 for(cfgIdx = 0; cfgIdx<cfgReq->numOfConfiguredSlice; cfgIdx++)
1898 if(cfgRsp.listOfSliceCfgRsp[cfgIdx]->rsp == RSP_OK)
1900 for(sliceIdx = 0; sliceIdx<storeSliceCfg->numOfSliceConfigured; sliceIdx++)
1902 if(!memcmp(&storeSliceCfg->listOfConfirguration[sliceIdx]->snssai, &cfgReq->listOfConfirguration[cfgIdx]->snssai, sizeof(Snssai)))
1904 memcpy(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo, cfgReq->listOfConfirguration[cfgIdx]->rrmPolicyRatioInfo,
1905 sizeof(SchRrmPolicyRatio));
1912 freeSchSliceCfgReq(cfgReq);
1915 /*******************************************************************************
1917 * @brief This function is used to send Slice re Cfg rsp to MAC
1921 * Function : SchSendSliceCfgRspToMac
1924 * function is used to send Slice re Cfg rsp to MAC
1926 * @params[in] Pst *pst, SchSliceCfgRsp schSliceReCfgRsp
1930 * ********************************************************************************/
1931 void SchSendSliceReCfgRspToMac(Inst inst, SchSliceCfgRsp schSliceReCfgRsp)
1935 memset(&rspPst, 0, sizeof(Pst));
1936 FILL_PST_SCH_TO_MAC(rspPst, inst);
1937 rspPst.event = EVENT_SLICE_RECFG_RSP_TO_MAC;
1939 SchSliceReCfgRspOpts[rspPst.selector](&rspPst, &schSliceReCfgRsp);
1941 /*******************************************************************************
1943 * @brief This function is used to store the slice reconfiguration Sch DB
1947 * Function : MacSchSliceReCfgReq
1950 * function is used to store the slice re configuration Sch DB
1952 * @params[in] Pst *pst, SchSliceCfgReq *schSliceReCfgReq
1958 * ********************************************************************************/
1959 uint8_t MacSchSliceReCfgReq(Pst *pst, SchSliceCfgReq *schSliceReCfgReq)
1962 Inst inst = pst->dstInst - SCH_INST_START;
1963 SchSliceCfgRsp schSliceReCfgRsp;
1965 DU_LOG("\nINFO --> SCH : Received Slice ReCfg request from MAC");
1966 if(schSliceReCfgReq)
1968 if(schSliceReCfgReq->listOfConfirguration)
1970 /* filling the slice configuration response of each slice */
1971 if(fillSliceCfgRsp(true, &schCb[inst].sliceCfg, NULLP, schSliceReCfgReq, &schSliceReCfgRsp, &count) != ROK)
1973 DU_LOG("\nERROR --> SCH : Failed to fill sch slice cfg response");
1977 /* Modify the slice configuration stored in schCb */
1978 if(modifySliceCfgInSchDb(&schCb[inst].sliceCfg, schSliceReCfgReq, schSliceReCfgRsp, count) != ROK)
1980 DU_LOG("\nERROR --> SCH : Failed to modify slice cfg of SchDb");
1983 SchSendSliceReCfgRspToMac(inst, schSliceReCfgRsp);
1988 DU_LOG("\nERROR --> SCH : Received SchSliceCfgReq is NULL");
1993 /****************************************************************************
1995 * @brief Stores the Paging Configuration from DU APP in CellCb
1999 * Function : schProcPagingParam
2002 * Process the Paging Configuration when FirstPDCCHMonitoring for
2003 * Paging Ocassion is not present.
2005 * As per 38.304 Sec 7.1,
2006 * "When firstPDCCH-MonitoringOccasionOfPO is present, the
2007 * starting PDCCH monitoring occasion number of (i_s + 1)th PO is the
2008 * (i_s + 1)th value of the firstPDCCHMonitoringOccasionOfPO
2009 * parameter; otherwise, it is equal to i_s * S."
2010 * "S = number of actual transmitted SSBs determined according
2011 * to ssb-PositionsInBurst in SIB1"
2013 * @params[in] SchCellCb *cell
2017 *************************************************************************/
2018 void schProcPagingCfg(SchCellCb *cell)
2020 PageCfg *pageCfgRcvd = NULL;
2023 pageCfgRcvd = &(cell->cellCfg.sib1SchCfg.pageCfg);
2025 if(pageCfgRcvd->poPresent == TRUE)
2027 /*Fetching first Pdcch Monitoring Occasion for SFN (i_s + 1)th*/
2028 for(i_sIdx = 0; i_sIdx < pageCfgRcvd->numPO; i_sIdx++)
2030 cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pageCfgRcvd->pagingOcc[i_sIdx] / MAX_SYMB_PER_SLOT ;
2031 if ((pageCfgRcvd->pagingOcc[i_sIdx] % MAX_SYMB_PER_SLOT) != 0 )
2033 cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot++;
2036 cell->pageCb.pagMonOcc[i_sIdx].frameOffset = 0;
2042 schCfgPdcchMonOccOfPO(cell);
2046 /****************************************************************************
2048 * @brief Calculate PO if not present in Configuration
2052 * Function : schCfgPdcchMonOccOfPO
2054 * Functionality: In this function, PO are calculated i_s * S because
2055 * FirstPDCCHMonitoring_ForPO is not present.
2057 * @params[in] SchCellCb *cellCb
2061 *************************************************************************/
2062 void schCfgPdcchMonOccOfPO(SchCellCb *cell)
2064 uint8_t cnt = 0, incr = 1, i_sIdx = 0, frameOffSet = 0;
2065 uint8_t nsValue = cell->cellCfg.sib1SchCfg.pageCfg.numPO;
2066 uint8_t totalNumSsb = cell->cellCfg.ssbSchCfg.totNumSsb;
2067 SlotTimingInfo tmpTimingInfo, pdcchTime;
2069 /*Starting with First Sfn and slot*/
2070 tmpTimingInfo.sfn = 0;
2071 tmpTimingInfo.slot = 0;
2073 pdcchTime = tmpTimingInfo;
2075 while(i_sIdx < nsValue)
2077 /*Increment frame Offset if PO falls on next SFN*/
2078 if(pdcchTime.sfn != tmpTimingInfo.sfn)
2082 pdcchTime = tmpTimingInfo;
2083 schIncrSlot(&(tmpTimingInfo), incr, cell->numSlots);
2087 cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2088 cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2094 if((cnt == totalNumSsb) && (i_sIdx < MAX_PO_PER_PF))
2096 cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2097 cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2105 /****************************************************************************
2107 * @brief Storing the paging information in SCH database
2111 * Function : schAddPagingIndtoList
2113 * Functionality: Storing the paging information in SCH database
2115 * @params[in] CmLListCp *storedPageList, CmLList *pageIndInfo
2117 * @return ROK - sucess
2120 *************************************************************************/
2121 uint8_t schAddPagingIndtoList(CmLListCp *storedPageList,void * pageIndInfo)
2123 CmLList *firstNodeOfList = NULLP;
2124 CmLList *currentNodeInfo = NULLP;
2125 SchPageInfo *tempNode = NULLP, *recvdNode = NULLP;
2127 recvdNode = (SchPageInfo*) pageIndInfo;
2128 CM_LLIST_FIRST_NODE(storedPageList,firstNodeOfList);
2130 SCH_ALLOC(currentNodeInfo, sizeof(CmLList));
2131 if(!currentNodeInfo)
2133 DU_LOG("\nERROR --> SCH : schAddPagingIndtoList() : Memory allocation failed");
2137 currentNodeInfo->node = (PTR)pageIndInfo;
2138 while(firstNodeOfList)
2140 tempNode = (SchPageInfo*)(firstNodeOfList->node);
2141 if ((recvdNode->TxTime.slot < tempNode->TxTime.slot))
2143 cmLListInsCrnt(storedPageList, currentNodeInfo);
2146 else if ((recvdNode->TxTime.slot == tempNode->TxTime.slot))
2148 DU_LOG("\nERROR --> SCH : schAddPagingIndtoList() : Slot[%d] is already present in the list", recvdNode->TxTime.slot);
2153 CM_LLIST_NEXT_NODE(storedPageList, firstNodeOfList);
2157 if(!firstNodeOfList)
2159 cmLListAdd2Tail(storedPageList, currentNodeInfo);
2161 DU_LOG("\nINFO --> SCH : Paging information is stored successfully");
2165 /****************************************************************************
2167 * @brief Process paging indication at SCH recevied form MAC
2171 * Function : MacSchPagingInd
2173 * Functionality: Process paging indication at SCH recevied form MAC
2175 * @params[in] Pst *pst, SchPageInd *pageInd
2179 *************************************************************************/
2180 uint8_t MacSchPagingInd(Pst *pst, SchPageInd *pageInd)
2182 uint8_t ret = RFAILED;
2183 uint16_t cellIdx = 0;
2184 Inst inst = pst->dstInst - SCH_INST_START;
2185 SchCellCb *cellCb = NULLP;
2186 SchPageInfo *pageInfo = NULLP;
2190 DU_LOG("\nINFO --> SCH : Received paging indication form MAC for cellId[%d]",pageInd->cellId);
2193 for(cellIdx = 0; cellIdx < MAX_NUM_CELL; cellIdx++)
2195 if((schCb[inst].cells[cellIdx]) && (schCb[inst].cells[cellIdx]->cellId == pageInd->cellId))
2197 cellCb = schCb[inst].cells[cellIdx];
2203 if(pageInd->i_s > cellCb->cellCfg.sib1SchCfg.pageCfg.numPO)
2205 DU_LOG("\nERROR --> SCH : MacSchPagingInd(): i_s should not be greater than number of paging occasion");
2209 SCH_ALLOC(pageInfo, sizeof(SchPageInfo));
2212 pageInfo->pf = pageInd->pf;
2213 pageInfo->i_s = pageInd->i_s;
2214 pageInfo->TxTime.cellId = pageInd->cellId;
2215 pageInfo->TxTime.sfn = (pageInd->pf + cellCb->pageCb.pagMonOcc[pageInd->i_s].frameOffset) % MAX_SFN;
2216 pageInfo->TxTime.slot = cellCb->pageCb.pagMonOcc[pageInd->i_s].pagingOccSlot;
2217 pageInfo->mcs = DEFAULT_MCS;
2218 pageInfo->msgLen = pageInd->pduLen;
2219 SCH_ALLOC(pageInfo->pagePdu, pageInfo->msgLen);
2220 if(!pageInfo->pagePdu)
2222 DU_LOG("\nERROR --> SCH : MacSchPagingInd(): Failed to allocate memory");
2226 memcpy(pageInfo->pagePdu, pageInd->pagePdu, pageInfo->msgLen);
2227 ret = schAddPagingIndtoList(&cellCb->pageCb.pageIndInfoRecord[pageInfo->TxTime.sfn], pageInfo);
2230 DU_LOG("\nERROR --> SCH : MacSchPagingInd(): Failed to store paging record");
2236 DU_LOG("\nERROR --> SCH : MacSchPagingInd(): Failed to allocate memory");
2242 DU_LOG("\nERROR --> SCH : Cell ID [%d] not found", pageInd->cellId);
2244 SCH_FREE(pageInd->pagePdu, pageInd->pduLen);
2245 SCH_FREE(pageInd, sizeof(SchPageInd));
2249 DU_LOG("\nERROR --> SCH : MacSchPagingInd(): Received null pointer");
2253 /**********************************************************************
2255 **********************************************************************/