[Epic-ID: ODUHIGH-406][Task-ID: ODUHIGH-415]: Paging Configuration
[o-du/l2.git] / src / 5gnrsch / sch.c
index a98832a..a0ff776 100644 (file)
@@ -58,7 +58,20 @@ SchCellCfgCfmFunc SchCellCfgCfmOpts[] =
    packSchCellCfgCfm      /* LWLC */
 };
 
+SchSliceCfgRspFunc SchSliceCfgRspOpts[] =
+{
+   packSchSliceCfgRsp,     /* LC */
+   MacProcSchSliceCfgRsp,  /* TC */
+   packSchSliceCfgRsp      /* LWLC */
+
+};
 
+SchSliceReCfgRspFunc SchSliceReCfgRspOpts[] =
+{
+   packSchSliceReCfgRsp,     /* LC */
+   MacProcSchSliceReCfgRsp,  /* TC */
+   packSchSliceReCfgRsp      /* LWLC */
+};
 /**
  * @brief Task Initiation function. 
  *
@@ -167,7 +180,7 @@ uint8_t SchInstCfg(RgCfg *cfg, Inst  dInst)
               
    /* Set Config done in TskInit */
    schCb[inst].schInit.cfgDone = TRUE;
-   DU_LOG("\nINFO  -->  SCH : Scheduler gen config done");
+   DU_LOG("\nINFO   -->  SCH : Scheduler gen config done");
 
    return ret;
 }
@@ -208,7 +221,7 @@ uint8_t SchProcGenCfgReq(Pst *pst, RgMngmt *cfg)
            "pst->dstInst=%d SCH_INST_START=%d", pst->dstInst,SCH_INST_START); 
       return ROK;
    }
-   DU_LOG("\nINFO -->  SCH : Received scheduler gen config");
+   DU_LOG("\nINFO   -->  SCH : Received scheduler gen config");
    /* Fill the post structure for sending the confirmation */
    memset(&cfmPst, 0 , sizeof(Pst));
    SchFillCfmPst(pst, &cfmPst, cfg);
@@ -664,6 +677,7 @@ uint8_t schInitCellCb(Inst inst, SchCellCfg *schCellCfg)
    cell->firstSsbTransmitted = false;
    cell->firstSib1Transmitted = false;
    fillSsbStartSymb(cell);
+   cmLListInit(&cell->ueToBeScheduled);
    schCb[inst].cells[inst] = cell;
 
    DU_LOG("\nINFO  -->  SCH : Cell init completed for cellId:%d", cell->cellId);
@@ -873,7 +887,10 @@ uint8_t SchHdlCellCfgReq(Pst *pst, SchCellCfg *schCellCfg)
    fillSchSib1Cfg(schCellCfg->numerology, schCellCfg->bandwidth, cellCb->numSlots,
         &(schCellCfg->sib1SchCfg), schCellCfg->phyCellId,
         schCellCfg->ssbSchCfg.ssbOffsetPointA);
+   
+   
    memcpy(&cellCb->cellCfg, schCellCfg, sizeof(SchCellCfg));
+   schProcPagingCfg(cellCb);
 
    /* Fill coreset frequencyDomainResource bitmap */
    coreset0Idx = cellCb->cellCfg.schInitialDlBwp.pdcchCommon.commonSearchSpace.coresetId;
@@ -926,21 +943,18 @@ uint8_t SchHdlCellCfgReq(Pst *pst, SchCellCfg *schCellCfg)
 uint8_t MacSchDlRlcBoInfo(Pst *pst, DlRlcBoInfo *dlBoInfo)
 {
    uint8_t  lcId = 0;
-   uint16_t ueIdx = 0;
-   uint16_t slot = 0;
-#ifdef NR_TDD
-   uint16_t slotIdx = 0;
-#endif
+   uint16_t ueId = 0;
+   bool isLcIdValid = false;
    SchUeCb *ueCb = NULLP;
    SchCellCb *cell = NULLP;
-   SchDlSlotInfo *schDlSlotInfo = 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");
+   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)
@@ -949,72 +963,59 @@ uint8_t MacSchDlRlcBoInfo(Pst *pst, DlRlcBoInfo *dlBoInfo)
       return RFAILED;
    }
 
-   GET_UE_IDX(dlBoInfo->crnti, ueIdx);
-   ueCb = &cell->ueCb[ueIdx-1];
+   GET_UE_ID(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;
+   }
 
-   if(lcId == SRB1_LCID || lcId == SRB2_LCID || lcId == SRB3_LCID || \
-         (lcId >= MIN_DRB_LCID && lcId <= MAX_DRB_LCID))
+   /*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)
    {
-      SET_ONE_BIT(ueIdx, cell->boIndBitMap);
-      if(ueCb->dlInfo.dlLcCtxt[lcId].lcId == lcId)
+      /*Check the LC is Dedicated or default and accordingly LCList will
+       * be used*/
+      if(ueCb->dlInfo.dlLcCtxt[lcId].isDedicated)
       {
-         ueCb->dlInfo.dlLcCtxt[lcId].bo = dlBoInfo->dataVolume;
+         lcLL = &(ueCb->dlLcPrbEst.dedLcInfo->dedLcList);
       }
       else
       {
-         DU_LOG("ERROR --> SCH: LCID:%d is not configured in SCH Cb",lcId);
-         return RFAILED;
+         lcLL = &(ueCb->dlLcPrbEst.defLcList);
       }
+      handleLcLList(lcLL, lcId, DELETE);
+      return ROK;
    }
-   else if(lcId != SRB0_LCID)
+
+   if(lcId == SRB0_LCID)
    {
-      DU_LOG("\nERROR  -->  SCH : Invalid LC Id %d in MacSchDlRlcBoInfo", lcId);
-      return RFAILED;
+      cell->raCb[ueId -1].msg4recvd = true;
+      cell->raCb[ueId -1].dlMsgPduLen = dlBoInfo->dataVolume;
+      
    }
-
-   slot = (cell->slotInfo.slot + SCHED_DELTA + PHY_DELTA_DL + BO_DELTA) % cell->numSlots;
-#ifdef NR_TDD
-   while(schGetSlotSymbFrmt(cell->slotFrmtBitMap, slot) != DL_SLOT)
+   else
    {
-      slot = (slot + 1)%cell->numSlots;
-      slotIdx++;
-      if(slotIdx==cell->numSlots)
+      /* 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)
       {
-         DU_LOG("\nERROR  -->  SCH : No DL Slot available");
+         ueCb->dlInfo.dlLcCtxt[lcId].bo = dlBoInfo->dataVolume;
+      }
+      else
+      {
+         DU_LOG("ERROR --> SCH: LCID:%d is not configured in SCH Cb",lcId);
          return RFAILED;
       }
    }
-#endif
-
-   schDlSlotInfo = cell->schDlSlotInfo[slot];
-
-   if(schDlSlotInfo == NULLP)
-   {
-      DU_LOG("\nERROR  -->  SCH : MacSchDlRlcBoInfo(): schDlSlotInfo does not exists");
-      return RFAILED;
-   }
-   SCH_ALLOC(schDlSlotInfo->dlMsgInfo, sizeof(DlMsgInfo));
-   if(schDlSlotInfo->dlMsgInfo == NULLP)
-   {
-      DU_LOG("\nERROR  -->  SCH : Memory allocation failed for dlMsgInfo");
-      schDlSlotInfo = NULL;
-      return RFAILED;
-   }
-
-   schDlSlotInfo->dlMsgInfo->crnti = dlBoInfo->crnti;
-   schDlSlotInfo->dlMsgInfo->ndi = 1;
-   schDlSlotInfo->dlMsgInfo->harqProcNum = 0;
-   schDlSlotInfo->dlMsgInfo->dlAssignIdx = 0;
-   schDlSlotInfo->dlMsgInfo->pucchTpc = 0;
-   schDlSlotInfo->dlMsgInfo->pucchResInd = 0;
-   schDlSlotInfo->dlMsgInfo->harqFeedbackInd = 0;
-   schDlSlotInfo->dlMsgInfo->dciFormatId = 1;
-   if(lcId == SRB0_LCID)
-   {
-      schDlSlotInfo->dlMsgInfo->isMsg4Pdu = true;
-      schDlSlotInfo->dlMsgInfo->dlMsgPduLen = dlBoInfo->dataVolume;
-   }
+   
+   /* Adding UE Id to list of pending UEs to be scheduled */
+   addUeToBeScheduled(cell, ueId);
    return ROK;
 }
 
@@ -1040,22 +1041,42 @@ uint8_t MacSchBsr(Pst *pst, UlBufferStatusRptInd *bsrInd)
    Inst           schInst       = pst->dstInst-SCH_INST_START;
    SchCellCb      *cellCb       = NULLP;
    SchUeCb        *ueCb         = NULLP;
-   uint8_t        lcgIdx;
+   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");
+   if(bsrInd == NULLP)
+   {
+      DU_LOG("\nERROR  -->  SCH : BSR Ind is empty");
+      return RFAILED;
+   }
    cellCb = schCb[schInst].cells[schInst];
+   if(cellCb == NULLP)
+   {
+      DU_LOG("\nERROR  -->  SCH : CellCb is empty");
+      return RFAILED;
+   }
    ueCb = schGetUeCb(cellCb, bsrInd->crnti);
 
+   if(ueCb == NULLP)
+   {
+      DU_LOG("\nERROR  -->  SCH : UeCB is empty");
+      return RFAILED;
+   }
+
+   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;
+      ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].priority = 1; //TODO: determining LCG priority?
+      ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].dataVol = bsrInd->dataVolInfo[lcgIdx].dataVol;
    }
+   
+   /* Adding UE Id to list of pending UEs to be scheduled */
+   addUeToBeScheduled(cellCb, ueCb->ueId);
    return ROK;
 }
 
@@ -1090,10 +1111,19 @@ uint8_t MacSchSrUciInd(Pst *pst, SrUciIndInfo *uciInd)
    DU_LOG("\nDEBUG  -->  SCH : Received SR");
 
    ueCb = schGetUeCb(cellCb, uciInd->crnti);
+   
+   if(ueCb->state == SCH_UE_STATE_INACTIVE)
+   {
+      DU_LOG("\nERROR  -->  SCH : Crnti %d is inactive", uciInd->crnti);
+      return ROK;  
+   }
 
    if(uciInd->numSrBits)
    {
       ueCb->srRcvd = true;
+      
+      /* Adding UE Id to list of pending UEs to be scheduled */
+      addUeToBeScheduled(cellCb, ueCb->ueId);
    }
    return ROK;
 }
@@ -1267,8 +1297,15 @@ uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
    bool           isPrachOccasion;
    FreePrbBlock   *freePrbBlock = NULLP;
    CmLList        *freePrbNode = NULLP;
-   SchPrbAlloc    *prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
+   SchPrbAlloc    *prbAlloc = NULLP;
 
+   if(cell == NULLP)
+   {
+      DU_LOG("\nERROR  --> SCH : allocatePrbUl(): Received cellCb is null");
+      return RFAILED;
+   }
+   
+   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)
@@ -1362,6 +1399,58 @@ uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
 
    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 ueId [%d] to cell->ueToBeScheduled list", *ueId);
+      return RFAILED;
+   }
+   return ROK;
+}
  
 /*******************************************************************************
  *
@@ -1369,7 +1458,7 @@ uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
  *
  * @details
  *
- *    Function : searchLargestFreeBlockDL
+ *    Function : searchLargestFreeBlock
  *
  *    Functionality:
  *     Finds the FreeBlock with MaxNum of FREE PRB considering SSB/SIB1 ocassions.
@@ -1377,6 +1466,7 @@ uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
  * @params[in] I/P > prbAlloc table (FreeBlock list)
  *             I/P > Slot timing Info
  *             O/P > Start PRB
+ *             I/P > Direction (UL/DL)
  *       
  *
  * @return Max Number of Free PRB 
@@ -1384,38 +1474,70 @@ uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
  *
  * ********************************************************************************/
 
-uint16_t searchLargestFreeBlockDL(SchCellCb *cell, SlotTimingInfo slotTime,uint16_t *startPrb)
+uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_t *startPrb, Direction dir)
 {
-   uint16_t       broadcastPrbStart=0, broadcastPrbEnd=0, maxFreePRB = 0;
-   PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
+   uint16_t       reservedPrbStart=0, reservedPrbEnd=0, maxFreePRB = 0;
    FreePrbBlock   *freePrbBlock = NULLP;
    CmLList        *freePrbNode = NULLP;
+   SchPrbAlloc    *prbAlloc = NULLP;
+   bool           checkOccasion = FALSE;
 
-   SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
-   SchPrbAlloc    *prbAlloc = &schDlSlotInfo->prbAlloc;
-
-   ssbOccasion = schCheckSsbOcc(cell, slotTime);
-   sib1Occasion = schCheckSib1Occ(cell, slotTime);
+   *startPrb = 0; /*Initialize the StartPRB to zero*/
 
-   if(ssbOccasion && sib1Occasion)
+   /*Based on Direction, Reserved Messsages will differi.e.
+    * DL >> SSB and SIB1 ocassions wheres for UL, PRACH ocassions to be checked
+    * and reserved before allocation for dedicated DL/UL msg*/
+   if(dir == DIR_DL)
    {
-      broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA; 
-      broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
+      SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
+      PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
+
+      prbAlloc = &schDlSlotInfo->prbAlloc;
+
+      ssbOccasion = schCheckSsbOcc(cell, slotTime);
+      sib1Occasion = schCheckSib1Occ(cell, slotTime);
+
+      checkOccasion = TRUE;
+      if(ssbOccasion && sib1Occasion)
+      {
+         reservedPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA; 
+         reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB + \
+                          cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
+      }
+      else if(ssbOccasion)
+      {
+         reservedPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
+         reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB -1;
+      }
+      else if(sib1Occasion)
+      {
+         reservedPrbStart = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.startPrb;
+         reservedPrbEnd = reservedPrbStart + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
+      }
+      else
+      {
+         checkOccasion = FALSE;  
+      }
    }
-   else if(ssbOccasion)
+   else if(dir == DIR_UL)
    {
-      broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
-      broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB -1;
+      prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
+
+      /* Check if PRACH is also scheduled in this slot */
+      checkOccasion = schCheckPrachOcc(cell, slotTime);
+      if(checkOccasion)
+      {
+         reservedPrbStart =  cell->cellCfg.schRachCfg.msg1FreqStart;
+         reservedPrbEnd = reservedPrbStart + (schCalcPrachNumRb(cell)) -1;
+      }
    }
-   else if(sib1Occasion)
+   else
    {
-      broadcastPrbStart = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.startPrb;
-      broadcastPrbEnd = broadcastPrbStart + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
+      DU_LOG("\nERROR --> SCH: Invalid Direction!");
+      return (maxFreePRB);
    }
 
-
    freePrbNode = prbAlloc->freePrbBlockList.first; 
-   *startPrb = 0; /*Initialize the StartPRB to zero*/
    while(freePrbNode)
    {
       freePrbBlock = (FreePrbBlock *)freePrbNode->node;
@@ -1429,27 +1551,27 @@ uint16_t searchLargestFreeBlockDL(SchCellCb *cell, SlotTimingInfo slotTime,uint1
          continue;
       }
 
-      /* If broadcast message is scheduled in this slot, then check if its PRBs belong to the current free block.
+      /* If Broadcast/Prach 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)))
+      if(checkOccasion && 
+            ((reservedPrbStart >= freePrbBlock->startPrb) && (reservedPrbStart <= freePrbBlock->endPrb)) && \
+            ((reservedPrbEnd >= freePrbBlock->startPrb) && (reservedPrbEnd <= 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((freePrbBlock->endPrb > reservedPrbEnd) && ((freePrbBlock->endPrb - reservedPrbEnd) > maxFreePRB))
          {
-            /* If sufficient free PRBs are available above broadcast message*/
-            *startPrb = broadcastPrbEnd + 1;
-            maxFreePRB = (freePrbBlock->endPrb - broadcastPrbEnd);              
+            /* If sufficient free PRBs are available above reserved message*/
+            *startPrb = reservedPrbEnd + 1;
+            maxFreePRB = (freePrbBlock->endPrb - reservedPrbEnd);               
          }
-         /*Also check the other freeBlock (i.e. Above the broadcast message) for MAX FREE PRB*/
-         if((broadcastPrbStart > freePrbBlock->startPrb) && ((broadcastPrbStart - freePrbBlock->startPrb) > maxFreePRB))
+         /*Also check the other freeBlock (i.e. Above the reserved message) for MAX FREE PRB*/
+         if((reservedPrbStart > freePrbBlock->startPrb) && ((reservedPrbStart - freePrbBlock->startPrb) > maxFreePRB))
          {
-            /* If free PRBs are available below broadcast message*/
+            /* If free PRBs are available below reserved message*/
             *startPrb = freePrbBlock->startPrb;
-            maxFreePRB = (broadcastPrbStart - freePrbBlock->startPrb);
+            maxFreePRB = (reservedPrbStart - freePrbBlock->startPrb);
          }
       }
       else  //Best Block
@@ -1466,6 +1588,505 @@ uint16_t searchLargestFreeBlockDL(SchCellCb *cell, SlotTimingInfo slotTime,uint1
    return(maxFreePRB);
 }
 
+/*******************************************************************************
+ *
+ * @brief This function is used to send Slice Cfg rsp to MAC
+ *
+ * @details
+ *
+ *    Function : SchSendSliceCfgRspToMac
+ *
+ *    Functionality:
+ *     function is used to send Slice Cfg rsp to MAC
+ *
+ * @params[in] Pst *pst, SchSliceCfgRsp sliceCfgRsp
+ *
+ * @return- void
+ *
+ * ********************************************************************************/
+void SchSendSliceCfgRspToMac(Inst inst, SchSliceCfgRsp sliceCfgRsp)
+{
+   Pst rspPst;
+   
+   memset(&rspPst, 0, sizeof(Pst));
+   FILL_PST_SCH_TO_MAC(rspPst, inst);
+   rspPst.event = EVENT_SLICE_CFG_RSP_TO_MAC;
+   
+   SchSliceCfgRspOpts[rspPst.selector](&rspPst, &sliceCfgRsp);
+
+}
+/*******************************************************************************
+ *
+ * @brief fill slice configuration response
+ *
+ * @details
+ *
+ *    Function : fillSliceCfgRsp
+ *
+ *    Functionality:
+ *     fill slice configuration response
+ *
+ * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t  count
+ *
+ * @return
+ *        ROK - Success
+ *        RFAILED - Failure
+ *
+ * ********************************************************************************/
+uint8_t fillSliceCfgRsp(bool sliceReCfg, SchSliceCfg *storedSliceCfg, SchCellCb *cellCb, SchSliceCfgReq *schSliceCfgReq, SchSliceCfgRsp *schSliceCfgRsp, uint8_t *count)
+{
+   bool sliceFound = false;
+   uint8_t cfgIdx = 0, sliceIdx = 0;
+
+   schSliceCfgRsp->numSliceCfgRsp  = schSliceCfgReq->numOfConfiguredSlice;
+   SCH_ALLOC(schSliceCfgRsp->listOfSliceCfgRsp, schSliceCfgRsp->numSliceCfgRsp * sizeof(SliceRsp*));
+   if(schSliceCfgRsp->listOfSliceCfgRsp == NULLP)
+   {
+      DU_LOG("\nERROR  --> SCH : Memory allocation failed at fillSliceCfgRsp");
+      return RFAILED;
+   }
+   
+   for(cfgIdx = 0; cfgIdx<schSliceCfgRsp->numSliceCfgRsp ; cfgIdx++)
+   {
+      sliceFound = false;
+      /* Here comparing the slice cfg request with the slice stored in cellCfg */
+      if(sliceReCfg != true)
+      {
+         for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList.numSliceSupport; sliceIdx++)
+         {
+            if(!memcmp(&schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList.snssai[sliceIdx], sizeof(Snssai)))
+            {
+               (*count)++;
+               sliceFound = true;
+               break;
+            }
+         }
+      }
+      else
+      {
+         /* Here comparing the slice cfg request with the slice stored in SchDb */
+         if(storedSliceCfg->listOfConfirguration)
+         {
+            for(sliceIdx = 0; sliceIdx<storedSliceCfg->numOfSliceConfigured; sliceIdx++)
+            {
+               if(!memcmp(&schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai, &storedSliceCfg->listOfConfirguration[sliceIdx]->snssai,\
+                        sizeof(Snssai)))
+               {
+                  (*count)++;
+                  sliceFound = true;
+                  break;
+               }
+            }
+         }
+      }
+
+      SCH_ALLOC(schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx], sizeof(SliceRsp));
+      if(schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx] == NULLP)
+      {
+         DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in fillSliceCfgRsp");
+         return RFAILED;
+      }
+
+      
+      schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->snssai = schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai;
+      if(sliceFound == true)
+         schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->rsp    = RSP_OK;
+      else
+      {
+         schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->rsp    = RSP_NOK;
+         schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->cause  = SLICE_NOT_FOUND;
+      }
+   }
+   return ROK;
+}
+
+/*******************************************************************************
+ *
+ * @brief This function is used to store the slice configuration Sch DB
+ *
+ * @details
+ *
+ *    Function : addSliceCfgInSchDb 
+ *
+ *    Functionality:
+ *     function is used to store the slice configuration Sch DB
+ *
+ * @params[in] SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq,
+ * SchSliceCfgRsp cfgRsp, uint8_t count
+ *
+ * @return
+ *        ROK - Success
+ *        RFAILED - Failure
+ *
+ * ********************************************************************************/
+uint8_t addSliceCfgInSchDb(SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq, SchSliceCfgRsp cfgRsp, uint8_t count)
+{
+   uint8_t cfgIdx = 0, sliceIdx = 0; 
+   
+   if(count)
+   {
+      storeSliceCfg->numOfSliceConfigured = count;
+      SCH_ALLOC(storeSliceCfg->listOfConfirguration, storeSliceCfg->numOfSliceConfigured * sizeof(SchRrmPolicyOfSlice*));
+      if(storeSliceCfg->listOfConfirguration == NULLP)
+      {
+         DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in addSliceCfgInSchDb");
+         return RFAILED;
+      }
+
+      for(cfgIdx = 0; cfgIdx<storeSliceCfg->numOfSliceConfigured; cfgIdx++)
+      {
+         if(cfgRsp.listOfSliceCfgRsp[cfgIdx]->rsp == RSP_OK)
+         {
+            SCH_ALLOC(storeSliceCfg->listOfConfirguration[sliceIdx], sizeof(SchRrmPolicyOfSlice));
+            if(storeSliceCfg->listOfConfirguration[sliceIdx] == NULLP)
+            {
+               DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in addSliceCfgInSchDb");
+               return RFAILED;
+            }
+
+            SCH_ALLOC(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
+            if(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo == NULLP)
+            {
+               DU_LOG("\nERROR  -->  SCH : Failed to allocate memory in addSliceCfgInSchDb");
+               return RFAILED;
+            }
+
+            memcpy(storeSliceCfg->listOfConfirguration[sliceIdx], cfgReq->listOfConfirguration[sliceIdx], sizeof(SchRrmPolicyOfSlice));
+            sliceIdx++;
+         }
+      }
+   }
+   return ROK;
+}
+
+/*******************************************************************************
+ *
+ * @brief This function is used to free the slice cfg and re cfg request pointer
+ *
+ * @details
+ *
+ *    Function : freeSchSliceCfgReq 
+ *
+ *    Functionality:
+ *     function is used to free the slice cfg and re cfg request pointer
+ *
+ * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
+ *
+ * @return
+ *        ROK - Success
+ *        RFAILED - Failure
+ * ********************************************************************************/
+void freeSchSliceCfgReq(SchSliceCfgReq *cfgReq)
+{
+   uint8_t cfgIdx = 0;
+   
+   if(cfgReq)
+   {
+      if(cfgReq->numOfConfiguredSlice)
+      {
+         for(cfgIdx = 0; cfgIdx<cfgReq->numOfConfiguredSlice; cfgIdx++)
+         {
+            if(cfgReq->listOfConfirguration[cfgIdx])
+            {
+               SCH_FREE(cfgReq->listOfConfirguration[cfgIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
+               SCH_FREE(cfgReq->listOfConfirguration[cfgIdx], sizeof(SchRrmPolicyOfSlice));
+            }
+         }
+         SCH_FREE(cfgReq->listOfConfirguration, cfgReq->numOfConfiguredSlice * sizeof(SchRrmPolicyOfSlice*));
+      }
+      SCH_FREE(cfgReq, sizeof(SchSliceCfgReq));
+   }
+}
+/*******************************************************************************
+ *
+ * @brief This function is used to store the slice configuration Sch DB
+ *
+ * @details
+ *
+ *    Function : MacSchSliceCfgReq 
+ *
+ *    Functionality:
+ *     function is used to store the slice configuration Sch DB
+ *
+ * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
+ *
+ * @return
+ *        ROK - Success
+ *        RFAILED - Failure
+ *
+ * ********************************************************************************/
+uint8_t MacSchSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
+{
+   uint8_t count = 0;
+   Inst   inst = pst->dstInst - 1;
+   SchSliceCfgRsp sliceCfgRsp;
+
+   DU_LOG("\nINFO  -->  SCH : Received Slice Cfg request from MAC");
+   if(schSliceCfgReq)
+   {
+      if(schSliceCfgReq->listOfConfirguration)
+      {
+         /* filling the slice configuration response of each slice */
+         if(fillSliceCfgRsp(false, NULLP, schCb[inst].cells[0], schSliceCfgReq, &sliceCfgRsp, &count) != ROK)
+         {
+            DU_LOG("\nERROR  -->  SCH : Failed to fill the slice cfg rsp");
+            return RFAILED;
+         }
+
+         if(addSliceCfgInSchDb(&schCb[inst].sliceCfg, schSliceCfgReq, sliceCfgRsp, count) != ROK)
+         {
+            DU_LOG("\nERROR  -->  SCH : Failed to add slice cfg in sch database");
+            return RFAILED;
+         }
+         freeSchSliceCfgReq(schSliceCfgReq);
+         SchSendSliceCfgRspToMac(inst, sliceCfgRsp);
+      }
+   }
+   else
+   {
+      DU_LOG("\nERROR  -->  SCH : Received SchSliceCfgReq is NULL");
+   }
+   return ROK;
+}
+
+/*******************************************************************************
+ *
+ * @brief This function is used to store the slice reconfiguration Sch DB
+ *
+ * @details
+ *
+ *    Function : modifySliceCfgInSchDb 
+ *
+ *    Functionality:
+ *     function is used to store the slice re configuration Sch DB
+ *
+ * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
+ *
+ * @return
+ *        ROK - Success
+ *        RFAILED - Failure
+ *
+ * ********************************************************************************/
+uint8_t modifySliceCfgInSchDb(SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq, SchSliceCfgRsp cfgRsp, uint8_t count)
+{
+   uint8_t cfgIdx = 0, sliceIdx = 0; 
+
+   if(count)
+   {
+      if(storeSliceCfg->listOfConfirguration == NULLP)
+      {
+         DU_LOG("\nINFO  -->  SCH : Memory allocation failed in modifySliceCfgInSchDb");
+         return RFAILED;
+      }
+
+      for(cfgIdx = 0; cfgIdx<cfgReq->numOfConfiguredSlice; cfgIdx++)
+      {
+         if(cfgRsp.listOfSliceCfgRsp[cfgIdx]->rsp == RSP_OK)
+         {
+            for(sliceIdx = 0; sliceIdx<storeSliceCfg->numOfSliceConfigured; sliceIdx++)
+            {
+               if(!memcmp(&storeSliceCfg->listOfConfirguration[sliceIdx]->snssai, &cfgReq->listOfConfirguration[cfgIdx]->snssai, sizeof(Snssai)))
+               {
+                  storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo = cfgReq->listOfConfirguration[cfgIdx]->rrmPolicyRatioInfo;
+                  break;
+               }
+            }
+         }
+      }
+   }
+   freeSchSliceCfgReq(cfgReq);
+   return ROK;
+}
+/*******************************************************************************
+ *
+ * @brief This function is used to send Slice re Cfg rsp to MAC
+ *
+ * @details
+ *
+ *    Function : SchSendSliceCfgRspToMac
+ *
+ *    Functionality:
+ *     function is used to send Slice re Cfg rsp to MAC
+ *
+ * @params[in] Pst *pst, SchSliceCfgRsp schSliceReCfgRsp
+ *
+ * @return- void
+ *
+ * ********************************************************************************/
+void SchSendSliceReCfgRspToMac(Inst inst, SchSliceCfgRsp schSliceReCfgRsp)
+{
+   Pst rspPst;
+   
+   memset(&rspPst, 0, sizeof(Pst));
+   FILL_PST_SCH_TO_MAC(rspPst, inst);
+   rspPst.event = EVENT_SLICE_RECFG_RSP_TO_MAC;
+   
+   SchSliceReCfgRspOpts[rspPst.selector](&rspPst, &schSliceReCfgRsp);
+}
+/*******************************************************************************
+ *
+ * @brief This function is used to store the slice reconfiguration Sch DB
+ *
+ * @details
+ *
+ *    Function : MacSchSliceReCfgReq 
+ *
+ *    Functionality:
+ *     function is used to store the slice re configuration Sch DB
+ *
+ * @params[in] Pst *pst, SchSliceCfgReq *schSliceReCfgReq
+ *
+ * @return
+ *        ROK - Success
+ *        RFAILED - Failure
+ *
+ * ********************************************************************************/
+uint8_t MacSchSliceReCfgReq(Pst *pst, SchSliceCfgReq *schSliceReCfgReq)
+{
+   uint8_t count = 0;
+   Inst   inst = pst->dstInst - 1;
+   SchSliceCfgRsp schSliceReCfgRsp;
+
+   DU_LOG("\nINFO  -->  SCH : Received Slice ReCfg request from MAC");
+   if(schSliceReCfgReq)
+   {
+      if(schSliceReCfgReq->listOfConfirguration)
+      {
+         /* filling the slice configuration response of each slice */
+         if(fillSliceCfgRsp(true, &schCb[inst].sliceCfg, NULLP, schSliceReCfgReq, &schSliceReCfgRsp, &count) != ROK)
+         {
+            DU_LOG("\nERROR  -->  SCH : Failed to fill sch slice cfg response");
+            return RFAILED;
+         }
+         
+         /* Modify the slice configuration stored in schCb */
+         if(modifySliceCfgInSchDb(&schCb[inst].sliceCfg, schSliceReCfgReq, schSliceReCfgRsp, count) != ROK)
+         {
+            DU_LOG("\nERROR  -->  SCH : Failed to modify slice cfg of SchDb");
+            return RFAILED;
+         }
+         SchSendSliceReCfgRspToMac(inst, schSliceReCfgRsp);
+      }
+   }
+   else
+   {
+      DU_LOG("\nERROR  -->  SCH : Received SchSliceCfgReq is NULL");
+   }
+   return ROK;
+}
+
+/****************************************************************************
+ *
+ * @brief Stores the Paging Configuration from DU APP in CellCb 
+ *
+ * @details
+ *
+ *    Function : schProcPagingParam
+ *
+ *    Functionality:
+ *          Process the Paging Configuration when FirstPDCCHMonitoring for
+ *          Paging Ocassion is not present.
+ *
+ *          As per 38.304 Sec 7.1,
+ *          "When firstPDCCH-MonitoringOccasionOfPO is present, the
+ *          starting PDCCH monitoring occasion number of (i_s + 1)th PO is the
+ *          (i_s + 1)th value of the firstPDCCHMonitoringOccasionOfPO
+ *          parameter; otherwise, it is equal to i_s * S."
+ *          "S = number of actual transmitted SSBs determined according 
+ *              to ssb-PositionsInBurst in SIB1"
+ *
+ * @params[in] SchCellCb *cell 
+ *       
+ * @return void 
+ *        
+ *************************************************************************/
+void schProcPagingCfg(SchCellCb *cell)
+{
+   PageCfg *pageCfgRcvd = NULL;
+   uint8_t i_sIdx = 0;
+
+   pageCfgRcvd = &(cell->cellCfg.sib1SchCfg.pageCfg);
+
+   if(pageCfgRcvd->poPresent == TRUE)
+   {
+      /*Fetching first Pdcch Monitoring Occasion for SFN (i_s + 1)th*/
+      for(i_sIdx = 0; i_sIdx < pageCfgRcvd->numPO; i_sIdx++)
+      {
+         cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pageCfgRcvd->pagingOcc[i_sIdx] / MAX_SYMB_PER_SLOT ;
+         if ((pageCfgRcvd->pagingOcc[i_sIdx] % MAX_SYMB_PER_SLOT) != 0 )
+         {
+            cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot++;
+         }
+
+         cell->pageCb.pagMonOcc[i_sIdx].frameOffset = 0;
+
+      }
+   }
+   else
+   {
+      schCfgPdcchMonOccOfPO(cell);                  
+   }
+}
+
+/****************************************************************************
+ *
+ * @brief Calculate PO if not present in Configuration 
+ *
+ * @details
+ *
+ *    Function : schCfgPdcchMonOccOfPO
+ *
+ *    Functionality: In this function, PO are calculated i_s * S because
+ *    FirstPDCCHMonitoring_ForPO is not present.
+ *
+ * @params[in] SchCellCb *cellCb
+ *       
+ * @return void 
+ *        
+ *************************************************************************/
+void schCfgPdcchMonOccOfPO(SchCellCb *cell)
+{
+   uint8_t         cnt = 0, incr = 1, i_sIdx = 0, frameOffSet = 0;
+   uint8_t         nsValue = cell->cellCfg.sib1SchCfg.pageCfg.numPO;
+   uint8_t         totalNumSsb = cell->cellCfg.ssbSchCfg.totNumSsb;
+   SlotTimingInfo  tmpTimingInfo, pdcchTime; 
+
+   /*Starting with First Sfn and slot*/
+   tmpTimingInfo.sfn = 0;
+   tmpTimingInfo.slot = 0;
+
+   pdcchTime = tmpTimingInfo;
+
+   while(i_sIdx < nsValue)
+   {
+      /*Increment frame Offset if PO falls on next SFN*/
+      if(pdcchTime.sfn != tmpTimingInfo.sfn)
+      {
+         frameOffSet++;
+      }
+      pdcchTime = tmpTimingInfo;
+      schIncrSlot(&(tmpTimingInfo), incr, cell->numSlots);
+
+      if (i_sIdx == 0)
+      {
+         cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
+         cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
+         i_sIdx++;
+      }
+      else
+      {
+         cnt++;
+         if((cnt == totalNumSsb) && (i_sIdx < MAX_PO_PER_PF)) 
+         {
+            cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
+            cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
+            cnt = 0;
+            i_sIdx++;
+         }
+      }
+   }
+}
+
 /**********************************************************************
   End of file
  **********************************************************************/