+/*******************************************************************************************
+ *
+ * @brief Allocate the PRB using RRM policy
+ *
+ * @details
+ *
+ * Function : prbAllocUsingRRMPolicy
+ *
+ * Functionality:
+ * [Step1]: Traverse each Node in the LC list
+ * [Step2]: Check whether the LC has ZERO requirement then clean this LC
+ * [Step3]: Calcualte the maxPRB for this LC.
+ * a. For Dedicated LC, maxPRB = sum of remainingReservedPRB and
+ * sharedPRB
+ * b. For Default, just SharedPRB count
+ * [Step4]: If the LC is the First one to be allocated for this UE then add
+ * TX_PAYLODN_LEN to reqBO
+ * [Step5]: Calculate the estimate PRB and estimate BO to be allocated
+ * based on reqBO and maxPRB left.
+ * [Step6]: Based on calculated PRB, Update Reserved PRB and Shared PRB counts
+ * [Step7]: Deduce the reqBO based on allocBO and move the LC node to last.
+ * [Step8]: Continue the next loop from List->head
+ *
+ * [Loop Exit]:
+ * [Exit1]: If all the LCs are allocated in list
+ * [Exit2]: If PRBs are exhausted
+ *
+ * @params[in] I/P > lcLinkList pointer (LcInfo list)
+ * I/P > IsDedicatedPRB (Flag to indicate that RESERVED PRB to use
+ * I/P > mcsIdx and PDSCH symbols count
+ * I/P & O/P > Shared PRB , reserved PRB Count
+ * I/P & O/P > Total TBS size accumulated
+ * I/P & O/P > isTxPayloadLenAdded[For DL] : Decision flag to add the TX_PAYLOAD_HDR_LEN
+ * I/P & O/P > srRcvd Flag[For UL] : Decision flag to add UL_GRANT_SIZE
+ *
+ * @return void
+ *
+ * *******************************************************************************************/
+void prbAllocUsingRRMPolicy(CmLListCp *lcLL, bool isDedicatedPRB, uint16_t mcsIdx,uint8_t numSymbols,\
+ uint16_t *sharedPRB, uint16_t *reservedPRB, bool *isTxPayloadLenAdded, bool *srRcvd)
+{
+ CmLList *node = NULLP;
+ LcInfo *lcNode = NULLP;
+ uint16_t remReservedPRB = 0, estPrb = 0, maxPRB = 0;
+
+ if(lcLL == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH: LcList not present");
+ return;
+ }
+ node = lcLL->first;
+
+ /*Only for Dedicated LcList, Valid value will be assigned to remReservedPRB
+ * For Other LcList, remReservedPRB = 0*/
+ if(reservedPRB != NULLP && isDedicatedPRB == TRUE)
+ {
+ remReservedPRB = *reservedPRB;
+ }
+
+ /*[Step1]*/
+ while(node)
+ {
+#if 0
+ /*For Debugging purpose*/
+ printLcLL(lcLL);
+#endif
+ lcNode = (LcInfo *)node->node;
+
+ /* [Step2]: Below condition will hit in rare case as it has been taken care during the cleaning
+ * process of LCID which was fully allocated. Check is just for safety purpose*/
+ if(lcNode->reqBO == 0 && lcNode->allocBO == 0)
+ {
+ DU_LOG("\nERROR --> SCH: LCID:%d has no requirement, clearing this node",\
+ lcNode->lcId);
+ deleteNodeFromLList(lcLL, node);
+ SCH_FREE(lcNode, sizeof(LcInfo));
+ node = lcLL->first;
+ continue;
+ }
+
+ /*[Exit1]: All LCs are allocated(allocBO = 0 for fully unallocated LC)*/
+ if(lcNode->allocBO != 0)
+ {
+ DU_LOG("\nDEBUG --> SCH: All LC are allocated [SharedPRB:%d]",*sharedPRB);
+ return;
+ }
+
+ /*[Exit2]: If PRBs are exhausted*/
+ if(isDedicatedPRB)
+ {
+ /*Loop Exit: All resources exhausted*/
+ if(remReservedPRB == 0 && *sharedPRB == 0)
+ {
+ DU_LOG("\nDEBUG --> SCH: Dedicated resources exhausted for LC:%d",lcNode->lcId);
+ return;
+ }
+ }
+ else
+ {
+ /*Loop Exit: All resources exhausted*/
+ if(*sharedPRB == 0)
+ {
+ DU_LOG("\nDEBUG --> SCH: Default resources exhausted for LC:%d",lcNode->lcId);
+ return;
+ }
+ }
+
+ /*[Step3]*/
+ maxPRB = remReservedPRB + *sharedPRB;
+
+ /*[Step4]*/
+ if((isTxPayloadLenAdded != NULLP) && (*isTxPayloadLenAdded == FALSE))
+ {
+ DU_LOG("\nDEBUG --> SCH: LC:%d is the First node to be allocated which includes TX_PAYLOAD_HDR_LEN",\
+ lcNode->lcId);
+ *isTxPayloadLenAdded = TRUE;
+ lcNode->allocBO = calculateEstimateTBSize((lcNode->reqBO + TX_PAYLOAD_HDR_LEN),\
+ mcsIdx, numSymbols, maxPRB, &estPrb);
+ lcNode->allocBO -=TX_PAYLOAD_HDR_LEN;
+ }
+ else if((srRcvd != NULLP) && (*srRcvd == TRUE))
+ {
+ DU_LOG("\nDEBUG --> SCH: LC:%d is the First node to be allocated which includes UL_GRANT_SIZE",\
+ lcNode->lcId);
+ *srRcvd = FALSE;
+ lcNode->reqBO += UL_GRANT_SIZE;
+ lcNode->allocBO = calculateEstimateTBSize(lcNode->reqBO, mcsIdx, numSymbols, maxPRB, &estPrb);
+ }
+ else
+ {
+ /*[Step4]*/
+ lcNode->allocBO = calculateEstimateTBSize(lcNode->reqBO,\
+ mcsIdx, numSymbols, maxPRB, &estPrb);
+ }
+
+ /*[Step6]:Re-adjust the reservedPRB pool count and *SharedPRB Count based on
+ * estimated PRB allocated*/
+ if((isDedicatedPRB == TRUE) && (estPrb <= remReservedPRB))
+ {
+ remReservedPRB = remReservedPRB - estPrb;
+ }
+ else /*LC requirement need PRB share from SharedPRB*/
+ {
+ if(*sharedPRB <= (estPrb - remReservedPRB))
+ {
+ DU_LOG("\nDEBUG --> SCH: SharedPRB is less");
+ *sharedPRB = 0;
+ }
+ else
+ {
+ *sharedPRB = *sharedPRB - (estPrb - remReservedPRB);
+ }
+ remReservedPRB = 0;
+ }
+
+ /*[Step7]*/
+ lcNode->reqBO -= lcNode->allocBO; /*Update the reqBO with remaining bytes unallocated*/
+ lcNode->allocPRB = estPrb;
+ cmLListAdd2Tail(lcLL, cmLListDelFrm(lcLL, node));
+
+ /*[Step8]:Next loop: First LC to be picked from the list
+ * because Allocated Nodes are moved to the last*/
+ node = lcLL->first;
+
+ }
+ return;
+}
+
+/*******************************************************************************************
+ *
+ * @brief Check the LC List and fill the LC and GrantSize to be sent to MAC as
+ * BO Report
+ *
+ * @details
+ *
+ * Function : updateGrantSizeForBoRpt
+ *
+ * Functionality:
+ * Check the LC List and fill the LC and GrantSize to be sent to MAC as
+ * BO Report in dlMsgAlloc Pointer
+ *
+ * @params[in] I/P > lcLinkList pointer (LcInfo list)
+ * I/P & O/P > dlMsgAlloc[for DL](Pending LC to be added in this context)
+ * I/P & O/P > BsrInfo (applicable for UL)
+ * I/P & O/P > accumalatedBOSize
+ * @return void
+ *
+ * *******************************************************************************************/
+void updateGrantSizeForBoRpt(CmLListCp *lcLL, DlMsgSchInfo *dlMsgAlloc,\
+ BsrInfo *bsrInfo, uint32_t *accumalatedBOSize)
+{
+ CmLList *node = NULLP, *next = NULLP;
+ LcInfo *lcNode = NULLP;
+
+ if(lcLL == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH: LcList not present");
+ return;
+ }
+
+ if(lcLL->count)
+ {
+ node = lcLL->first;
+ }
+ else
+ {
+ /*lcLL is empty*/
+ return;
+ }
+
+ /*Traverse List*/
+ while(node)
+ {
+ next = node->next;
+ lcNode = (LcInfo *)node->node;
+ if(lcNode != NULLP)
+ {
+ DU_LOG("\nINFO --> SCH : LcID:%d, [reqBO, allocBO, allocPRB]:[%d,%d,%d]",\
+ lcNode->lcId, lcNode->reqBO, lcNode->allocBO, lcNode->allocPRB);
+ if(dlMsgAlloc != NULLP)
+ {
+
+ /*Add this LC to dlMsgAlloc so that if this LC gets allocated, BO
+ * report for allocation can be sent to MAC*/
+ dlMsgAlloc->numOfTbs = 1;
+ dlMsgAlloc->transportBlock[0].lcSchInfo[dlMsgAlloc->transportBlock[0].numLc].lcId = lcNode->lcId;
+ dlMsgAlloc->transportBlock[0].lcSchInfo[dlMsgAlloc->transportBlock[0].numLc].schBytes = lcNode->allocBO;
+
+ /*Calculate the Total Payload/BO size allocated*/
+ *accumalatedBOSize += dlMsgAlloc->transportBlock[0].lcSchInfo[dlMsgAlloc->transportBlock[0].numLc].schBytes;
+
+ DU_LOG("\nINFO --> SCH: Added in MAC BO report: LCID:%d,reqBO:%d,Idx:%d, TotalBO Size:%d",\
+ lcNode->lcId,lcNode->reqBO, dlMsgAlloc->transportBlock[0].numLc, *accumalatedBOSize);
+
+ dlMsgAlloc->transportBlock[0].numLc++;
+ handleLcLList(lcLL, lcNode->lcId, DELETE);
+ }
+ else if(bsrInfo != NULLP)
+ {
+ *accumalatedBOSize += lcNode->allocBO;
+ DU_LOG("\nINFO --> SCH: UL : LCID:%d,reqBO:%d, TotalBO Size:%d",\
+ lcNode->lcId,lcNode->reqBO, *accumalatedBOSize);
+ }
+ }
+ node = next;
+ }/*End of while*/
+ return;
+}
+
+/*******************************************************************
+*
+* @brief fill DL message information for MSG4 and Dedicated DL Msg
+*
+* @details
+*
+* Function : fillDlMsgInfo
+*
+* Functionality:
+* fill DL message information for MSG4 and Dedicated DL Msg
+*
+* @params[in] DlMsgInfo *dlMsgInfo, uint16_t crnti
+* @params[in] bool isRetx, SchDlHqProcCb *hqP
+* @return void
+*
+*******************************************************************/
+void fillDlMsgInfo(DlMsgSchInfo *dlMsgSchInfo, uint16_t crnti, bool isRetx, SchDlHqProcCb *hqP)
+{
+ hqP->tbInfo[0].isEnabled = TRUE;
+ hqP->tbInfo[0].state = HQ_TB_WAITING;
+ hqP->tbInfo[0].txCntr++;
+ hqP->tbInfo[1].isEnabled = TRUE;
+ hqP->tbInfo[1].state = HQ_TB_WAITING;
+ hqP->tbInfo[1].txCntr++;
+ dlMsgSchInfo->crnti = crnti;
+ dlMsgSchInfo->transportBlock[0].ndi = hqP->tbInfo[0].ndi; /*How to handle two tb case?TBD*/
+ dlMsgSchInfo->harqProcNum = hqP->procId;
+ dlMsgSchInfo->dlAssignIdx = 0;
+ dlMsgSchInfo->pucchTpc = 0;
+ dlMsgSchInfo->pucchResInd = 0;
+ dlMsgSchInfo->harqFeedbackInd = hqP->k1;
+ dlMsgSchInfo->dciFormatId = 1;
+}
+
+/*******************************************************************
+ *
+ * @brief sch Process pending Msg4 Req
+ *
+ * @details
+ *
+ * Function : schProcessMsg4Req
+ *
+ * Functionality:
+ * sch Process pending Msg4 Req
+ *
+ * @params[in] SchCellCb *cell, cell cb struct pointer
+ * @params[in] SlotTimingInfo currTime, current timing info
+ * @params[in] uint8_t ueId, ue ID
+ * @params[in] bool isRetxMsg4, indicator to MSG4 retransmission
+ * @params[in] SchDlHqProcCb **msg4HqProc, address of MSG4 HARQ proc pointer
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ *******************************************************************/
+
+uint8_t schProcessMsg4Req(SchCellCb *cell, SlotTimingInfo currTime, uint8_t ueId, bool isRetxMsg4, SchDlHqProcCb **msg4HqProc)
+{
+ uint8_t pdschStartSymbol = 0, pdschNumSymbols = 0;
+ SlotTimingInfo pdcchTime, pdschTime, pucchTime;
+ DlMsgSchInfo *dciSlotAlloc = NULLP; /* Stores info for transmission of PDCCH for Msg4 */
+ DlMsgSchInfo *msg4SlotAlloc = NULLP; /* Stores info for transmission of PDSCH for Msg4 */
+
+ if(cell == NULL)
+ {
+ DU_LOG("\nERROR --> SCH: schProcessMsg4Req() : Cell is NULL");
+ return RFAILED;
+ }
+
+ if (isRetxMsg4 == FALSE)
+ {
+ if (RFAILED == schDlGetAvlHqProcess(cell, &cell->ueCb[ueId - 1], msg4HqProc))
+ {
+ DU_LOG("\nERROR --> SCH: schProcessMsg4Req() : No process");
+ return RFAILED;
+ }
+ }
+
+ if(findValidK0K1Value(cell, currTime, ueId, false, &pdschStartSymbol, &pdschNumSymbols, &pdcchTime, &pdschTime,\
+ &pucchTime, isRetxMsg4, *msg4HqProc) != true )
+ {
+ DU_LOG("\nERROR --> SCH: schProcessMsg4Req() : k0 k1 not found");
+ return RFAILED;
+ }
+
+ if(cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] == NULL)
+ {
+ SCH_ALLOC(dciSlotAlloc, sizeof(DlMsgSchInfo));
+ if(dciSlotAlloc == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH : Memory Allocation failed for dciSlotAlloc");
+ return RFAILED;
+ }
+ cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = dciSlotAlloc;
+ memset(dciSlotAlloc, 0, sizeof(DlMsgSchInfo));
+ }
+ else
+ dciSlotAlloc = cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1];
+
+ /* Fill PDCCH and PDSCH scheduling information for Msg4 */
+ if((schDlRsrcAllocMsg4(cell, pdschTime, ueId, dciSlotAlloc, pdschStartSymbol, pdschNumSymbols, isRetxMsg4, *msg4HqProc)) != ROK)
+ {
+ DU_LOG("\nERROR --> SCH: Scheduling of Msg4 failed in slot [%d]", pdschTime.slot);
+ if(!dciSlotAlloc->dlMsgPdschCfg)
+ {
+ SCH_FREE(dciSlotAlloc, sizeof(DlMsgSchInfo));
+ cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
+ }
+ return RFAILED;
+ }
+
+ /* Check if both DCI and RAR are sent in the same slot.
+ * If not, allocate memory RAR PDSCH slot to store RAR info
+ */
+ if(pdcchTime.slot == pdschTime.slot)
+ {
+ SCH_ALLOC(dciSlotAlloc->dlMsgPdschCfg, sizeof(PdschCfg));
+ if(!dciSlotAlloc->dlMsgPdschCfg)
+ {
+ DU_LOG("\nERROR --> SCH : Memory Allocation failed for dciSlotAlloc->dlMsgPdschCfg");
+ SCH_FREE(dciSlotAlloc->dlMsgPdcchCfg, sizeof(PdcchCfg));
+ SCH_FREE(dciSlotAlloc, sizeof(DlMsgSchInfo));
+ cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
+ return RFAILED;
+ }
+ memcpy(dciSlotAlloc->dlMsgPdschCfg, &dciSlotAlloc->dlMsgPdcchCfg->dci.pdschCfg, sizeof(PdschCfg));
+ }
+ else
+ {
+ /* Allocate memory to schedule rarSlot to send RAR, pointer will be checked at schProcessSlotInd() */
+ if(cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1] == NULL)
+ {
+ SCH_ALLOC(msg4SlotAlloc, sizeof(DlMsgSchInfo));
+ if(msg4SlotAlloc == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH : Memory Allocation failed for msg4SlotAlloc");
+ SCH_FREE(dciSlotAlloc->dlMsgPdcchCfg, sizeof(PdcchCfg));
+ if(!dciSlotAlloc->dlMsgPdschCfg)
+ {
+ SCH_FREE(dciSlotAlloc, sizeof(DlMsgSchInfo));
+ cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
+ }
+ return RFAILED;
+ }
+ cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1] = msg4SlotAlloc;
+ memset(msg4SlotAlloc, 0, sizeof(DlMsgSchInfo));
+ }
+ else
+ msg4SlotAlloc = cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1];
+
+ /* Copy all msg4 pdschcfg info */
+ msg4SlotAlloc->crnti =dciSlotAlloc->crnti;
+ msg4SlotAlloc->bwp = dciSlotAlloc->bwp;
+ SCH_ALLOC(msg4SlotAlloc->dlMsgPdschCfg, sizeof(PdschCfg));
+ if(msg4SlotAlloc->dlMsgPdschCfg)
+ {
+ memcpy(msg4SlotAlloc->dlMsgPdschCfg, &dciSlotAlloc->dlMsgPdcchCfg->dci.pdschCfg, sizeof(PdschCfg));
+ }
+ else
+ {
+ SCH_FREE(dciSlotAlloc->dlMsgPdcchCfg, sizeof(PdcchCfg));
+ if(dciSlotAlloc->dlMsgPdschCfg == NULLP)
+ {
+ SCH_FREE(dciSlotAlloc, sizeof(DlMsgSchInfo));
+ cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
+
+ }
+ SCH_FREE(msg4SlotAlloc, sizeof(DlMsgSchInfo));
+ cell->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
+ DU_LOG("\nERROR --> SCH : Memory Allocation failed for msg4SlotAlloc->dlMsgPdschCfg");
+ return RFAILED;
+ }
+ }
+
+ /* PUCCH resource */
+ schAllocPucchResource(cell, pucchTime, cell->raCb[ueId-1].tcrnti, &cell->ueCb[ueId-1], isRetxMsg4, *msg4HqProc);
+
+ cell->schDlSlotInfo[pdcchTime.slot]->pdcchUe = ueId;
+ cell->schDlSlotInfo[pdschTime.slot]->pdschUe = ueId;
+ cell->schUlSlotInfo[pucchTime.slot]->pucchUe = ueId;
+ cell->raCb[ueId-1].msg4recvd = FALSE;
+ if(isRetxMsg4)
+ {
+ cell->ueCb[ueId-1].retxMsg4HqProc= NULLP;
+ }
+ return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief sch Process pending Sr or Bsr Req
+ *
+ * @details
+ *
+ * Function : updateBsrAndLcList
+ *
+ * Functionality:
+ * Updating the BSRInfo in UECB and Lclist
+ *
+ * @params[in] SchCellCb *cell, SlotTimingInfo currTime
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ *******************************************************************/
+void updateBsrAndLcList(CmLListCp *lcLL, BsrInfo *bsrInfo, uint8_t status)
+{
+ CmLList *node = NULLP, *next = NULLP;
+ LcInfo *lcNode = NULLP;
+
+ if(lcLL == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH: LcList not present");
+ return;
+ }
+
+ if(lcLL->count)
+ {
+ node = lcLL->first;
+ }
+ else
+ {
+ /*lcLL is empty*/
+ return;
+ }
+
+ while(node)
+ {
+ next = node->next;
+ lcNode = (LcInfo *)node->node;
+ if(lcNode != NULLP)
+ {
+ /*Only when Status is OK then allocation is marked as ZERO and reqBO
+ * is updated in UE's DB. If Failure, then allocation is added to reqBO
+ * and same is updated in Ue's DB inside BSR Info structure*/
+ if(status == ROK)
+ {
+ lcNode->allocBO = 0;
+ }
+
+ lcNode->reqBO += lcNode->allocBO;
+ bsrInfo[lcNode->lcId].dataVol = lcNode->reqBO;
+ if(lcNode->reqBO == 0)
+ {
+ handleLcLList(lcLL, lcNode->lcId, DELETE);
+ }
+ }
+ node = next;
+ }
+}
+
+/*******************************************************************
+ *
+ * @brief sch Process pending Sr or Bsr Req
+ *
+ * @details
+ *
+ * Function : schProcessSrOrBsrReq
+ *
+ * Functionality:
+ * sch Process pending Sr or Bsr Req
+ *
+ * @params[in] SchCellCb *cell, SlotTimingInfo currTime
+ * @params[in] uint8_t ueId, Bool isRetx, SchUlHqProcCb **hqP
+ * @return true - success
+ * false - failure
+ *
+ *******************************************************************/
+bool schProcessSrOrBsrReq(SchCellCb *cell, SlotTimingInfo currTime, uint8_t ueId, bool isRetx, SchUlHqProcCb **hqP)
+{
+ bool k2Found = FALSE;
+ uint8_t startSymb = 0, symbLen = 0;
+ uint8_t k2TblIdx = 0, k2Index = 0, k2Val = 0;
+ SchUeCb *ueCb;
+ SchK2TimingInfoTbl *k2InfoTbl=NULLP;
+ SlotTimingInfo dciTime, puschTime;
+
+ if(cell == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH: schProcessSrOrBsrReq() : Cell is NULL");
+ return false;
+ }
+
+ ueCb = &cell->ueCb[ueId-1];
+
+ if(ueCb == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH: schProcessSrOrBsrReq() : UE is NULL");
+ return false;
+ }
+
+ if (isRetx == FALSE)
+ {
+ if (schUlGetAvlHqProcess(cell, ueCb, hqP) != ROK)
+ {
+ return RFAILED;
+ }
+ }
+
+ /* Calculating time frame to send DCI for SR */
+ ADD_DELTA_TO_TIME(currTime, dciTime, PHY_DELTA_DL + SCHED_DELTA, cell->numSlots);
+#ifdef NR_TDD
+ if(schGetSlotSymbFrmt(dciTime.slot, cell->slotFrmtBitMap) == DL_SLOT)
+#endif
+ {
+ if(ueCb->k2TblPrsnt)
+ k2InfoTbl = &ueCb->k2InfoTbl;
+ else
+ k2InfoTbl = &cell->k2InfoTbl;
+
+ for(k2TblIdx = 0; k2TblIdx < k2InfoTbl->k2TimingInfo[dciTime.slot].numK2; k2TblIdx++)
+ {
+ k2Index = k2InfoTbl->k2TimingInfo[dciTime.slot].k2Indexes[k2TblIdx];
+
+ if(!ueCb->k2TblPrsnt)
+ {
+ k2Val = cell->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList[k2Index].k2;
+ startSymb = cell->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList[k2Index].startSymbol;
+ symbLen = cell->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList[k2Index].symbolLength;
+ }
+ else
+ {
+ k2Val = ueCb->ueCfg.spCellCfg.servCellRecfg.initUlBwp.puschCfg.timeDomRsrcAllocList[k2Index].k2;
+ startSymb = ueCb->ueCfg.spCellCfg.servCellRecfg.initUlBwp.puschCfg.timeDomRsrcAllocList[k2Index].startSymbol;
+ symbLen = ueCb->ueCfg.spCellCfg.servCellRecfg.initUlBwp.puschCfg.timeDomRsrcAllocList[k2Index].symbolLength;
+ }
+ /* Check for number of Symbol of PUSCH should be same as original in case of transmisson*/
+ /* Calculating time frame to send PUSCH for SR */
+ ADD_DELTA_TO_TIME(dciTime, puschTime, k2Val, cell->numSlots);
+#ifdef NR_TDD
+ if(schGetSlotSymbFrmt(puschTime.slot, cell->slotFrmtBitMap) == DL_SLOT)
+ continue;
+#endif
+ if(cell->schUlSlotInfo[puschTime.slot]->puschUe != 0)
+ {
+ continue;
+ }
+ k2Found = true;
+ if(hqP)
+ {
+ ADD_DELTA_TO_TIME(puschTime, (*hqP)->puschTime, 0, cell->numSlots);
+ }
+ break;
+ }
+ }
+
+ if(k2Found == true)
+ {
+ if(cell->api->SchScheduleUlLc(dciTime, puschTime, startSymb, symbLen, isRetx, hqP) != ROK)
+ return false;
+ }
+ else
+ {
+ DU_LOG("\nDEBUG --> SCH : schProcessSrOrBsrReq(): K2 value is not found");
+ return false;
+ }
+ return true;
+}
+
+/********************************************************************************
+ *
+ * @brief Increment the Slot by a input factor
+ *
+ * @details
+ *
+ * Function : schIncrSlot
+ *
+ * Functionality:
+ * Increment the slot by a input factor till num of Slots configured in a
+ * Radio Frame. If it exceeds, move to next sfn.
+ *
+ * @params[in/out] SlotTimingInfo timingInfo
+ * [in] uint8_t incr [Increment factor]
+ * [in] numSlotsPerRF [Number of Slots configured per RF as per
+ * numerology]
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ *******************************************************************/
+void schIncrSlot(SlotTimingInfo *timingInfo, uint8_t incr, uint16_t numSlotsPerRF)
+{
+ timingInfo->slot += incr;
+ if(timingInfo->slot >= numSlotsPerRF)
+ {
+ timingInfo->sfn += timingInfo->slot/numSlotsPerRF;
+ timingInfo->slot %= numSlotsPerRF;
+ if(timingInfo->sfn > MAX_SFN)
+ {
+ timingInfo->sfn %= MAX_SFN;
+ }
+ }
+}
+
+/*******************************************************************
+*
+* @brief Fill PDSCH info in Page Alloc
+*
+* @details
+*
+* Function : schFillPagePdschCfg
+*
+* Functionality: Fill PDSCH info in Page Alloc
+*
+* @params[in] SchCellCb *cell, PdschCfg *pagePdschCfg, SlotTimingInfo slotTime,
+* uint16_t tbsSize, uint8_t mcs, uint16_t startPrb
+*
+* @return pointer to return Value(ROK, RFAILED)
+*
+* ****************************************************************/
+uint8_t schFillPagePdschCfg(SchCellCb *cell, PageDlSch *pageDlSch, SlotTimingInfo slotTime, uint16_t tbSize, uint8_t mcs, uint16_t startPrb)
+{
+ uint8_t dmrsStartSymbol, startSymbol, numSymbol;
+
+ /* fill the PDSCH PDU */
+
+ pageDlSch->tbInfo.mcs = mcs;
+ tbSize = tbSize + TX_PAYLOAD_HDR_LEN;
+ pageDlSch->tbInfo.tbSize = tbSize;
+ pageDlSch->dmrs.dmrsType = 0; /* type-1 */
+ pageDlSch->dmrs.nrOfDmrsSymbols = NUM_DMRS_SYMBOLS;
+ pageDlSch->dmrs.dmrsAddPos = DMRS_ADDITIONAL_POS;
+
+ /* the RB numbering starts from coreset0, and PDSCH is always above SSB */
+ pageDlSch->freqAlloc.startPrb = startPrb;
+ pageDlSch->freqAlloc.numPrb = schCalcNumPrb(tbSize, mcs, NUM_PDSCH_SYMBOL);
+ pageDlSch->vrbPrbMapping = 0; /* non-interleaved */
+ /* This is Intel's requirement. PDSCH should start after PDSCH DRMS symbol */
+ pageDlSch->timeAlloc.mappingType = DMRS_MAP_TYPE_A; /* Type-A */
+ pageDlSch->timeAlloc.startSymb = 3; /* spec-38.214, Table 5.1.2.1-1 */
+ pageDlSch->timeAlloc.numSymb = NUM_PDSCH_SYMBOL;
+
+ /* Find total symbols occupied including DMRS */
+ dmrsStartSymbol = findDmrsStartSymbol(4);
+ /* If there are no DRMS symbols, findDmrsStartSymbol() returns MAX_SYMB_PER_SLOT,
+ * in that case only PDSCH symbols are marked as occupied */
+ if(dmrsStartSymbol == MAX_SYMB_PER_SLOT)
+ {
+ startSymbol = pageDlSch->timeAlloc.startSymb;
+ numSymbol = pageDlSch->timeAlloc.numSymb;
+ }
+ /* If DMRS symbol is found, mark DMRS and PDSCH symbols as occupied */
+ else
+ {
+ startSymbol = dmrsStartSymbol;
+ numSymbol = pageDlSch->dmrs.nrOfDmrsSymbols + pageDlSch->timeAlloc.numSymb;
+ }
+
+ /* Allocate the number of PRBs required for DL PDSCH */
+ if((allocatePrbDl(cell, slotTime, startSymbol, numSymbol,\
+ &pageDlSch->freqAlloc.startPrb, pageDlSch->freqAlloc.numPrb)) != ROK)
+ {
+ DU_LOG("\nERROR --> SCH : allocatePrbDl() failed for DL MSG");
+ return RFAILED;
+ }
+ return ROK;
+}
+
+/**
+ * @brief Handles retransmission for MSG3
+ *
+ * @details
+ *
+ * Function : schMsg3RetxSchedulingForUe
+ *
+ * This function handles retransmission for MSG3
+ *
+ * @param[in] SchRaCb *raCb, RA cb pointer
+ * @return
+ * -# ROK
+ * -# RFAILED
+ **/
+uint8_t schMsg3RetxSchedulingForUe(SchRaCb *raCb)
+{
+ bool k2Found = false;
+ uint16_t dciSlot = 0;
+ SlotTimingInfo dciTime, msg3Time;
+ SchCellCb *cell = NULLP;
+ SlotTimingInfo currTime;
+ DciInfo *dciInfo = NULLP;
+ cell = raCb->cell;
+ currTime = cell->slotInfo;
+
+ /* Calculating time frame to send DCI for MSG3 Retx*/
+ ADD_DELTA_TO_TIME(currTime, dciTime, PHY_DELTA_DL + SCHED_DELTA, cell->numSlots);
+#ifdef NR_TDD
+ /* Consider this slot for sending DCI, only if it is a DL slot */
+ if(schGetSlotSymbFrmt(dciSlot, raCb->cell->slotFrmtBitMap) == DL_SLOT)
+#endif
+ {
+ /* If PDCCH is already scheduled on this slot, cannot schedule PDSCH for another UE here. */
+ if(cell->schDlSlotInfo[dciSlot]->pdcchUe != 0)
+ return false;
+
+ k2Found = schGetMsg3K2(cell, &raCb->msg3HqProc, dciTime.slot, &msg3Time, TRUE);
+
+ if (!k2Found)
+ {
+ return RFAILED;
+ }
+ SCH_ALLOC(dciInfo, sizeof(DciInfo));
+ if(!dciInfo)
+ {
+ DU_LOG("\nERROR --> SCH : Memory Allocation failed for dciInfo alloc");
+ return RFAILED;
+ }
+ cell->schDlSlotInfo[msg3Time.slot]->ulGrant = dciInfo;
+ SCH_ALLOC(cell->schUlSlotInfo[msg3Time.slot]->schPuschInfo, sizeof(SchPuschInfo));
+ memset(dciInfo,0,sizeof(DciInfo));
+ schFillUlDciForMsg3Retx(raCb, cell->schUlSlotInfo[msg3Time.slot]->schPuschInfo, dciInfo);
+ }
+ raCb->retxMsg3HqProc = NULLP;
+ return ROK;
+}
+
+/**
+ * @brief Get K2 value for MSG3
+ *
+ * @details
+ *
+ * Function : schGetMsg3K2
+ *
+ * This function gets K2 for MSG3
+ *
+ * @param[in] SchCellCb *cell, Cell cb struc pointer
+ * @param[in] SchUlHqProcCb* msg3HqProc, msg3 harq proc pointer
+ * @param[in] uint16_t dlTime, DL time of scheduling
+ * @param[in] SlotTimingInfo *msg3Time, MSG3 timing info
+ * @param[in] bool isRetx, indicates MSG3 retransmission
+ * @return
+ * -# true
+ * -# false
+ **/
+bool schGetMsg3K2(SchCellCb *cell, SchUlHqProcCb* msg3HqProc, uint16_t dlTime, SlotTimingInfo *msg3Time, bool isRetx)
+{
+ bool k2Found = false;
+ uint8_t k2TblIdx = 0;
+ uint8_t k2Index = 0;
+ uint8_t k2 = 0;
+ uint8_t numK2 = 0;
+ uint8_t puschMu = 0;
+ uint8_t msg3Delta = 0, msg3MinSchTime = 0;
+#ifdef NR_TDD
+ uint8_t totalCfgSlot = 0;
+#endif
+ SchK2TimingInfoTbl *msg3K2InfoTbl=NULLP;
+ SlotTimingInfo currTime, msg3TempTime;
+ currTime = cell->slotInfo;
+ puschMu = cell->numerology;
+
+ if (isRetx)
+ {
+ if(!msg3HqProc)
+ return false;
+
+ numK2 = cell->k2InfoTbl.k2TimingInfo[dlTime].numK2;
+ msg3K2InfoTbl = &cell->msg3K2InfoTbl;
+ msg3MinSchTime = 0;
+ msg3Delta = 0;
+ }
+ else
+ {
+ numK2 = cell->msg3K2InfoTbl.k2TimingInfo[dlTime].numK2;
+ msg3K2InfoTbl = &cell->k2InfoTbl;
+ msg3MinSchTime = minMsg3SchTime[cell->numerology];
+ msg3Delta = puschDeltaTable[puschMu];
+ }
+
+ for(k2TblIdx = 0; k2TblIdx < numK2; k2TblIdx++)
+ {
+ k2Index = msg3K2InfoTbl->k2TimingInfo[dlTime].k2Indexes[k2TblIdx];
+
+ k2 = cell->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList[k2Index].k2;
+ if (isRetx)
+ {
+ if ((msg3HqProc->strtSymbl != cell->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList[k2Index].startSymbol) ||
+ (msg3HqProc->numSymbl != cell->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList[k2Index].symbolLength))
+ {
+ continue;
+ }
+ }
+ /* Delta is added to the slot allocation for msg3 based on 38.214 section 6.1.2.1 */
+ k2 = k2 + msg3Delta;
+ if(k2 >= msg3MinSchTime)
+ {
+ ADD_DELTA_TO_TIME(currTime, msg3TempTime, k2, cell->numSlots);
+#ifdef NR_TDD
+ if(schGetSlotSymbFrmt(msg3TempTime.slot % totalCfgSlot, cell->slotFrmtBitMap) == DL_SLOT)
+ continue;
+#endif
+ /* If PUSCH is already scheduled on this slot, another PUSCH
+ * pdu cannot be scheduled here */
+ if(cell->schUlSlotInfo[msg3TempTime.slot]->puschUe != 0)
+ continue;
+ k2Found = true;
+ break;
+ }
+ }
+ if (k2Found == true)
+ {
+ msg3Time->slot = msg3TempTime.slot;
+ msg3Time->sfn = msg3TempTime.sfn;
+ msg3Time->slot = msg3TempTime.slot;
+ }
+ return k2Found;
+}
+