+/*******************************************************************
+ *
+ * @brief Processes DL RLC BO info from MAC
+ *
+ * @details
+ *
+ * Function : MacSchDlRlcBoInfo
+ *
+ * Functionality:
+ * Processes DL RLC BO info from MAC
+ *
+ * @params[in]
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t MacSchDlRlcBoInfo(Pst *pst, DlRlcBoInfo *dlBoInfo)
+{
+ uint8_t lcId = 0;
+ uint16_t ueId = 0;
+ bool isLcIdValid = false;
+ SchUeCb *ueCb = NULLP;
+ SchCellCb *cell = NULLP;
+ Inst inst = pst->dstInst-SCH_INST_START;
+ CmLListCp *lcLL = NULLP;
+
+#ifdef CALL_FLOW_DEBUG_LOG
+ DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_DL_RLC_BO_INFO_TO_SCH\n");
+#endif
+
+ DU_LOG("\nDEBUG --> SCH : Received RLC BO Status indication LCId [%d] BO [%d]", dlBoInfo->lcId, dlBoInfo->dataVolume);
+ cell = schCb[inst].cells[inst];
+
+ if(cell == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH : MacSchDlRlcBoInfo(): Cell does not exists");
+ return RFAILED;
+ }
+
+ GET_UE_IDX(dlBoInfo->crnti, ueId);
+ ueCb = &cell->ueCb[ueId-1];
+ lcId = dlBoInfo->lcId;
+ CHECK_LCID(lcId, isLcIdValid);
+ if(isLcIdValid == FALSE)
+ {
+ DU_LOG("ERROR --> SCH: LCID:%d is not valid", lcId);
+ return RFAILED;
+ }
+
+ /*Expected when theres a case of Retransmission Failure or Resetablishment
+ *By Zero BO, the RLC is informing that previous data can be cleared out
+ *Thus clearing out the LC from the Lc priority list*/
+ if(dlBoInfo->dataVolume == 0)
+ {
+ /*Check the LC is Dedicated or default and accordingly LCList will
+ * be used*/
+ if(ueCb->dlInfo.dlLcCtxt[lcId].isDedicated)
+ {
+ lcLL = &(ueCb->dlLcPrbEst.dedLcInfo->dedLcList);
+ }
+ else
+ {
+ lcLL = &(ueCb->dlLcPrbEst.defLcList);
+ }
+ handleLcLList(lcLL, lcId, DELETE);
+ return ROK;
+ }
+
+ if(lcId == SRB0_LCID)
+ {
+ cell->raCb[ueId -1].msg4recvd = true;
+ cell->raCb[ueId -1].dlMsgPduLen = dlBoInfo->dataVolume;
+
+ }
+ else
+ {
+ /* TODO : These part of changes will be corrected during DL scheduling as
+ * per K0 - K1 -K2 */
+ SET_ONE_BIT(ueId, cell->boIndBitMap);
+ if(ueCb->dlInfo.dlLcCtxt[lcId].lcId == lcId)
+ {
+ ueCb->dlInfo.dlLcCtxt[lcId].bo = dlBoInfo->dataVolume;
+ }
+ else
+ {
+ DU_LOG("ERROR --> SCH: LCID:%d is not configured in SCH Cb",lcId);
+ return RFAILED;
+ }
+ }
+
+ /* Adding UE Id to list of pending UEs to be scheduled */
+ addUeToBeScheduled(cell, ueId);
+ return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Processes BSR indiation from MAC
+ *
+ * @details
+ *
+ * Function : MacSchBsr
+ *
+ * Functionality:
+ * Processes DL BSR from MAC
+ *
+ * @params[in] Pst pst
+ * UlBufferStatusRptInd bsrInd
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t MacSchBsr(Pst *pst, UlBufferStatusRptInd *bsrInd)
+{
+ Inst schInst = pst->dstInst-SCH_INST_START;
+ SchCellCb *cellCb = NULLP;
+ SchUeCb *ueCb = NULLP;
+ uint8_t lcgIdx = 0;
+
+#ifdef CALL_FLOW_DEBUG_LOG
+ DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_SHORT_BSR\n");
+#endif
+
+ DU_LOG("\nDEBUG --> SCH : Received BSR");
+ cellCb = schCb[schInst].cells[schInst];
+ ueCb = schGetUeCb(cellCb, bsrInd->crnti);
+
+ ueCb->bsrRcvd = true;
+ /* store dataVolume per lcg in uecb */
+ for(lcgIdx = 0; lcgIdx < bsrInd->numLcg; lcgIdx++)
+ {
+ ueCb->bsrInfo[lcgIdx].priority = 1; //TODO: determining LCG priority?
+ ueCb->bsrInfo[lcgIdx].dataVol = bsrInd->dataVolInfo[lcgIdx].dataVol;
+ }
+
+ /* Adding UE Id to list of pending UEs to be scheduled */
+ addUeToBeScheduled(cellCb, ueCb->ueIdx);
+ return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Processes SR UCI indication from MAC
+ *
+ * @details
+ *
+ * Function : MacSchSrUciInd
+ *
+ * Functionality:
+ * Processes SR UCI indication from MAC
+ *
+ * @params[in] Post structure
+ * UCI Indication
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t MacSchSrUciInd(Pst *pst, SrUciIndInfo *uciInd)
+{
+ Inst inst = pst->dstInst-SCH_INST_START;
+
+ SchUeCb *ueCb;
+ SchCellCb *cellCb = schCb[inst].cells[inst];
+
+#ifdef CALL_FLOW_DEBUG_LOG
+ DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_UCI_IND_TO_SCH\n");
+#endif
+
+ DU_LOG("\nDEBUG --> SCH : Received SR");
+
+ ueCb = schGetUeCb(cellCb, uciInd->crnti);
+
+ if(uciInd->numSrBits)
+ {
+ ueCb->srRcvd = true;
+
+ /* Adding UE Id to list of pending UEs to be scheduled */
+ addUeToBeScheduled(cellCb, ueCb->ueIdx);
+ }
+ return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Allocates requested PRBs for DL
+ *
+ * @details
+ *
+ * Function : allocatePrbDl
+ *
+ * Functionality:
+ * Allocates requested PRBs in DL
+ * Keeps track of allocated PRB (using bitmap) and remaining PRBs
+ *
+ * @params[in] prbAlloc table
+ * Start symbol
+ * Number of symbols
+ * Start PRB
+ * Number of PRBs
+ *
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
+ uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
+{
+ uint8_t symbol = 0;
+ uint16_t broadcastPrbStart=0, broadcastPrbEnd=0;
+ FreePrbBlock *freePrbBlock = NULLP;
+ CmLList *freePrbNode = NULLP;
+ PduTxOccsaion ssbOccasion=0, sib1Occasion=0;
+ SchDlSlotInfo *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
+ SchPrbAlloc *prbAlloc = &schDlSlotInfo->prbAlloc;
+
+ /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
+ * Search for an appropriate location in PRB grid and allocate requested resources */
+ if(*startPrb == MAX_NUM_RB)
+ {
+ /* Check if SSB/SIB1 is also scheduled in this slot */
+ ssbOccasion = schCheckSsbOcc(cell, slotTime);
+ sib1Occasion = schCheckSib1Occ(cell, slotTime);
+
+ if(ssbOccasion && sib1Occasion)
+ {
+ broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
+ broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
+ }
+ else if(ssbOccasion)
+ {
+ broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
+ broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB -1;
+ }
+ else if(sib1Occasion)
+ {
+ broadcastPrbStart = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.startPrb;
+ broadcastPrbEnd = broadcastPrbStart + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
+ }
+
+ /* Iterate through all free PRB blocks */
+ freePrbNode = prbAlloc->freePrbBlockList.first;
+ while(freePrbNode)
+ {
+ freePrbBlock = (FreePrbBlock *)freePrbNode->node;
+
+ /* If broadcast message is scheduled in this slot, then check if its PRBs belong to the current free block.
+ * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
+ if((ssbOccasion || sib1Occasion) &&
+ ((broadcastPrbStart >= freePrbBlock->startPrb) && (broadcastPrbStart <= freePrbBlock->endPrb)) && \
+ ((broadcastPrbEnd >= freePrbBlock->startPrb) && (broadcastPrbEnd <= freePrbBlock->endPrb)))
+ {
+ /* Implmentation is done such that highest-numbered free-RB is allocated first */
+ if((freePrbBlock->endPrb > broadcastPrbEnd) && ((freePrbBlock->endPrb - broadcastPrbEnd) >= numPrb))
+ {
+ /* If sufficient free PRBs are available above bradcast message then,
+ * endPrb = freePrbBlock->endPrb
+ * startPrb = endPrb - numPrb +1;
+ */
+ *startPrb = freePrbBlock->endPrb - numPrb +1;
+ break;
+ }
+ else if((broadcastPrbStart > freePrbBlock->startPrb) && ((broadcastPrbStart - freePrbBlock->startPrb) >= numPrb))
+ {
+ /* If free PRBs are available below broadcast message then,
+ * endPrb = broadcastPrbStart - 1
+ * startPrb = endPrb - numPrb +1
+ */
+ *startPrb = broadcastPrbStart - numPrb;
+ break;
+ }
+ else
+ {
+ freePrbNode = freePrbNode->next;
+ continue;
+ }
+ }
+ else
+ {
+ /* Check if requested number of blocks can be allocated from the current block */
+ if (freePrbBlock->numFreePrb < numPrb)
+ {
+ freePrbNode = freePrbNode->next;
+ continue;
+ }
+ *startPrb = freePrbBlock->endPrb - numPrb +1;
+ break;
+ }
+ }
+
+ /* If no free block can be used to allocated request number of RBs */
+ if(*startPrb == MAX_NUM_RB)
+ return RFAILED;
+ }
+
+ /* If startPrb is known already, check if requested PRBs are available for allocation */
+ else
+ {
+ freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
+ if(!freePrbNode)
+ {
+ DU_LOG("\nERROR --> SCH: Requested DL PRB unavailable");
+ return RFAILED;
+ }
+ }
+
+ /* Update bitmap to allocate PRBs */
+ for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
+ {
+ if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
+ {
+ DU_LOG("\nERROR --> SCH: fillPrbBitmap() failed for symbol [%d] in DL", symbol);
+ return RFAILED;
+ }
+ }
+
+ /* Update the remaining number for free PRBs */
+ removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
+
+ return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Allocates requested PRBs for UL
+ *
+ * @details
+ *
+ * Function : allocatePrbUl
+ *
+ * Functionality:
+ * Allocates requested PRBs in UL
+ * Keeps track of allocated PRB (using bitmap) and remaining PRBs
+ *
+ * @params[in] prbAlloc table
+ * Start symbol
+ * Number of symbols
+ * Start PRB
+ * Number of PRBs
+ *
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
+ uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
+{
+ uint8_t symbol = 0;
+ uint16_t prachStartPrb, prachNumPrb, prachEndPrb;
+ bool isPrachOccasion;
+ FreePrbBlock *freePrbBlock = NULLP;
+ CmLList *freePrbNode = NULLP;
+ SchPrbAlloc *prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
+
+ /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
+ * Search for an appropriate location in PRB grid and allocate requested resources */
+ if(*startPrb == MAX_NUM_RB)
+ {
+ /* Check if PRACH is also scheduled in this slot */
+ isPrachOccasion = schCheckPrachOcc(cell, slotTime);
+ if(isPrachOccasion)
+ {
+ prachStartPrb = cell->cellCfg.schRachCfg.msg1FreqStart;
+ prachNumPrb = schCalcPrachNumRb(cell);
+ prachEndPrb = prachStartPrb + prachNumPrb -1;
+ }
+
+ /* Iterate through all free PRB blocks */
+ freePrbNode = prbAlloc->freePrbBlockList.first;
+ while(freePrbNode)
+ {
+ freePrbBlock = (FreePrbBlock *)freePrbNode->node;
+
+ /* If PRACH is scheduled in this slot, then check if its PRBs belong to the current free block.
+ * PRBs required for PRACH cannot be allocated to any other message */
+ if((isPrachOccasion) &&
+ ((prachStartPrb >= freePrbBlock->startPrb) && (prachStartPrb <= freePrbBlock->endPrb)) &&
+ ((prachEndPrb >= freePrbBlock->startPrb) && (prachEndPrb <= freePrbBlock->endPrb)))
+ {
+ /* Implmentation is done such that highest-numbered free-RB is allocated first */
+ if((freePrbBlock->endPrb > prachEndPrb) && ((freePrbBlock->endPrb - prachEndPrb) >= numPrb))
+ {
+ /* If sufficient free PRBs are available above PRACH message then,
+ * endPrb = freePrbBlock->endPrb
+ * startPrb = endPrb - numPrb +1;
+ */
+ *startPrb = freePrbBlock->endPrb - numPrb +1;
+ break;
+ }
+ else if((prachStartPrb > freePrbBlock->startPrb) && ((prachStartPrb - freePrbBlock->startPrb) >= numPrb))
+ {
+ /* If free PRBs are available below PRACH message then,
+ * endPrb = prachStartPrb - 1
+ * startPrb = endPrb - numPrb +1
+ */
+ *startPrb = prachStartPrb - numPrb;
+ break;
+ }
+ else
+ {
+ freePrbNode = freePrbNode->next;
+ continue;
+ }
+ }
+ else
+ {
+ /* Check if requested number of PRBs can be allocated from currect block */
+ if(freePrbBlock->numFreePrb < numPrb)
+ {
+ freePrbNode = freePrbNode->next;
+ continue;
+ }
+ *startPrb = freePrbBlock->endPrb - numPrb +1;
+ break;
+ }
+ }
+
+ /* If no free block can be used to allocated requested number of RBs */
+ if(*startPrb == MAX_NUM_RB)
+ return RFAILED;
+ }
+ else
+ {
+ /* If startPrb is known already, check if requested PRBs are available for allocation */
+ freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
+ if(!freePrbNode)
+ {
+ DU_LOG("\nERROR --> SCH: Requested UL PRB unavailable");
+ return RFAILED;
+ }
+ }
+
+ /* Update bitmap to allocate PRBs */
+ for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
+ {
+ if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
+ {
+ DU_LOG("\nERROR --> SCH: fillPrbBitmap() failed for symbol [%d] in UL", symbol);
+ return RFAILED;
+ }
+ }
+
+ /* Update the remaining number for free PRBs */
+ removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
+
+ return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Add UE to ueToBeScheduled List
+ *
+ * @details
+ *
+ * Function : addUeToBeScheduled
+ *
+ * Functionality:
+ * Search if UE entry present in the list
+ * If yes, return.
+ * If no, add UE to the list
+ *
+ * @params[in] Cell control block
+ * Ue Idx to be added
+ *
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t addUeToBeScheduled(SchCellCb *cell, uint8_t ueIdToAdd)
+{
+ uint8_t *ueId;
+ CmLList *node;
+
+ /* Search if UE entry is already present in ueToBeScheduled list.
+ * If yes, another entry for same UE not needed. Hence, return */
+ node = cell->ueToBeScheduled.first;
+ while(node)
+ {
+ ueId = (uint8_t *)node->node;
+ if(*ueId == ueIdToAdd)
+ return ROK;
+ node = node->next;
+ }
+
+ /* If UE entry not present already, add UE to the end of ueToBeScheduled list */
+ SCH_ALLOC(ueId, sizeof(uint8_t));
+ if(!ueId)
+ {
+ DU_LOG("\nERROR --> SCH : Memory allocation failure in addUeToBeScheduled");
+ return RFAILED;
+ }
+ *ueId = ueIdToAdd;
+ if(addNodeToLList(&cell->ueToBeScheduled, ueId, NULLP) != ROK)
+ {
+ DU_LOG("\nERROR --> SCH : Failed to add UeIdx to cell->ueToBeScheduled list");
+ return RFAILED;
+ }
+ return ROK;
+}
+
+/*******************************************************************************
+ *
+ * @brief Try to find Best Free Block with Max Num PRB
+ *
+ * @details
+ *
+ * Function : searchLargestFreeBlockDL
+ *
+ * Functionality:
+ * Finds the FreeBlock with MaxNum of FREE PRB considering SSB/SIB1 ocassions.
+ *
+ * @params[in] I/P > prbAlloc table (FreeBlock list)
+ * I/P > Slot timing Info
+ * O/P > Start PRB
+ *
+ *
+ * @return Max Number of Free PRB
+ * If 0, then no Suitable Free Block
+ *
+ * ********************************************************************************/
+
+uint16_t searchLargestFreeBlockDL(SchCellCb *cell, SlotTimingInfo slotTime,uint16_t *startPrb)
+{
+ uint16_t broadcastPrbStart=0, broadcastPrbEnd=0, maxFreePRB = 0;
+ PduTxOccsaion ssbOccasion=0, sib1Occasion=0;
+ FreePrbBlock *freePrbBlock = NULLP;
+ CmLList *freePrbNode = NULLP;
+
+ SchDlSlotInfo *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
+ SchPrbAlloc *prbAlloc = &schDlSlotInfo->prbAlloc;
+
+ ssbOccasion = schCheckSsbOcc(cell, slotTime);
+ sib1Occasion = schCheckSib1Occ(cell, slotTime);
+
+ if(ssbOccasion && sib1Occasion)
+ {
+ broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
+ broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
+ }
+ else if(ssbOccasion)
+ {
+ broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
+ broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB -1;
+ }
+ else if(sib1Occasion)
+ {
+ broadcastPrbStart = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.startPrb;
+ broadcastPrbEnd = broadcastPrbStart + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
+ }
+
+
+ freePrbNode = prbAlloc->freePrbBlockList.first;
+ *startPrb = 0; /*Initialize the StartPRB to zero*/
+ while(freePrbNode)
+ {
+ freePrbBlock = (FreePrbBlock *)freePrbNode->node;
+
+ /*For block with same numFreeBlocks, choose the one with HighestPRB range
+ *Since FreeBLockList are arranged in Descending order of PRB range thus Skipping this block*/
+ if(maxFreePRB >= freePrbBlock->numFreePrb)
+ {
+ //skip this block
+ freePrbNode = freePrbNode->next;
+ continue;
+ }
+
+ /* If broadcast message is scheduled in this slot, then check if its PRBs belong to the current free block.
+ * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
+ if((ssbOccasion || sib1Occasion) &&
+ ((broadcastPrbStart >= freePrbBlock->startPrb) && (broadcastPrbStart <= freePrbBlock->endPrb)) && \
+ ((broadcastPrbEnd >= freePrbBlock->startPrb) && (broadcastPrbEnd <= freePrbBlock->endPrb)))
+ {
+
+ /* Implmentation is done such that highest-numbered free-RB is Checked first
+ and freePRB in this block is greater than Max till now */
+ if((freePrbBlock->endPrb > broadcastPrbEnd) && ((freePrbBlock->endPrb - broadcastPrbEnd) > maxFreePRB))
+ {
+ /* If sufficient free PRBs are available above broadcast message*/
+ *startPrb = broadcastPrbEnd + 1;
+ maxFreePRB = (freePrbBlock->endPrb - broadcastPrbEnd);
+ }
+ /*Also check the other freeBlock (i.e. Above the broadcast message) for MAX FREE PRB*/
+ if((broadcastPrbStart > freePrbBlock->startPrb) && ((broadcastPrbStart - freePrbBlock->startPrb) > maxFreePRB))
+ {
+ /* If free PRBs are available below broadcast message*/
+ *startPrb = freePrbBlock->startPrb;
+ maxFreePRB = (broadcastPrbStart - freePrbBlock->startPrb);
+ }
+ }
+ else //Best Block
+ {
+ if(maxFreePRB < freePrbBlock->numFreePrb)
+ {
+ *startPrb = freePrbBlock->startPrb;
+ maxFreePRB = freePrbBlock->numFreePrb;
+ }
+
+ }
+ freePrbNode = freePrbNode->next;
+ }
+ return(maxFreePRB);
+}
+