FCFS.c problem fix 75/12975/1 review/bimo_fransiscus_asisi/11653
authorjohnson72 <d11002806@gapps.ntust.edu.tw>
Tue, 23 Jul 2024 10:08:01 +0000 (18:08 +0800)
committerjohnson72 <d11002806@gapps.ntust.edu.tw>
Tue, 23 Jul 2024 10:18:06 +0000 (18:18 +0800)
Change-Id: Ie4defcd6436184323b4d562687de02cc2cc31d7e
Signed-off-by: johnson72 <d11002806@gapps.ntust.edu.tw>
18 files changed:
src/5gnrrlc/rlc_cfg_dl.c
src/5gnrrlc/rlc_layer_mgr.c
src/5gnrrlc/rlc_tmr.c
src/5gnrrlc/rlc_upr_inf_mgr.c
src/5gnrrlc/rlc_utils.h
src/5gnrrlc/rlc_utl_dl.c
src/5gnrsch/sch.c
src/5gnrsch/sch.h
src/5gnrsch/sch_fcfs.c
src/5gnrsch/sch_slice_based.c
src/5gnrsch/sch_slice_based.h
src/5gnrsch/sch_slot_ind.c
src/5gnrsch/sch_ue_mgr.c
src/5gnrsch/sch_utils.c
src/5gnrsch/sch_utils.h
src/cm/common_def.h
src/cm/rgu.h
src/du_app/du_cfg.c

index a42e44d..f4728fb 100755 (executable)
@@ -416,6 +416,13 @@ static S16 rlcCfgFillDlRbCb(RlcCb *gCb,RlcDlRbCb *rbCb,RlcDlUeCb *ueCb,RlcEntCfg
       {
          DU_LOG("\nERROR  --> RLC_DL : rlcCfgFillDlRbCb(): SNSSAI insertion in Tput list failed");
       }
+
+      /* Dennis: Initialize the drbTput data structure */
+      if(rlcHandleDrbTputlist(gCb, rbCb->snssai, rbCb->rlcId.ueId, \
+                              rbCb->lch.lChId, CREATE, DIR_DL) == NULLP)
+      {
+         DU_LOG("\nERROR  --> RLC_DL : rlcCfgFillDlRbCb(): DRB insertion in Tput list failed");
+      }
    }
    rbCb->mode = entCfg->entMode;
    rbCb->discTmrInt = entCfg->discardTmr;
index 304e60e..759ae4c 100755 (executable)
@@ -178,6 +178,7 @@ static S16 rlcLmmGenCfg(RlcCb  *gCb,RlcGenCfg *cfg)
    memset(gCb->rlcThpt.ueTputInfo.thptPerUe, 0, MAX_NUM_UE * sizeof(RlcThptPerUe));
 
    gCb->rlcThpt.snssaiTputInfo.snssaiThptTmr.tmrEvnt = TMR_NONE;
+   gCb->rlcThpt.drbTputInfo.drbThptTmr.tmrEvnt = TMR_NONE;
    
    if(gCb->genCfg.rlcMode == LKW_RLC_MODE_DL)
    {
@@ -409,6 +410,12 @@ static S16 rlcLmmGenCfg(RlcCb  *gCb,RlcGenCfg *cfg)
          rlcStartTmr(gCb, (PTR)(&gCb->rlcThpt), EVENT_RLC_SNSSAI_THROUGHPUT_TMR);
       }
 
+      /* Starting timer to print DRB throughput */
+      if((rlcChkTmr(gCb, (PTR)(&gCb->rlcThpt), EVENT_RLC_DRB_THROUGHPUT_TMR)) == FALSE)
+      {
+         DU_LOG("\nINFO    --> RLC_DL : Starting DRB Throughput timer");
+         rlcStartTmr(gCb, (PTR)(&gCb->rlcThpt), EVENT_RLC_DRB_THROUGHPUT_TMR);
+      }
    
    return (LCM_REASON_NOT_APPL);
 } 
index 0c7234e..eba0cfe 100755 (executable)
@@ -202,10 +202,19 @@ void rlcStartTmr(RlcCb *gCb, PTR cb, int16_t tmrEvnt)
          arg.max = RLC_MAX_THPT_TMR; 
          break;
       }
+      case EVENT_RLC_DRB_THROUGHPUT_TMR:
+      {
+         RlcThpt *thptCb = (RlcThpt *)cb;
+         RLC_TMR_CALCUATE_WAIT(arg.wait, ODU_DRB_THROUGHPUT_PRINT_TIME_INTERVAL, gCb->genCfg.timeRes);
+         arg.timers = &thptCb->drbTputInfo.drbThptTmr;
+         arg.max = RLC_MAX_THPT_TMR; 
+         break;
+      }
       default:
       {
          DU_LOG("\nERROR  -->  RLC : rlcStartTmr: Invalid tmr Evnt [%d]", tmrEvnt);
       }
+      
    } 
 
    if(arg.wait != 0)
@@ -302,6 +311,12 @@ void rlcStopTmr(RlcCb *gCb, PTR cb, uint8_t tmrType)
          arg.max  = RLC_MAX_THPT_TMR;
          break;
       }
+      case EVENT_RLC_DRB_THROUGHPUT_TMR:
+      {
+         arg.timers   = &((RlcThpt *)cb)->drbTputInfo.drbThptTmr;
+         arg.max = RLC_MAX_THPT_TMR; 
+         break;
+      }
       default:
       {
          DU_LOG("\nERROR  -->  RLC : rlcStopTmr: Invalid tmr Evnt[%d]", tmrType);
@@ -391,6 +406,11 @@ Void rlcTmrExpiry(PTR cb,S16 tmrEvnt)
          rlcSnssaiThptTmrExpiry(cb);
          break;
       }
+      case EVENT_RLC_DRB_THROUGHPUT_TMR:
+      {
+         rlcDrbThptTmrExpiry(cb);
+         break;
+      }
       default:
       {
          break;
@@ -452,6 +472,10 @@ bool rlcChkTmr(RlcCb *gCb, PTR cb, int16_t tmrEvnt)
       {
          return (((RlcThpt *)cb)->snssaiTputInfo.snssaiThptTmr.tmrEvnt == EVENT_RLC_SNSSAI_THROUGHPUT_TMR);
       }
+      case EVENT_RLC_DRB_THROUGHPUT_TMR:
+      {
+         return (((RlcThpt *)cb)->drbTputInfo.drbThptTmr.tmrEvnt == EVENT_RLC_DRB_THROUGHPUT_TMR);
+      }
       default:
       {
          DU_LOG("\nERROR  -->  RLC : rlcChkTmr: Invalid tmr Evnt [%d]", tmrEvnt);
@@ -561,7 +585,7 @@ void rlcUeThptTmrExpiry(PTR cb)
              */
              tpt = (double)(rlcThptCb->ueTputInfo.thptPerUe[ueIdx].dataVol * 8)/(double)ODU_UE_THROUGHPUT_PRINT_TIME_INTERVAL;
       
-             DU_LOG("\nUE Id : %d   DL Tpt : %.2Lf", rlcThptCb->ueTputInfo.thptPerUe[ueIdx].ueId, tpt);
+             DU_LOG("\nUE Id : %d   DL Tpt : %.2Lf (Kbps)", rlcThptCb->ueTputInfo.thptPerUe[ueIdx].ueId, tpt);
              rlcThptCb->ueTputInfo.thptPerUe[ueIdx].dataVol = 0;
          }
       }
@@ -622,6 +646,43 @@ void rlcSnssaiThptTmrExpiry(PTR cb)
    rlcStartTmr(RLC_GET_RLCCB(rlcThptCb->inst), (PTR)rlcThptCb, EVENT_RLC_SNSSAI_THROUGHPUT_TMR);
    return;
 }
+
+/**
+ * @brief Handler to do processing on expiry of the DRB throughput timer
+ *
+ * @details
+ *    This function processes the RLC DRB throughput timer expiry.
+ *
+ * @param[in] cb  Pointer to the RLC throughput struct
+ *
+ * @return  Void
+ */
+void rlcDrbThptTmrExpiry(PTR cb)
+{
+   RlcThpt *rlcThptCb = (RlcThpt*)cb; 
+   uint16_t  ueIdx;
+
+   /* If cell is not up, throughput details cannot be printed */
+   if(gCellStatus != CELL_UP)
+   {
+      /* Restart timer */
+      rlcStartTmr(RLC_GET_RLCCB(rlcThptCb->inst), (PTR)(rlcThptCb), EVENT_RLC_DRB_THROUGHPUT_TMR);
+      return;
+   }
+   
+   for(ueIdx = 0; ueIdx < MAX_NUM_UE; ueIdx++)
+   {
+      if(rlcThptCb->drbTputInfo.dlTputPerDrbList[ueIdx] != NULLP)
+      {
+         rlcCalculateTputPerDrb(rlcThptCb->drbTputInfo.dlTputPerDrbList[ueIdx], DIR_DL);
+      }
+   }
+
+   /* Restart timer */
+   rlcStartTmr(RLC_GET_RLCCB(rlcThptCb->inst), (PTR)rlcThptCb, EVENT_RLC_DRB_THROUGHPUT_TMR);
+   return;
+}
+
 /**
 *
 * @brief filling RLC UE delete configuration
index a717adf..f1b952a 100755 (executable)
@@ -1074,16 +1074,16 @@ uint8_t rlcCalculateTputPerSnssai(CmLListCp *snssaiList, Direction dir)
    while(node)
    {
       snssaiNode = (RlcTptPerSnssai *)node->node;
-      snssaiNode->tpt =  (double)(snssaiNode->dataVol * 8)/(double)(ODU_SNSSAI_THROUGHPUT_PRINT_TIME_INTERVAL * 0.001);
+      snssaiNode->tpt =  (double)(snssaiNode->dataVol * 8)/(double)(ODU_SNSSAI_THROUGHPUT_PRINT_TIME_INTERVAL);
      
       if(dir == DIR_DL)
       {
-         DU_LOG("\nDEBUG  -->  RLC_DL: SNSSAI(sst:%d,sd [%d,%d, %d]), DL Tpt : %.5lf", snssaiNode->snssai->sst,\
+         DU_LOG("\nDEBUG  -->  RLC_DL: SNSSAI(sst:%d,sd [%d,%d, %d]), DL Tpt : %.5lf (kbps)", snssaiNode->snssai->sst,\
                snssaiNode->snssai->sd[0], snssaiNode->snssai->sd[1],snssaiNode->snssai->sd[2] , snssaiNode->tpt);
       }
       if(dir == DIR_UL)
       {
-         DU_LOG("\nDEBUG  -->  RLC_UL: SNSSAI(sst:%d,sd [%d,%d, %d]), UL Tpt : %.5lf", snssaiNode->snssai->sst,\
+         DU_LOG("\nDEBUG  -->  RLC_UL: SNSSAI(sst:%d,sd [%d,%d, %d]), UL Tpt : %.5lf (kbps)", snssaiNode->snssai->sst,\
                snssaiNode->snssai->sd[0], snssaiNode->snssai->sd[1],snssaiNode->snssai->sd[2] , snssaiNode->tpt);
       }
 
@@ -1094,6 +1094,257 @@ uint8_t rlcCalculateTputPerSnssai(CmLListCp *snssaiList, Direction dir)
    return(snssaiCnt);
 }
 
+/**
+ * @brief 
+ *    Handler for Creating, Searching or Deleting DrbTput List. 
+ *
+ * @details
+ *    This function is called whenever a new LC is configured with a snssai.
+ *
+ * @param[in] gCb            RlcCb 
+ * @param[in] snssai         Snssai to be handled
+ * @param[in] ueId           UE ID
+ * @param[in] lcId           LC ID
+ * @param[in] Action         Type of action to be handled(Create,Search,Delete)
+ *
+ * @return  RlcTptPerSnssai
+ *    -# Snssai Node
+ *   
+ */
+RlcTptPerDrb* rlcHandleDrbTputlist(RlcCb *gCb, Snssai *snssai, uint8_t ueId, uint8_t lcId, ActionTypeLL action, Direction dir)
+{
+   CmLListCp *drbList = NULLP;
+   CmLList  *node = NULLP;
+   RlcTptPerDrb *drbNode = NULLP;
+   bool found = FALSE;
+
+   if(dir == DIR_DL)
+   {
+      drbList = gCb->rlcThpt.drbTputInfo.dlTputPerDrbList[ueId-1];
+      if(action == CREATE)
+      {
+         if(drbList == NULLP)
+         {
+            RLC_ALLOC(gCb, gCb->rlcThpt.drbTputInfo.dlTputPerDrbList[ueId-1], sizeof(CmLListCp));
+            drbList = gCb->rlcThpt.drbTputInfo.dlTputPerDrbList[ueId-1];
+            cmLListInit(drbList);
+         }
+      }
+      else
+      {
+         if(drbList == NULLP)
+         {
+            DU_LOG("\nERROR --> RLC: DRB DL list doesnt exist!");
+            return NULLP;
+         }
+      }
+   }
+   else
+   {
+      DU_LOG("\nERROR  -->  RLC : Direction:%d is invalid", dir);
+      return NULLP;
+   }
+
+   node = drbList->first;
+
+   /*Traversing the LC LinkList*/
+   while(node)
+   {
+      drbNode = (RlcTptPerDrb *)node->node;
+      if(drbNode->lcId == lcId)
+      { 
+         //DU_LOG("\nDEBUG  -->  RLC : LC ID found in LL");
+         found = TRUE;
+         break;
+      }
+      node = node->next;
+   }//end of while
+
+   switch(action)
+   {
+      case SEARCH:
+         {
+            if(!found)
+            {
+               drbNode = NULLP;
+            }
+            return (drbNode);
+         }
+
+      case CREATE:
+         {
+            if(found)
+               return (drbNode);
+
+            drbNode = NULLP;
+            /*Allocate the List*/
+            RLC_ALLOC(gCb, drbNode, sizeof(RlcTptPerDrb));
+            if(drbNode)
+            {
+               RLC_ALLOC(gCb, drbNode->snssai, sizeof(Snssai));
+               if(drbNode->snssai == NULLP)
+               {
+                 DU_LOG("\nERROR  --> RLC : Allocation of DRB node failed");
+                 return NULLP;
+               }
+               memcpy(drbNode->snssai,snssai,sizeof(Snssai));
+               drbNode->lcId = lcId;
+               drbNode->ueId = ueId;
+               drbNode->dataVol = 0;
+            }
+            else
+            {
+               DU_LOG("\nERROR  --> RLC : Allocation of DRB node failed");
+               return NULLP;
+            }
+
+            node = NULLP;
+            RLC_ALLOC(gCb, node, sizeof(CmLList));
+            if(node)
+            {
+               node->node = (PTR)drbNode;
+               cmLListAdd2Tail(drbList, node);
+            }
+            else
+            {
+               DU_LOG("\nERROR  --> RLC : Allocation of DRB node failed");
+               return NULLP;
+            }
+            DU_LOG("\nDEBUG  --> RLC : DRB node added successfully");
+            return (drbNode);
+         }
+
+      case DELETE:
+         {
+            if(found && node)
+            {
+               node = cmLListDelFrm(drbList, node);
+               RLC_FREE(gCb, node, sizeof(CmLList));
+               RLC_FREE(gCb, drbNode, sizeof(RlcTptPerDrb));
+               DU_LOG("\nDEBUG  --> RLC : DRB node found and deletion performed");
+
+               if(drbList->count == 0)
+               {
+                  RLC_FREE(gCb, drbList, sizeof(CmLListCp));
+                  DU_LOG("\nINFO   --> RLC : This DRB was last in the list thus freeing the list also");
+               }
+            }
+            else
+            {
+               DU_LOG("\nERROR  --> RLC : DRB node not found in List thus no deletion performed");
+            }
+            return NULLP;
+         }
+       case PRINT:
+       case TRAVERSE_ALL:
+         {
+            break;
+         }
+       default:
+         {
+            DU_LOG("\nERROR  -> RLC: Incorrect ActionType:%d",action);
+            break;
+         }
+   }
+   return (drbNode);
+}
+
+/**
+ * @brief 
+ *    Handler for Deleting DrbTput List. 
+ *
+ * @details
+ *    This function is called during Shutdown to remove all the DRB entries
+ *    and deallocate the DRB tput list as well
+ *
+ * @param[in] gCb            RlcCb 
+ *
+ * @return uint_8 (ROK/RFAILED)
+ *   
+ */
+uint8_t rlcDelTputDrbList(RlcCb *gCb, Direction dir)
+{
+   CmLListCp *drbList = NULLP;
+   CmLList  *node = NULLP, *next = NULLP;
+   RlcTptPerSnssai *drbNode = NULLP;
+   if(dir == DIR_DL)
+   {
+      drbList = gCb->rlcThpt.drbTputInfo.dlTputPerDrbList;
+   }
+   else
+   {
+      DU_LOG("\nERROR  -->  RLC: Invalid direction:%d",dir);
+      return RFAILED;
+   }
+   if(drbList == NULLP)
+   {
+      DU_LOG("\nERROR -->  RLC: DrbList not exist");
+      return RFAILED;
+   }
+   node = drbList->first;
+
+   /*Traversing the LC LinkList*/
+   while(node)
+   {
+      drbNode = (RlcTptPerDrb *)node->node;
+      next = node->next;
+      node = cmLListDelFrm(drbList, node);
+      RLC_FREE(gCb, node, sizeof(CmLList));
+      RLC_FREE(gCb, drbNode, sizeof(RlcTptPerDrb));
+      node = next;
+   }
+   if(drbList->count == 0)
+   {
+      RLC_FREE(gCb, drbList, sizeof(CmLListCp));
+      DU_LOG("\nDEBUG   -->  RLC : This DRB node was last in the list thus freeing the list also");
+   }
+   return ROK;
+}
+
+/**
+ * @brief 
+ *    Handler for calculating the Tput for each DRB in Tput list after expiry. 
+ *
+ * @details
+ *    This function is called whenever DRB Tput timer expires and calculate
+ *    Tput for each DRB in list
+ *
+ * @param[in] DRBList     A list of DRB
+ *
+ * @return void 
+ *   
+ */
+uint8_t rlcCalculateTputPerDrb(CmLListCp *drbList, Direction dir)
+{
+   CmLList  *node = NULLP;
+   RlcTptPerDrb *drbNode = NULLP;
+   uint8_t drbCnt = 0;
+
+   node = drbList->first;
+   if(node == NULLP)
+   {
+      DU_LOG("\n No DRB in list");
+      return(drbCnt);
+   }
+   /*Traversing the LC LinkList*/
+   while(node)
+   {
+      drbNode = (RlcTptPerDrb *)node->node;
+      drbNode->tpt =  (double)(drbNode->dataVol * 8)/(double)(ODU_DRB_THROUGHPUT_PRINT_TIME_INTERVAL);
+     
+      if(dir == DIR_DL)
+      {
+         DU_LOG("\nDEBUG  -->  Tput per DRB: UE ID: %d, LC ID: %d, SNSSAI(sst:%d,sd [%d,%d,%d]), DL Tpt : %.5lf (kbps)", \
+         drbNode->ueId, drbNode->lcId, drbNode->snssai->sst, drbNode->snssai->sd[0], drbNode->snssai->sd[1], \
+         drbNode->snssai->sd[2] , drbNode->tpt);
+      }
+
+      drbNode->dataVol = 0;
+      node = node->next;
+      drbCnt++;
+   }
+   return(drbCnt);
+}
 /********************************************************************30**
          End of file
 **********************************************************************/
index caf2c7e..b3c2215 100755 (executable)
@@ -469,6 +469,7 @@ extern "C" {
 #define EVENT_RLC_UE_THROUGHPUT_TMR       7
 #define EVENT_RLC_UE_DELETE_TMR           8
 #define EVENT_RLC_SNSSAI_THROUGHPUT_TMR   9
+#define EVENT_RLC_DRB_THROUGHPUT_TMR   10
 
 /* Wait time for RLC Timers */
 #define RLC_UE_DELETE_WAIT_TIME           5 /*in milliseconds */
@@ -1721,6 +1722,20 @@ typedef struct rlcTptPerSnssai
    double   tpt;
 }RlcTptPerSnssai;
 
+typedef struct rlcTptPerDrb
+{
+   uint8_t   lcId;
+   uint8_t   ueId;
+   Snssai   *snssai;
+   uint64_t dataVol;
+   double   tpt;
+}RlcTptPerDrb;
+
+typedef struct rlcDrbTputInfo
+{
+   CmTimer       drbThptTmr;                   /* Throughput Timer */
+   CmLListCp     *dlTputPerDrbList[MAX_NUM_UE];   /* Linked List of rlcTptPerDrb */
+}RlcDrbTputInfo;
 
 typedef struct rlcSnssaiTputInfo
 {
@@ -1744,6 +1759,7 @@ typedef struct rlcThpt
    Inst               inst;                /* RLC instance */
    RlcUeTputInfo      ueTputInfo;
    RlcSnssaiTputInfo  snssaiTputInfo;
+   RlcDrbTputInfo     drbTputInfo;
 }RlcThpt;
 
 /** 
@@ -1802,6 +1818,8 @@ void rlcUeThptTmrExpiry(PTR cb);
 uint8_t  rlcUeDeleteTmrExpiry(PTR cb);
 
 void rlcSnssaiThptTmrExpiry(PTR cb);
+
+void rlcDrbThptTmrExpiry(PTR cb);
 RlcTptPerSnssai* rlcHandleSnssaiTputlist(RlcCb *gCb, Snssai *snssai,\
                                 ActionTypeLL  action, Direction dir);
 uint8_t rlcCalculateTputPerSnssai(CmLListCp *snssaiList, Direction dir);
@@ -1809,6 +1827,10 @@ uint8_t rlcDelTputSnssaiList(RlcCb *gCb, Direction dir);
 uint8_t BuildSliceReportToDu(uint8_t snssaiCnt);
 bool rlcFindSliceEntry(SliceIdentifier snssaiVal, uint8_t *snssaiIdx,\
                       SlicePmList *sliceStats);
+RlcTptPerDrb* rlcHandleDrbTputlist(RlcCb *gCb, Snssai *snssai, uint8_t ueId, \
+                           uint8_t lcId, ActionTypeLL action, Direction dir);
+uint8_t rlcDelTputDrbList(RlcCb *gCb, Direction dir);
+uint8_t rlcCalculateTputPerDrb(CmLListCp *drbList, Direction dir);
 
 #ifdef LTE_L2_MEAS
 Void rlcLmmSendAlarm ARGS (( RlcCb *gCb,
index 870ff96..595a7d5 100755 (executable)
@@ -446,6 +446,7 @@ uint8_t rlcUtlSendToMac(RlcCb *gCb, SuId suId, KwDStaIndInfo *staIndInfo)
    //Debug
    uint32_t staIndSz=0,datIndSz = 0;
    RlcTptPerSnssai *snssaiTputNode = NULLP;
+   RlcTptPerDrb *drbTputNode = NULLP;
 
    datReqInfo = NULLP;
    RLC_ALLOC_SHRABL_BUF(RLC_MEM_REGION_DL, RLC_POOL,
@@ -515,6 +516,16 @@ uint8_t rlcUtlSendToMac(RlcCb *gCb, SuId suId, KwDStaIndInfo *staIndInfo)
                      DU_LOG("\nINFO   -->  RLC_DL: SNSSAI List Grant:%d, lcId:%d, total :%ld",\
                            staIndTb->lchStaInd[count].totBufSize, staIndTb->lchStaInd[count].lcId,\
                            snssaiTputNode->dataVol);
+
+                  }
+
+                  drbTputNode = rlcHandleDrbTputlist(gCb, rbCb->snssai, ueId, staIndTb->lchStaInd[count].lcId, SEARCH, DIR_DL);
+                  if(drbTputNode != NULLP)
+                  {
+                     drbTputNode->dataVol += staIndTb->lchStaInd[count].totBufSize;
+                     //DU_LOG("\nINFO   -->  RLC_DL: DRB List Grant:%d, lcId:%d, total :%ld",\
+                           staIndTb->lchStaInd[count].totBufSize, staIndTb->lchStaInd[count].lcId,\
+                           drbTputNode->dataVol);
                   }
                }
 
index 2278e09..5b36ec1 100644 (file)
@@ -1884,8 +1884,10 @@ void freeSchSliceCfgReq(SchSliceCfgReq *sliceCfgReq)
 uint8_t SchProcSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
 {
    uint8_t ret = ROK;
+   SchCellCb *cellCb;
    Inst   inst = pst->dstInst - SCH_INST_START;
 
+   cellCb = schCb[inst].cells[0];
    DU_LOG("\nINFO  -->  SCH : Received Slice Cfg request from MAC");
    if(schSliceCfgReq)
    {
@@ -1897,6 +1899,10 @@ uint8_t SchProcSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
             DU_LOG("\nERROR  -->  SCH : Failed to fill the slice cfg rsp");
             ret = RFAILED;
          }
+         else
+         {
+            cellCb->api->SchSliceCfgReq(cellCb);
+         }
          freeSchSliceCfgReq(schSliceCfgReq);
       }
    }
@@ -2011,7 +2017,9 @@ uint8_t SchProcSliceRecfgReq(Pst *pst, SchSliceRecfgReq *schSliceRecfgReq)
 {
    uint8_t ret = ROK;
    Inst   inst = pst->dstInst - SCH_INST_START;
+   SchCellCb *cellCb;
 
+   cellCb = schCb[inst].cells[0];
    DU_LOG("\nINFO  -->  SCH : Received Slice ReCfg request from MAC");
    if(schSliceRecfgReq)
    {
@@ -2023,6 +2031,10 @@ uint8_t SchProcSliceRecfgReq(Pst *pst, SchSliceRecfgReq *schSliceRecfgReq)
             DU_LOG("\nERROR  -->  SCH : Failed to fill sch slice cfg response");
             ret = RFAILED;
          }
+         else
+         {
+            cellCb->api->SchSliceRecfgReq(cellCb);
+         }
          freeSchSliceCfgReq(schSliceRecfgReq);
       }
    }
index 4feaa18..7054294 100644 (file)
@@ -367,6 +367,7 @@ typedef struct schLcCtxt
 {
    uint8_t lcId;     // logical Channel ID
    uint8_t lcp;      // logical Channel Prioritization
+   uint16_t   fiveQi; // 5QI
    SchLcState lcState;
    uint32_t bo;
    uint16_t   pduSessionId; /*Pdu Session Id*/
@@ -565,6 +566,8 @@ typedef struct schAllApis
    void (* SchDlRlcBoInfo)(SchCellCb *cellCb, uint16_t ueId);
    void (* SchSrUciInd)(SchCellCb *cellCb, uint16_t ueId);
    void (* SchBsr)(SchCellCb *cellCb, uint16_t ueId);
+   void (* SchSliceCfgReq)(SchCellCb *cellCb);
+   void (* SchSliceRecfgReq)(SchCellCb *cellCb);
    void (* SchHandleLcList)(void *ptr, CmLList *node, ActionTypeLL action);
    void (* SchAddToDlHqRetxList)(SchDlHqProcCb *hqP);
    void (* SchAddToUlHqRetxList)(SchUlHqProcCb *hqP);
index edfad66..898de1a 100644 (file)
@@ -167,6 +167,44 @@ void SchFcfsModUeConfigReq(SchUeCb *ueCb)
    return;
 }
 
+/*******************************************************************
+ *
+ * @brief Handles Slice configuration request
+ *
+ * @details
+ *
+ *    Function : schFcfsSliceCfgReq
+ *
+ *    Functionality: 
+ *
+ * @params[in] Pointer to Cell control block
+ * @return void
+ *
+ * ****************************************************************/
+void schFcfsSliceCfgReq(SchCellCb *cellCb)
+{
+   return;
+}
+
+/*******************************************************************
+ *
+ * @brief Handles Slice Reconfiguration request
+ *
+ * @details
+ *
+ *    Function : schFcfsSliceRecfgReq
+ *
+ *    Functionality: 
+ *
+ * @params[in] Pointer to Cell control block
+ * @return void
+ *
+ * ****************************************************************/
+void schFcfsSliceRecfgReq(SchCellCb *cellCb)
+{
+   return;
+}
+
 /*******************************************************************
  *
  * @brief Handles UE Delete Request
@@ -1356,6 +1394,8 @@ void schFcfsAllApisInit(SchAllApis *allFcfsApi)
     allFcfsApi->SchDlRlcBoInfo = schFcfsDlRlcBoInfo;
     allFcfsApi->SchSrUciInd = schFcfsSrUciInd;
     allFcfsApi->SchBsr = schFcfsBsr;
+    allFcfsApi->SchSliceCfgReq = schFcfsSliceCfgReq;
+    allFcfsApi->SchSliceRecfgReq = schFcfsSliceRecfgReq;
 
     /* Internal API function pointers */
     allFcfsApi->SchAddToDlHqRetxList = schFcfsAddToDlHqRetxList;
index 149e7d9..a3da86a 100644 (file)
@@ -31,6 +31,8 @@ File:     sch_slice_based.c
 /** @file sch_slot_ind.c
   @brief This module processes slot indications
  */
+#include "time.h"
+#include "pthread.h"
 #include "common_def.h"
 #include "tfu.h"
 #include "lrg.h"
@@ -73,7 +75,13 @@ uint8_t schSliceBasedCellCfgReq(SchCellCb *cellCb)
       return RFAILED;
    }
    cmLListInit(&schSpcCellCb->ueToBeScheduled);
+   cmLListInit(&schSpcCellCb->sliceCbList);
    cellCb->schSpcCell = (void *)schSpcCellCb;
+
+   schSpcCellCb->timer_sec = 0;
+   schSpcCellCb->slot_ind_count = 0;
+   schSpcCellCb->algoDelay = 0;
+   schSpcCellCb->isTimerStart = false;
    return ROK;
 }
 
@@ -131,6 +139,10 @@ void schSliceBasedCellDelReq(SchCellCb *cellCb)
 uint8_t SchSliceBasedAddUeConfigReq(SchUeCb *ueCb)
 {
    SchSliceBasedUeCb *ueSliceBasedCb;
+   SchSliceBasedCellCb *schSpcCell;
+   float_t random;
+
+   schSpcCell = (SchSliceBasedCellCb *)ueCb->cellCb->schSpcCell;
 
    SCH_ALLOC(ueSliceBasedCb, sizeof(SchSliceBasedHqCb));
    if(!ueSliceBasedCb)
@@ -141,8 +153,15 @@ uint8_t SchSliceBasedAddUeConfigReq(SchUeCb *ueCb)
    
    cmLListInit(&ueSliceBasedCb->hqRetxCb.ulRetxHqList);
    cmLListInit(&ueSliceBasedCb->hqRetxCb.dlRetxHqList);
+   ueSliceBasedCb->isTxPayloadLenAdded = FALSE;
+
+   /* Hard-coded the weight of each UE */
+   random = ((rand() % 10) + 1) * 0.1;
+   ueSliceBasedCb->weight = random;
+
    ueCb->schSpcUeCb = (void *)ueSliceBasedCb;
    
+   schSliceBasedFillLcInfoToSliceCb(&schSpcCell->sliceCbList, ueCb);
    return ROK;
 }
 
@@ -162,7 +181,170 @@ uint8_t SchSliceBasedAddUeConfigReq(SchUeCb *ueCb)
  * ****************************************************************/
 void SchSliceBasedModUeConfigReq(SchUeCb *ueCb)
 {
-   /*TBD: No action required for Slice Based*/
+   SchSliceBasedCellCb *schSpcCell;
+   schSpcCell = (SchSliceBasedCellCb *)ueCb->cellCb->schSpcCell;
+
+   schSliceBasedFillLcInfoToSliceCb(&schSpcCell->sliceCbList, ueCb);
+   return;
+}
+
+/*******************************************************************
+ *
+ * @brief Handles Slice configuration request
+ *
+ * @details
+ *
+ *    Function : SchSliceBasedSliceCfgReq
+ *
+ *    Functionality: Calculate the available PRB quotas for each slice when receiving Slice Configuration Request from MAC
+ *
+ * @params[in] Pointer to Cell control block
+ * @return void
+ *
+ * ****************************************************************/
+void SchSliceBasedSliceCfgReq(SchCellCb *cellCb)
+{
+   CmLList *sliceCfg = NULLP;
+   CmLListCp *storedSliceCfg;
+   SchSliceBasedCellCb  *schSpcCell;
+   SchSliceBasedSliceCb *sliceCbToStore;
+   SchRrmPolicyOfSlice *rrmPolicyNode;
+   uint8_t tempAlgoSelection = 0;
+   uint8_t threadCounter = 0;
+   uint8_t threadRes;
+   schSpcCell = (SchSliceBasedCellCb *)cellCb->schSpcCell;
+   storedSliceCfg = &schCb[cellCb->instIdx].sliceCfg;
+   sliceCfg = storedSliceCfg->first;
+   
+   SchSliceBasedDlThreadArg *threadArg[schSpcCell->sliceCbList.count];
+   pthread_t intraSliceThread[schSpcCell->sliceCbList.count];
+
+   while(sliceCfg)
+   {
+      rrmPolicyNode = (SchRrmPolicyOfSlice *)sliceCfg->node;
+
+      SCH_ALLOC(sliceCbToStore, sizeof(SchSliceBasedSliceCb));
+      if(sliceCbToStore)
+      {
+         memcpy(&sliceCbToStore->snssai, &rrmPolicyNode->snssai, sizeof(Snssai));
+         memcpy(&sliceCbToStore->rrmPolicyRatioInfo, &rrmPolicyNode->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
+
+         if(tempAlgoSelection < 1)
+         {
+            sliceCbToStore->algorithm = RR;
+            sliceCbToStore->algoMethod = FLAT;
+         }
+         else
+         {
+            sliceCbToStore->algorithm = RR;
+            sliceCbToStore->algoMethod = FLAT;
+         }
+         addNodeToLList(&schSpcCell->sliceCbList, sliceCbToStore, NULL);
+
+         tempAlgoSelection++;
+
+#ifdef SCH_MULTI_THREAD
+         /* Create thread in initialization */
+         SCH_ALLOC(schSpcCell->threadArg[threadCounter], sizeof(SchSliceBasedDlThreadArg));
+         SCH_ALLOC(schSpcCell->threadArg[threadCounter]->triggerFlag, sizeof(uint8_t));
+         *schSpcCell->threadArg[threadCounter]->triggerFlag = 0;
+         threadRes = pthread_create(&schSpcCell->intraSliceThread[threadCounter], NULL, schSliceBasedDlIntraSliceThreadScheduling, \
+                                    (void *)schSpcCell->threadArg[threadCounter]);
+         
+         if(threadRes != 0)
+         {
+            DU_LOG("\nERROR  -->  SCH : Thread Creation failed for intra-slice scheduling");
+            return false;
+         }
+
+         threadCounter++;
+#endif
+      }
+      else
+      {
+         DU_LOG("\nERROR  -->  SCH : Memory allocation failed in SchSliceBasedSliceCfgReq");
+         return;
+      }
+
+      DU_LOG("\nDennis --> SCH: Process Slice Config Request: SST:%d, SD:[%d, %d, %d] RRMMaxRatio:%d, RRMMinRatio:%d, RRMDedicatedRatio:%d",\
+            rrmPolicyNode->snssai.sst, rrmPolicyNode->snssai.sd[0], rrmPolicyNode->snssai.sd[1], \
+            rrmPolicyNode->snssai.sd[2], rrmPolicyNode->rrmPolicyRatioInfo.maxRatio, \
+            rrmPolicyNode->rrmPolicyRatioInfo.minRatio, rrmPolicyNode->rrmPolicyRatioInfo.dedicatedRatio);
+      // DU_LOG("\nDennis --> SCH: Calculate PRB quota: Total PRB of Bandwidth:%d, Shared PRB Quota:%d, Prioritized PRB Quota:%d, Dedicated PRB Quota:%d",\
+      // MAX_NUM_RB, sliceCbToStore->sharedPrb, sliceCbToStore->prioritizedPrb, sliceCbToStore->dedicatedPrb);
+
+      sliceCfg = sliceCfg->next;
+   }
+
+   /* Print the sliceCbLL for debugging */
+   // node = schSpcCell->sliceCbList.first;
+   // while(node)
+   // {
+   //    sliceCbToStore = (SchSliceBasedSliceCb *)node->node;
+   //    DU_LOG("\nDennis --> SST:%d, SD:%d, Shared PRB Quota:%d, Prioritized PRB Quota:%d, Dedicated PRB Quota:%d",\
+   //    sliceCbToStore->snssai.sst, rrmPolicyNode->snssai.sd[0], sliceCbToStore->sharedPrb,\
+   //    sliceCbToStore->prioritizedPrb, sliceCbToStore->dedicatedPrb);
+
+   //    node = node->next;
+   // }
+   return;
+}
+
+/*******************************************************************
+ *
+ * @brief Handles Slice Reconfiguration request
+ *
+ * @details
+ *
+ *    Function : SchSliceBasedSliceRecfgReq
+ *
+ *    Functionality: Calculate the available PRB quotas for each slice when receiving Slice Reconfiguration Request from MAC
+ *
+ * @params[in] Pointer to Cell control block
+ * @return void
+ *
+ * ****************************************************************/
+void SchSliceBasedSliceRecfgReq(SchCellCb *cellCb)
+{
+   CmLList *sliceCfg = NULLP;
+   CmLList *node = NULLP;
+   CmLListCp *storedSliceCfg;
+   SchSliceBasedCellCb  *schSpcCell;
+   SchSliceBasedSliceCb *sliceCbNode;
+   SchRrmPolicyOfSlice *rrmPolicyNode;
+
+   schSpcCell = (SchSliceBasedCellCb *)cellCb->schSpcCell;
+   storedSliceCfg = &schCb[cellCb->instIdx].sliceCfg;
+   sliceCfg = storedSliceCfg->first;
+   node = schSpcCell->sliceCbList.first;
+   
+   while(sliceCfg)
+   {
+      rrmPolicyNode = (SchRrmPolicyOfSlice *)sliceCfg->node;
+
+      while(node)
+      {
+         sliceCbNode = (SchSliceBasedSliceCb *)node->node;
+
+         if(memcmp(&rrmPolicyNode->snssai, &sliceCbNode->snssai, sizeof(Snssai)) == 0)
+         {
+            memcpy(&sliceCbNode->rrmPolicyRatioInfo, &rrmPolicyNode->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
+            DU_LOG("\nDennis --> SCH: Process Slice Config Request: SST:%d, SD:[%d, %d, %d] RRMMaxRatio:%d, RRMMinRatio:%d, RRMDedicatedRatio:%d",\
+            rrmPolicyNode->snssai.sst, rrmPolicyNode->snssai.sd[0], rrmPolicyNode->snssai.sd[1], \
+            rrmPolicyNode->snssai.sd[2], rrmPolicyNode->rrmPolicyRatioInfo.maxRatio, \
+            rrmPolicyNode->rrmPolicyRatioInfo.minRatio, rrmPolicyNode->rrmPolicyRatioInfo.dedicatedRatio);
+            
+            // DU_LOG("\nDennis --> SCH: Calculate PRB quota: Total PRB of Bandwidth:%d, Shared PRB Quota:%d, Prioritized PRB Quota:%d, Dedicated PRB Quota:%d",\
+            // MAX_NUM_RB, sliceCbNode->sharedPrb, sliceCbNode->prioritizedPrb, sliceCbNode->dedicatedPrb);
+            
+            break;
+         }
+
+         node = node->next;
+      }
+
+      sliceCfg = sliceCfg->next;
+   }
    return;
 }
 
@@ -1159,6 +1341,11 @@ void schSliceBasedScheduleSlot(SchCellCb *cell, SlotTimingInfo *slotInd, Inst sc
 
    schSpcCell = (SchSliceBasedCellCb *)cell->schSpcCell;
    
+   if(schSpcCell->isTimerStart)
+   {
+      setRrmPolicyWithTimer(cell);
+   }
+
    /* Select first UE in the linked list to be scheduled next */
    pendingUeNode = schSpcCell->ueToBeScheduled.first;
    if(pendingUeNode)
@@ -1256,8 +1443,9 @@ void schSliceBasedScheduleSlot(SchCellCb *cell, SlotTimingInfo *slotInd, Inst sc
                /* DL Data new transmission */
                if((cell->boIndBitMap) & (1<<ueId))
                {
-                  isDlMsgPending = true;               
-                  isDlMsgScheduled = schFillBoGrantDlSchedInfo(cell, *slotInd, ueId, FALSE, &hqP);
+                  isDlMsgPending = true;
+                  //isDlMsgScheduled = schFillBoGrantDlSchedInfo(cell, *slotInd, ueId, FALSE, &hqP);
+                  isDlMsgScheduled = schSliceBasedDlScheduling(cell, *slotInd, ueId, FALSE, &hqP);
 
                   /* If DL scheduling failed, free the newly assigned HARQ process */
                   if(!isDlMsgScheduled)
@@ -1269,6 +1457,24 @@ void schSliceBasedScheduleSlot(SchCellCb *cell, SlotTimingInfo *slotInd, Inst sc
 #endif
                   }
                }
+               else
+               {
+                  /* Reset the allocated PRB in each sliceCB */
+                  CmLList *sliceCbNode = NULLP; 
+                  SchSliceBasedSliceCb *sliceCb = NULLP;
+                  SchSliceBasedCellCb *schSpcCell = NULLP;
+
+                  schSpcCell = (SchSliceBasedCellCb *)cell->schSpcCell;
+                  sliceCbNode = schSpcCell->sliceCbList.first;
+
+                  while(sliceCbNode)
+                  {
+                     sliceCb = (SchSliceBasedSliceCb *)sliceCbNode->node;
+                     sliceCb->allocatedPrb = 0;
+
+                     sliceCbNode = sliceCbNode->next;
+                  }
+               }
             }
 
             /* Scheduling of UL grant */
@@ -1295,6 +1501,7 @@ void schSliceBasedScheduleSlot(SchCellCb *cell, SlotTimingInfo *slotInd, Inst sc
                {
                   isUlGrantPending = true;
                   isUlGrantScheduled = schProcessSrOrBsrReq(cell, *slotInd, ueId, FALSE, &ulHqP);
+                  //isUlGrantScheduled = schSliceBasedUlScheduling(cell, *slotInd, ueId, FALSE, &ulHqP);
                   if(!isUlGrantScheduled)
                      schUlReleaseHqProcess(ulHqP, FALSE);
                   else
@@ -1323,6 +1530,2853 @@ void schSliceBasedScheduleSlot(SchCellCb *cell, SlotTimingInfo *slotInd, Inst sc
    }
 }
 
+/*******************************************************************
+ *
+ * @brief Fill the lcInfo into corresponding slice control block for each UE
+ *
+ * @details
+ *
+ *    Function : schSliceBasedFillLcInfoToSliceCb
+ *
+ *    Functionality: Beacuse each LC is associated with slice, this function
+ *       fills and classifies the lcInfo of each UE into corresponding slice control block.
+ *       Moreover, LCs are ordered from higher priority(lower priority level) to 
+ *       lower priority(higher priority level)
+ *
+ * @params[in] Pointer to Slice Control Block List
+ *             Pointer to UE Control Block
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t schSliceBasedFillLcInfoToSliceCb(CmLListCp *sliceCbList, SchUeCb *ueCb)
+{
+   CmLList *sliceCbNode;
+   CmLList *lcInfoNode, *lcInfoNext;
+   SchSliceBasedSliceCb *sliceCb;
+   uint8_t ueId;
+   uint8_t lcIdx;
+   float_t totalPriorLevel = 0;
+   SchSliceBasedLcInfo *tempLcInfo;
+
+   ueId = ueCb->ueId;
+   sliceCbNode = sliceCbList->first;
+
+   while(sliceCbNode)
+   {
+      sliceCb = (SchSliceBasedSliceCb *)sliceCbNode->node; 
+
+      /* Rebuild the lcInfoList */
+      lcInfoNode = sliceCb->lcInfoList[ueId-1].first;
+      while(lcInfoNode)
+      {
+         lcInfoNext = lcInfoNode->next;
+         SCH_FREE(lcInfoNode->node, sizeof(SchSliceBasedLcInfo));
+         cmLListDelFrm(&sliceCb->lcInfoList[ueId-1], lcInfoNode);
+         SCH_FREE(lcInfoNode, sizeof(CmLList));
+         
+         lcInfoNode = lcInfoNext;
+      }
+      cmLListDeleteLList(&sliceCb->lcInfoList[ueId-1]);
+      
+      cmLListInit(&sliceCb->lcInfoList[ueId-1]);
+
+      for(lcIdx = 0; lcIdx < MAX_NUM_LC; lcIdx++)
+      {  
+         if(ueCb->dlInfo.dlLcCtxt[lcIdx].snssai)
+         {
+            if(memcmp(&sliceCb->snssai, ueCb->dlInfo.dlLcCtxt[lcIdx].snssai, sizeof(Snssai)) == 0)
+            {
+               DU_LOG("\nDennis --> LC ID:%d is added to SST:%d slice", lcIdx, sliceCb->snssai.sst);
+               SCH_ALLOC(tempLcInfo, sizeof(SchSliceBasedLcInfo));
+               tempLcInfo->lcId = lcIdx;
+               tempLcInfo->reqBO = 0;
+               tempLcInfo->allocBO = 0;
+               tempLcInfo->allocPRB = 0;
+               tempLcInfo->ueCb = ueCb;
+               tempLcInfo->priorLevel = schSliceBasedCalculatePriorLevel(ueCb->dlInfo.dlLcCtxt[lcIdx].fiveQi);
+               totalPriorLevel += tempLcInfo->priorLevel;
+               addNodeToLList(&sliceCb->lcInfoList[ueId-1], tempLcInfo, NULL);
+            }
+         }
+      }
+      schSliceBasedSortLcByPriorLevel(&sliceCb->lcInfoList[ueId-1], totalPriorLevel);
+
+      sliceCbNode = sliceCbNode->next;
+      totalPriorLevel = 0;
+   }
+   return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Get the default priority level according to the 5QI mapping table
+ *
+ * @details
+ *
+ *    Function : schSliceBasedCalculatePriorLevel
+ *
+ *    Functionality: Get the default priority level according to the 5QI mapping table
+ *
+ * @params[in] 5QI value
+ * @return Priority Level
+ *
+ * ****************************************************************/
+uint16_t schSliceBasedCalculatePriorLevel(uint16_t fiveQi)
+{
+   uint8_t fiveQiIdx;
+   for(fiveQiIdx = 0; fiveQiIdx < MAX_5QI_TABLE_IDX; fiveQiIdx++)
+   {
+      /* Get the corresponding 5QI Index */
+      if(fiveQiIdxTable[fiveQiIdx] == fiveQi)
+         break;
+   }
+
+   return fiveQiTable[fiveQiIdx][1];
+}
+
+/*******************************************************************
+ *
+ * @brief Sort the logical channel according to priority level within a slice
+ *
+ * @details
+ *
+ *    Function : schSliceBasedSortLcByPriorLevel
+ *
+ *    Functionality: Sort the logical channel according to priority level within a slice
+ *
+ * @params[in] Pointer to LC Info Control Block List
+ * @params[in] Sum of priority level of each LC within a slice
+ * @return void
+ *
+ * ****************************************************************/
+void schSliceBasedSortLcByPriorLevel(CmLListCp *lcInfoList, float_t totalPriorLevel)
+{
+   CmLList *outerNode = NULLP, *interNode, *minPriorNode = NULLP, *tempNode; 
+   SchSliceBasedLcInfo *outerLcInfo = NULLP, *interLcInfo = NULLP, *minPriorLcInfo = NULLP;
+
+   outerNode = lcInfoList->first;
+
+   if(!outerNode)
+   {
+      DU_LOG("\nDennis  -->  schSliceBasedSortLcByPriorLevel(): LL is empty");
+      return RFAILED;
+   }
+   else
+   {
+      while(outerNode)
+      {
+         outerLcInfo = (SchSliceBasedLcInfo *)outerNode->node;
+         interNode = outerNode;
+
+         minPriorNode = interNode;
+         minPriorLcInfo = (SchSliceBasedLcInfo *)minPriorNode->node;
+
+         /* Find the lowest priority level LC (highest priority) */
+         while(interNode)
+         {
+            interLcInfo = (SchSliceBasedLcInfo *)interNode->node;
+
+            if(interLcInfo->priorLevel <= minPriorLcInfo->priorLevel)
+            {
+               minPriorNode = interNode;
+               minPriorLcInfo = interLcInfo;
+            }
+            
+            interNode = interNode->next;
+         }
+
+         if(outerNode != minPriorNode)
+         {
+            /* Swapping minPriorNode and outerNode */
+            tempNode = minPriorNode->next;
+            minPriorNode->next = outerNode->next;
+            outerNode->next = tempNode;
+         
+            if (minPriorNode->next != NULLP)
+               minPriorNode->next->prev = minPriorNode;
+            else
+               lcInfoList->last = minPriorNode; /* ->next = NULLP means that this node is the last node */
+            if (outerNode->next != NULLP)
+               outerNode->next->prev = outerNode;
+            else
+               lcInfoList->last = outerNode;  /* ->next = NULLP means that this node is the last node */
+         
+            tempNode = minPriorNode->prev;
+            minPriorNode->prev = outerNode->prev;
+            outerNode->prev = tempNode;
+         
+            if (minPriorNode->prev != NULLP)
+               minPriorNode->prev->next = minPriorNode;
+            else
+               lcInfoList->first = minPriorNode;  /* ->prev = NULLP means that this node is the first node */
+
+            if (outerNode->prev != NULLP)
+               outerNode->prev->next = outerNode;
+            else
+               lcInfoList->first = outerNode;  /* ->prev = NULLP means that this node is the first node */
+
+            outerNode = minPriorNode;
+            outerLcInfo = minPriorLcInfo;
+         }
+
+         /* Calculate the weight of each LC */
+         outerLcInfo->weight = outerLcInfo->priorLevel / totalPriorLevel;
+         outerNode = outerNode->next;
+      }
+   }
+}
+
+/*******************************************************************
+ *
+ * @brief Sort the UE according to the weight
+ *
+ * @details
+ *
+ *    Function : schSliceBasedSortLcByPriorLevel
+ *
+ *    Functionality: Sort the UE according to the weight
+ *
+ * @params[in] Pointer to cell control block
+ * @params[in] Pointer to UE List
+ * @params[in] Sum of weight of each UE
+ * @return void
+ *
+ * ****************************************************************/
+void schSliceBasedSortUeByWeight(SchCellCb *cellCb, CmLListCp *ueList, float_t totalWeight)
+{
+   CmLList *outerNode = NULLP, *interNode, *maxWeightNode = NULLP, *tempNode;
+   uint8_t outerUeId, interUeId, maxWeightUeId; 
+   SchSliceBasedUeCb *outerUe = NULLP, *interUe = NULLP, *maxWeightUe = NULLP;
+
+   outerNode = ueList->first;
+
+   if(!outerNode)
+   {
+      DU_LOG("\nDennis  -->  schSliceBasedSortLcByPriorLevel(): LL is empty");
+      return RFAILED;
+   }
+   else
+   {
+      while(outerNode)
+      {
+         outerUeId = *(uint8_t *)outerNode->node;
+         outerUe = (SchSliceBasedUeCb *)cellCb->ueCb[outerUeId-1].schSpcUeCb;
+
+         interNode = outerNode;
+
+         maxWeightNode = interNode;
+         maxWeightUeId = *(uint8_t *)maxWeightNode->node;
+         maxWeightUe = (SchSliceBasedUeCb *)cellCb->ueCb[maxWeightUeId-1].schSpcUeCb;
+
+         /* Find the highest weight UE (highest priority) */
+         while(interNode)
+         {
+            interUeId = *(uint8_t *)interNode->node;
+            interUe = (SchSliceBasedUeCb *)cellCb->ueCb[interUeId-1].schSpcUeCb;
+
+            if(interUe->weight >= maxWeightUe->weight)
+            {
+               maxWeightNode = interNode;
+               maxWeightUe = interUe;
+            }
+            
+            interNode = interNode->next;
+         }
+
+         if(outerNode != maxWeightNode)
+         {
+            /* Swapping maxWeightNode and outerNode */
+            tempNode = maxWeightNode->next;
+            maxWeightNode->next = outerNode->next;
+            outerNode->next = tempNode;
+         
+            if (maxWeightNode->next != NULLP)
+               maxWeightNode->next->prev = maxWeightNode;
+            else
+               ueList->last = maxWeightNode; /* ->next = NULLP means that this node is the last node */
+            if (outerNode->next != NULLP)
+               outerNode->next->prev = outerNode;
+            else
+               ueList->last = outerNode;  /* ->next = NULLP means that this node is the last node */
+         
+            tempNode = maxWeightNode->prev;
+            maxWeightNode->prev = outerNode->prev;
+            outerNode->prev = tempNode;
+         
+            if (maxWeightNode->prev != NULLP)
+               maxWeightNode->prev->next = maxWeightNode;
+            else
+               ueList->first = maxWeightNode;  /* ->prev = NULLP means that this node is the first node */
+
+            if (outerNode->prev != NULLP)
+               outerNode->prev->next = outerNode;
+            else
+               ueList->first = outerNode;  /* ->prev = NULLP means that this node is the first node */
+
+            outerNode = maxWeightNode;
+            outerUe = maxWeightUe;
+         }
+         /* Calculate the weight of UE withing this TTI */
+         outerUe->prbWeight = outerUe->weight / totalWeight;
+         outerNode = outerNode->next;
+      }
+   }
+}
+
+/*******************************************************************
+ *
+ * @brief Main DL scheduling function
+ *
+ * @details
+ *
+ *    Function : schSliceBasedDlScheduling
+ *
+ *    Functionality: 
+ *       [Step1]: Get the available HARQ process for this UE
+ *       [Step2]: Find the k0, k1 value for this UE (Time Resource Allocation)
+ *       [Step3]: Allocate the memory to PDSCH and PDCCH allocation result of this UE
+ *       [Step4]: Search the largest free PRB block to do the scheduling
+ *       [Step5]: Traverse each slice to do the intra-slice scheduling individually
+ *       [Step6]: Get the remaining resource after intra-slice scheduling
+ *                and leave it to final scheduling
+ *       [Step7]: Run the final scheduling to allocate the remaining resource
+ *                and fill the scheduling result
+ * 
+ * @params[in] I/P > Pointer to Cell Control Block
+ *             I/P > Slot timing info
+ *             I/P > UE ID
+ *             I/P > Retransmission Flag
+ *             I/P > The address of pointer to DL HARQ Process Control Block
+ * @return true     - success
+ *         false    - failure
+ *
+ * ****************************************************************/
+bool schSliceBasedDlScheduling(SchCellCb *cell, SlotTimingInfo currTime, uint8_t ueId, bool isRetx, SchDlHqProcCb **hqP)
+{
+   uint8_t pdschNumSymbols = 0, pdschStartSymbol = 0;
+   uint16_t startPrb = 0;
+   uint16_t maxFreePRB = 0;
+   uint16_t totalRemainingPrb = 0;
+   uint16_t currSliceCnt = 0;
+   SchUeCb *ueCb = NULLP;
+   SlotTimingInfo pdcchTime, pdschTime, pucchTime;
+   DlMsgSchInfo *dciSlotAlloc = NULLP;
+   SchSliceBasedCellCb *schSpcCell = NULLP;
+   CmLList *sliceCbNode = NULLP; 
+   SchSliceBasedSliceCb *sliceCb = NULLP;
+
+   /* Hard-coded the UE DL LL for 1 UE per TTI (Ready for multi-UEs per TTI scheduling) */
+   SchDlHqProcCb *ueNewHarqList[MAX_NUM_UE];
+   ueNewHarqList[ueId-1] = *hqP;
+
+   CmLListCp ueDlNewTransmission;
+   cmLListInit(&ueDlNewTransmission);
+   addNodeToLList(&ueDlNewTransmission, &ueId, NULLP);
+
+   ueCb = &cell->ueCb[ueId-1];
+
+   /* [Step1]: Get the available HARQ process for this UE */
+   if (isRetx == FALSE)
+   {
+      if(schDlGetAvlHqProcess(cell, ueCb, &ueNewHarqList[ueId-1]) != ROK)
+      {
+         return false;
+      }
+   }
+
+   /* [Step2]: Find the k0, k1 value for this UE (Time Resource Allocation) */
+   if(findValidK0K1Value(cell, currTime, ueId, ueCb->k0K1TblPrsnt,\
+            &pdschStartSymbol, &pdschNumSymbols, &pdcchTime, &pdschTime, &pucchTime, isRetx, ueNewHarqList[ueId-1]) != true )
+   {
+      /* If a valid combination of slots to scheduled PDCCH, PDSCH and PUCCH is
+       * not found, do not perform resource allocation. Return from here. */
+      return false;
+   }
+
+   /* [Step3]: Allocate the memory to PDSCH and PDCCH allocation result of this UE */
+   if(cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] == NULL)
+   {
+      SCH_ALLOC(dciSlotAlloc, sizeof(DlMsgSchInfo));
+      if(!dciSlotAlloc)
+      {
+         DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for ded DL msg alloc");
+         return false;
+      }
+      cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId -1] = dciSlotAlloc;
+      memset(dciSlotAlloc, 0, sizeof(DlMsgSchInfo));
+   }
+
+   schSpcCell = (SchSliceBasedCellCb *)cell->schSpcCell;
+   sliceCbNode = schSpcCell->sliceCbList.first;
+
+   /* [Step4]: Search the largest free PRB block to do the scheduling */
+   maxFreePRB = searchLargestFreeBlock(ueNewHarqList[ueId-1]->hqEnt->cell, pdschTime, &startPrb, DIR_DL);
+   totalRemainingPrb = maxFreePRB;
+   
+   /* [Step5]: Traverse each slice to do the intra-slice scheduling individually */
+   if (isRetx == FALSE)
+   {
+      while(sliceCbNode)
+      {
+         sliceCb = (SchSliceBasedSliceCb *)sliceCbNode->node;
+         
+#ifdef SCH_MULTI_THREAD
+
+         /* Pack the argument for thread function */
+         schSpcCell->threadArg[currSliceCnt]->cell = cell;
+         schSpcCell->threadArg[currSliceCnt]->pdcchTime = &pdcchTime;
+         schSpcCell->threadArg[currSliceCnt]->pdschNumSymbols = pdschNumSymbols;
+         schSpcCell->threadArg[currSliceCnt]->totalRemainingPrb = &totalRemainingPrb;
+         schSpcCell->threadArg[currSliceCnt]->maxFreePRB = &maxFreePRB;
+         schSpcCell->threadArg[currSliceCnt]->sliceCb = sliceCb;
+         schSpcCell->threadArg[currSliceCnt]->ueDlNewTransmission= &ueDlNewTransmission;
+
+         /* Trigger Point: Run the intra-slice scheduling with multi-thread feature */
+         *schSpcCell->threadArg[currSliceCnt]->triggerFlag = 1;
+
+         currSliceCnt++;
+         sliceCbNode = sliceCbNode->next;
+      }
+
+      /* Wait for each thread finishing the intra-slice scheduling */
+      currSliceCnt = 1;
+      DU_LOG("\nDennis  -->  waiting for intra-slice scheduling");
+      while(currSliceCnt)
+      {
+         currSliceCnt = 0;
+         for(int sliceCnt=0; sliceCnt < schSpcCell->sliceCbList.count; sliceCnt++)
+         {
+            if(*schSpcCell->threadArg[sliceCnt]->triggerFlag)
+            {
+               currSliceCnt++;
+            }
+         }
+      }
+
+#else
+         /* [Step6]: Get the remaining resource after intra-slice scheduling
+          * and leave it to final scheduling */
+         if(schSliceBasedDlIntraSliceScheduling(cell, pdcchTime, pdschNumSymbols, &ueDlNewTransmission, maxFreePRB, \
+            &totalRemainingPrb, sliceCb) != ROK)
+         {
+            DU_LOG("\nDennis --> DL Intra Slice Scheduling Failed");
+            return false;
+         }
+
+         sliceCbNode = sliceCbNode->next;
+      }
+#endif
+
+   }  
+
+   /*  [Step7]: Run the final scheduling to allocate the remaining resource
+    *  and fill the scheduling result */
+   if(schSliceBasedDlFinalScheduling(cell, pdschTime, pdcchTime, pucchTime, pdschStartSymbol, pdschNumSymbols, &ueDlNewTransmission, isRetx, ueNewHarqList, totalRemainingPrb, startPrb) != ROK)
+   {
+      DU_LOG("\nDennis --> DL Final Scheduling Failed");
+      return false;
+   }
+
+   /* Free the hard-coded UE DL New Transmission LL for 1 UE per TTI */
+   SCH_FREE(ueDlNewTransmission.first, sizeof(CmLList));
+
+   return true;
+}
+
+/*******************************************************************
+ *
+ * @brief a. Allocate the dedicated resource and prioritized resource for this slice
+ *        to achieve the resource isolation between slice
+ *        b. Each slice can apply different algorithm
+ *
+ * @details
+ *
+ *    Function : schSliceBasedDlIntraSliceScheduling
+ *
+ *    Functionality: 
+ *       [Step1]: Calculate the dedicated, prioritized, shared resource according to RRMPolicyRatio
+ *                as per 3GPP 28.541 Sec: 4.3.36. Assume one slice is associated with one RRMPolicyRatio
+ *       [Step2]: Traverse the UE to do:
+ *                a. Sum the weight of each UE which could be used in scheduling algorithm
+ *                b. Update the requested BO of each LC in current slice
+ *       [Step3]: Run the scheduling algorithm assigned to this slice
+ *       [Step4]: Calculate the remaining PRB according to the rule of dedicated resource and prioritized resource
+ *                As per 3GPP 28.541 Sec: 4.3.36
+ *                a. Dedicated resource can not share to other slice
+ *                b. Unused prioritized resource can share to other slice
+ * 
+ * @params[in] I/P > Pointer to Cell Control Block
+ *             I/P > PDCCH Slot timing info
+ *             I/P > Number of PDSCH Symbols
+ *             I/P > UE DL New Transmission LL
+ *             I/P > Number of PRB of Max FreePRB Block
+ *             I/P & O/P > Total remaining PRB after finishing intra-slice scheduling
+ *             I/P & O/P > Pointer to slice control block to store the information of this slice
+ * 
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t schSliceBasedDlIntraSliceScheduling(SchCellCb *cellCb, SlotTimingInfo pdcchTime, uint8_t pdschNumSymbols, \
+                                            CmLListCp *ueDlNewTransmission, uint16_t maxFreePRB, uint16_t *totalRemainingPrb,\
+                                            SchSliceBasedSliceCb *sliceCb)
+{  
+   uint16_t crnti = 0;
+   uint16_t minimumPrb = 0, remainingPrb = 0;
+   SchUeCb *ueCb = NULLP;
+   uint8_t  ueId;
+   CmLList *ueNode;
+   DlMsgSchInfo *dciSlotAlloc;
+   float_t totalUeWeight = 0;
+   SchSliceBasedUeCb *ueSliceBasedCb = NULLP;
+
+   /* [Step1]: Calculate the slice PRB quota according to RRMPolicyRatio and MaxFreePRB */
+   sliceCb->dedicatedPrb = (uint16_t)(((sliceCb->rrmPolicyRatioInfo.dedicatedRatio)*(maxFreePRB))/100);
+   sliceCb->prioritizedPrb = (uint16_t)(((sliceCb->rrmPolicyRatioInfo.minRatio - sliceCb->rrmPolicyRatioInfo.dedicatedRatio)\
+                                             *(maxFreePRB))/100);
+   sliceCb->sharedPrb = (uint16_t)(((sliceCb->rrmPolicyRatioInfo.maxRatio - sliceCb->rrmPolicyRatioInfo.minRatio)\
+                                          *(maxFreePRB))/100);
+   minimumPrb = sliceCb->dedicatedPrb + sliceCb->prioritizedPrb;
+
+#ifdef SLICE_BASED_DEBUG_LOG
+   DU_LOG("\n\n===============Dennis  -->  SCH Intra-Slice : Start to run IntraSliceScheduling [SST:%d, MinimumPRB Quota:%d]===============", \
+   sliceCb->snssai.sst, minimumPrb);
+#endif
+
+   ueNode = ueDlNewTransmission->first;
+
+   /* [Step2] */
+   while(ueNode)
+   {
+      ueId = *(uint8_t *)(ueNode->node);
+      ueCb = &cellCb->ueCb[ueId-1];
+      ueSliceBasedCb = (SchSliceBasedUeCb *)ueCb->schSpcUeCb;
+
+      /* Sum the weight of each UE */
+      totalUeWeight += ueSliceBasedCb->weight;
+   
+      /* Update the requested BO of each LC in current slice */
+      schSliceBasedUpdateLcListReqBo(&sliceCb->lcInfoList[ueId-1], ueCb, DIR_DL);
+      ueNode = ueNode->next;
+   }
+
+   /* [Step3]: Run the scheduling algorithm assigned to this slice */
+   if(sliceCb->algorithm == RR)
+   {
+      if(minimumPrb != 0)
+      {
+         remainingPrb = minimumPrb;            
+         schSliceBasedRoundRobinAlgo(cellCb, ueDlNewTransmission, sliceCb->lcInfoList, \
+                                    pdschNumSymbols, &remainingPrb, sliceCb->algoMethod, NULLP);
+      }
+
+      /* Get the allocated PRB after scheduling algorithm */
+      sliceCb->allocatedPrb = minimumPrb - remainingPrb;
+
+#ifdef SLICE_BASED_DEBUG_LOG
+      DU_LOG("\nDennis  -->  SCH Intra-Slice Result : [SST: %d, Allocated PRB: %d, Unallocated PRB: %d, Algo: RR]", sliceCb->snssai.sst, \
+               sliceCb->allocatedPrb, remainingPrb);
+#endif
+   }
+   else if(sliceCb->algorithm == WFQ)
+   {
+      /* Sort the UE list in terms of the weight */
+      /* This function should be moved to schSliceBasedDlScheduling() when go through the UE list (for Jojo)*/
+      schSliceBasedSortUeByWeight(cellCb, ueDlNewTransmission, totalUeWeight);
+
+      if(minimumPrb != 0)
+      {
+         remainingPrb = minimumPrb;            
+         schSliceBasedWeightedFairQueueAlgo(cellCb, ueDlNewTransmission, sliceCb->lcInfoList, \
+                                    pdschNumSymbols, &remainingPrb, sliceCb->algoMethod, NULLP);
+      }
+
+      /* Get the allocated PRB after scheduling algorithm */
+      sliceCb->allocatedPrb = minimumPrb - remainingPrb;
+
+#ifdef SLICE_BASED_DEBUG_LOG
+      DU_LOG("\nDennis  -->  SCH Intra-Slice Result : [SST: %d, Allocated PRB: %d, Unallocated PRB: %d, Algo: WFQ]", sliceCb->snssai.sst, \
+               sliceCb->allocatedPrb, remainingPrb);      
+#endif
+   }
+   else
+   {
+      DU_LOG("\nDennis  -->  In schSliceBasedDlIntraSliceScheduling() : Invalid Scheduling Algorithm");
+      return;
+   }
+   
+   
+   /* [Step4]: Calculate the remaining PRB according to the rule */
+   if(sliceCb->allocatedPrb > sliceCb->dedicatedPrb)
+   {
+      *totalRemainingPrb = *totalRemainingPrb - sliceCb->allocatedPrb;
+   }
+   else
+   {
+      *totalRemainingPrb = *totalRemainingPrb - sliceCb->dedicatedPrb;
+   }
+
+   return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief a. Allocate the dedicated resource and prioritized resource for this slice
+ *        to achieve the resource isolation between slice
+ *        b. Each slice can apply different algorithm
+ *        c. For multi-thread intra-slice scheduling
+ * 
+ * @details
+ *
+ *    Function : schSliceBasedDlIntraSliceThreadScheduling
+ *       
+ *       [Step1]: Polling the trigger flag to trigger the intra-slice scheduling
+ *       [Step2]: Calculate the dedicated, prioritized, shared resource according to RRMPolicyRatio
+ *                as per 3GPP 28.541 Sec: 4.3.36. Assume one slice is associated with one RRMPolicyRatio
+ *       [Step3]: Traverse the UE to do:
+ *                a. Sum the weight of each UE which could be used in scheduling algorithm
+ *                b. Update the requested BO of each LC in current slice
+ *       [Step4]: Run the scheduling algorithm assigned to this slice
+ *       [Step5]: Calculate the remaining PRB according to the rule of dedicated resource and prioritized resource
+ *                As per 3GPP 28.541 Sec: 4.3.36
+ *                a. Dedicated resource can not share to other slice
+ *                b. Unused prioritized resource can share to other slice
+ *
+ * @params[in] Pointer to thread argument
+ * @return void
+ *
+ * ****************************************************************/
+void *schSliceBasedDlIntraSliceThreadScheduling(void *threadArg)
+{
+   SchSliceBasedDlThreadArg *dlThreadArg;
+   dlThreadArg = (SchSliceBasedDlThreadArg *)threadArg;
+
+   /* [Step1]: Polling the trigger flag to trigger the intra-slice scheduling */
+   while(1)
+   {  
+      if(*dlThreadArg->triggerFlag)
+      {
+         uint16_t crnti = 0;
+         uint16_t minimumPrb = 0, remainingPrb = 0;
+         SchUeCb *ueCb = NULLP;
+         uint8_t  ueId;
+         CmLList *ueNode;
+         DlMsgSchInfo *dciSlotAlloc;
+         float_t totalUeWeight = 0;
+         SchSliceBasedUeCb *ueSliceBasedCb = NULLP;
+
+         SchCellCb *cellCb;
+         SlotTimingInfo pdcchTime;
+         uint8_t pdschNumSymbols;
+         uint16_t *totalRemainingPrb;
+         uint16_t maxFreePRB;
+         SchSliceBasedSliceCb *sliceCb;
+         CmLListCp *ueDlNewTransmission;
+
+         cellCb = dlThreadArg->cell;
+         pdcchTime = *dlThreadArg->pdcchTime;
+         pdschNumSymbols = dlThreadArg->pdschNumSymbols;
+         totalRemainingPrb = dlThreadArg->totalRemainingPrb;
+         maxFreePRB = *dlThreadArg->maxFreePRB;
+         sliceCb = dlThreadArg->sliceCb;
+         ueDlNewTransmission = dlThreadArg->ueDlNewTransmission;
+
+         /* [Step2]: Calculate the slice PRB quota according to RRMPolicyRatio and MaxFreePRB */
+         sliceCb->dedicatedPrb = (uint16_t)(((sliceCb->rrmPolicyRatioInfo.dedicatedRatio)*(maxFreePRB))/100);
+         sliceCb->prioritizedPrb = (uint16_t)(((sliceCb->rrmPolicyRatioInfo.minRatio - sliceCb->rrmPolicyRatioInfo.dedicatedRatio)\
+                                                   *(maxFreePRB))/100);
+         sliceCb->sharedPrb = (uint16_t)(((sliceCb->rrmPolicyRatioInfo.maxRatio - sliceCb->rrmPolicyRatioInfo.minRatio)\
+                                                *(maxFreePRB))/100);
+         minimumPrb = sliceCb->dedicatedPrb + sliceCb->prioritizedPrb;
+
+#ifdef SLICE_BASED_DEBUG_LOG
+         DU_LOG("\n\n===============Dennis  -->  SCH Intra-Slice : Start to run IntraSliceScheduling [SST:%d, MinimumPRB Quota:%d]===============", \
+         sliceCb->snssai.sst, minimumPrb);
+#endif
+
+         ueNode = ueDlNewTransmission->first;
+
+         /* [Step3] */
+         while(ueNode)
+         {
+            ueId = *(uint8_t *)(ueNode->node);
+            ueCb = &cellCb->ueCb[ueId-1];
+            ueSliceBasedCb = (SchSliceBasedUeCb *)ueCb->schSpcUeCb;
+
+            /* Sum the weight of each UE */
+            totalUeWeight += ueSliceBasedCb->weight;
+         
+            /* Update the requested BO of each LC in current slice */
+            schSliceBasedUpdateLcListReqBo(&sliceCb->lcInfoList[ueId-1], ueCb, DIR_DL);
+            ueNode = ueNode->next;
+         }
+
+         /* [Step4]: Run the scheduling algorithm assigned to this slice */
+         if(sliceCb->algorithm == RR)
+         {
+            if(minimumPrb != 0)
+            {
+               remainingPrb = minimumPrb;            
+               schSliceBasedRoundRobinAlgo(cellCb, ueDlNewTransmission, sliceCb->lcInfoList, \
+                                          pdschNumSymbols, &remainingPrb, sliceCb->algoMethod, NULLP);
+            }
+
+            /* Get the allocated PRB after scheduling algorithm */
+            sliceCb->allocatedPrb = minimumPrb - remainingPrb;
+
+#ifdef SLICE_BASED_DEBUG_LOG
+            DU_LOG("\nDennis  -->  SCH Intra-Slice Result : [SST: %d, Allocated PRB: %d, Unallocated PRB: %d, Algo: RR]", sliceCb->snssai.sst, \
+                     sliceCb->allocatedPrb, remainingPrb);
+#endif
+         }
+         else if(sliceCb->algorithm == WFQ)
+         {
+            /* Sort the UE list in terms of the weight */
+            /* This function should be moved to schSliceBasedDlScheduling() when go through the UE list (for Jojo)*/
+            schSliceBasedSortUeByWeight(cellCb, ueDlNewTransmission, totalUeWeight);
+
+            if(minimumPrb != 0)
+            {
+               remainingPrb = minimumPrb;            
+               schSliceBasedWeightedFairQueueAlgo(cellCb, ueDlNewTransmission, sliceCb->lcInfoList, \
+                                          pdschNumSymbols, &remainingPrb, sliceCb->algoMethod, NULLP);
+            }
+
+            /* Get the allocated PRB after scheduling algorithm */
+            sliceCb->allocatedPrb = minimumPrb - remainingPrb;
+
+#ifdef SLICE_BASED_DEBUG_LOG
+            DU_LOG("\nDennis  -->  SCH Intra-Slice Result : [SST: %d, Allocated PRB: %d, Unallocated PRB: %d, Algo: WFQ]", sliceCb->snssai.sst, \
+                     sliceCb->allocatedPrb, remainingPrb);      
+#endif
+         }
+         else
+         {
+            DU_LOG("\nDennis  -->  In schSliceBasedDlIntraSliceScheduling() : Invalid Scheduling Algorithm");
+            return;
+         }
+         
+         
+         /* [Step5]: Calculate the remaining PRB according to the rule */
+         if(sliceCb->allocatedPrb > sliceCb->dedicatedPrb)
+         {
+            *totalRemainingPrb = *totalRemainingPrb - sliceCb->allocatedPrb;
+         }
+         else
+         {
+            *totalRemainingPrb = *totalRemainingPrb - sliceCb->dedicatedPrb;
+         }
+
+         /* Set the trigger flag to 0 and waiting for next trigger point */
+         *dlThreadArg->triggerFlag = 0;
+
+         /* Sleep to reduce the CPU usage */
+         usleep(500);
+      }
+   }
+}
+
+/*******************************************************************
+ *
+ * @brief Final scheduling
+ *
+ * @details
+ *
+ *    Function : schSliceBasedDlFinalScheduling
+ *
+ *    Functionality: 
+ *       [Step1]: Traverse each UE to allocate remaining PRB to default slice
+ *       [Step2]: Traverse each slice to allocate the remaining PRB according to slice priority
+ *                Currently, slice 1 would be the highest priority and slice 2, slice 3...
+ *                Slice priority should be implicit in the RAN Control indication from RIC in the future
+ *       [Step3]: Run the scheduling algorithm assigned to this slice based on the rule of shared resource
+ *                As per 3GPP 28.541 Sec: 4.3.36:
+ *                Shared resource defines the how many remaining resource this slice can use
+ *       [Step4]: Traverse each UE to fill the scheduling result
+ *       [Step5]: Traverse each LC to fill the exact scheduled bytes of this LC and reset the LC Info node
+ *       [Step6]: Fill the scheduling result into PDCCH and PDSCH configuration
+ *       [Step7]: Check if both DCI and DL_MSG are sent in the same slot.
+ *                If not, allocate memory for DL_MSG PDSCH slot to store PDSCH info
+ *       [Step8]: Allocate the PUCCH resource for HARQ to this UE
+ *       [Step9]: Reset the BO of each LC and boIndBitMap for this UE
+ * 
+ * @params[in] I/P > Pointer to Cell Control Block
+ *             I/P > PDSCH Slot timing info
+ *             I/P > PDCCH Slot timing info
+ *             I/P > PUCCH Slot timing info
+ *             I/P > Strat PDSCH Symbols
+ *             I/P > Number of PDSCH Symbols
+ *             I/P > Number of PDSCH Symbols
+ *             I/P > UE DL New Transmission LL
+ *             I/P > Retransmission Flag
+ *             I/P > Double Pointer to HARQ DL Process Controll Block List
+ *             I/P > Remaining PRBs after intra-slice scheduling
+ *             I/P > Start PRB Index
+ * 
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t schSliceBasedDlFinalScheduling(SchCellCb *cellCb, SlotTimingInfo pdschTime, SlotTimingInfo pdcchTime, \
+                                       SlotTimingInfo pucchTime, uint8_t pdschStartSymbol, uint8_t pdschNumSymbols, 
+                                       CmLListCp *ueDlNewTransmission, bool isRetx, SchDlHqProcCb **ueNewHarqList, \
+                                       uint16_t remainingPrb, uint16_t startPrb)
+{  
+   uint8_t lcIdx = 0;
+   uint16_t mcsIdx = 0;
+   uint16_t crnti = 0;
+   uint8_t  ueId;
+   uint16_t availablePrb = 0;
+   uint32_t accumalatedSize = 0;
+   uint16_t numPRB = 0;
+   SchUeCb *ueCb = NULLP;
+   DlMsgSchInfo *dciSlotAlloc, *dlMsgAlloc;
+   SchSliceBasedCellCb *schSpcCell = NULLP;
+   CmLList *sliceCbNode = NULLP;
+   CmLList *ueNode;
+   CmLListCp defLcList;
+   SchSliceBasedSliceCb *sliceCb = NULLP;
+   SchSliceBasedUeCb *ueSliceBasedCb = NULLP;
+
+#ifdef SLICE_BASED_DEBUG_LOG  
+   DU_LOG("\n\n===============DEBUG  -->  SCH Final : Start to run final-scheduling [Remaining PRB is:%d]===============", remainingPrb);
+#endif
+
+   /* [Step1]: Traverse each UE to allocate remaining PRB to default slice */
+   ueNode = ueDlNewTransmission->first;
+   while(ueNode)
+   {  
+      ueId = *(uint8_t *)(ueNode->node);
+      ueCb = &cellCb->ueCb[ueId-1];
+      ueSliceBasedCb = (SchSliceBasedUeCb *)ueCb->schSpcUeCb;
+
+      mcsIdx = ueCb->ueCfg.dlModInfo.mcsIndex;
+      if(remainingPrb != 0)
+      {
+         cmLListInit(&defLcList);
+
+         /* Allocate the remaining PRB to default slice */
+         for(lcIdx = 0; lcIdx < MAX_NUM_LC; lcIdx++)
+         {
+            if(ueCb->dlInfo.dlLcCtxt[lcIdx].snssai == NULLP && ueCb->dlInfo.dlLcCtxt[lcIdx].bo != 0)
+            {
+               /* Update the reqPRB and Payloadsize for this LC in the appropriate List */
+               if(updateLcListReqPRB(&defLcList, ueCb->dlInfo.dlLcCtxt[lcIdx].lcId,\
+                        (ueCb->dlInfo.dlLcCtxt[lcIdx].bo + MAC_HDR_SIZE)) != ROK)
+               {
+                  DU_LOG("\nERROR  --> SCH : Updation in default LC Info LL Failed");
+               }
+               else
+               {
+#ifdef SLICE_BASED_DEBUG_LOG
+                  DU_LOG("\nDEBUG  -->  SCH : Append LC to default LC Info LL [LCID, reqBO] [%d, %d]", lcIdx, \
+                  ueCb->dlInfo.dlLcCtxt[lcIdx].bo + MAC_HDR_SIZE);
+#endif
+               }
+            }
+         }
+
+         availablePrb = remainingPrb;
+         schSliceBasedPrbAllocUsingRRMPolicy(&defLcList, mcsIdx, pdschNumSymbols, &availablePrb, \
+                                             &ueSliceBasedCb->isTxPayloadLenAdded, NULLP);
+
+#ifdef SLICE_BASED_DEBUG_LOG
+         DU_LOG("\nDEBUG  -->  SCH Final Default Slice : [UE ID: %d, Allocated PRB: %d, Remaining PRB: %d]", \
+               ueId, remainingPrb - availablePrb, availablePrb);
+#endif
+         remainingPrb = availablePrb;
+      }
+      ueNode = ueNode->next;
+   }
+
+   /* [Step2]: Traverse each slice to Allocate the remaining PRB according to slice priority */
+   schSpcCell = (SchSliceBasedCellCb *)cellCb->schSpcCell;
+   sliceCbNode = schSpcCell->sliceCbList.first;
+
+   while(sliceCbNode)
+   {
+      sliceCb = (SchSliceBasedSliceCb *)sliceCbNode->node;
+
+      /* [Step3]: Run the scheduling algorithm assigned to this slice */
+      if(sliceCb->algorithm == RR)
+      {   
+#ifdef SLICE_BASED_DEBUG_LOG
+         DU_LOG("\n\n===============DEBUG  -->  SCH Final : Start to run FinalScheduling \
+               [SST:%d, Shared PRB Quota:%d, Remaining PRB:%d, Algo: RR]===============", \
+               sliceCb->snssai.sst, sliceCb->sharedPrb, remainingPrb);
+#endif
+
+         if(remainingPrb != 0)
+         {  
+            /* [Step3]: Based on the rule of shared resource to allocate */
+            if(sliceCb->sharedPrb >= remainingPrb)
+            {
+               availablePrb = remainingPrb; 
+               schSliceBasedRoundRobinAlgo(cellCb, ueDlNewTransmission, sliceCb->lcInfoList, \
+                                    pdschNumSymbols, &availablePrb, sliceCb->algoMethod, NULLP);
+               sliceCb->allocatedPrb += remainingPrb - availablePrb;
+               remainingPrb = availablePrb;
+            }
+            else
+            {
+               availablePrb = sliceCb->sharedPrb;
+               schSliceBasedRoundRobinAlgo(cellCb, ueDlNewTransmission, sliceCb->lcInfoList, \
+                                    pdschNumSymbols, &availablePrb, sliceCb->algoMethod, NULLP);
+               sliceCb->allocatedPrb += sliceCb->sharedPrb - availablePrb;
+               remainingPrb = remainingPrb - (sliceCb->sharedPrb - availablePrb);
+            }
+         }
+      }
+      else if(sliceCb->algorithm == WFQ)
+      {
+#ifdef SLICE_BASED_DEBUG_LOG
+         DU_LOG("\n\n===============DEBUG  -->  SCH Final : Start to run FinalScheduling \
+               [SST:%d, Shared PRB Quota:%d, Remaining PRB:%d, Algo: WFQ]===============", \
+               sliceCb->snssai.sst, sliceCb->sharedPrb, remainingPrb);
+#endif
+
+         if(remainingPrb != 0)
+         {
+            /* [Step3]: Based on the rule of shared resource to allocate */
+            if(sliceCb->sharedPrb >= remainingPrb)
+            {
+               availablePrb = remainingPrb; 
+               schSliceBasedWeightedFairQueueAlgo(cellCb, ueDlNewTransmission, sliceCb->lcInfoList, \
+                                    pdschNumSymbols, &availablePrb, sliceCb->algoMethod, NULLP);
+               sliceCb->allocatedPrb += remainingPrb - availablePrb;
+               remainingPrb = availablePrb;
+            }
+            else
+            {
+               availablePrb = sliceCb->sharedPrb;
+               schSliceBasedWeightedFairQueueAlgo(cellCb, ueDlNewTransmission, sliceCb->lcInfoList, \
+                                    pdschNumSymbols, &availablePrb, sliceCb->algoMethod, NULLP);
+               sliceCb->allocatedPrb += sliceCb->sharedPrb - availablePrb;
+               remainingPrb = remainingPrb - (sliceCb->sharedPrb - availablePrb);
+            }
+         }
+      }
+      else
+      {
+         DU_LOG("\nERROR  -->  In schSliceBasedDlFinalScheduling() : Invalid Scheduling Algorithm");
+         return;
+      }
+#ifdef SLICE_BASED_DEBUG_LOG
+      DU_LOG("\nDEBUG  -->  SCH Final Scheduling Result : [SST: %d, Allocated PRB: %d, Remaining PRB: %d]", \
+            sliceCb->snssai.sst, sliceCb->allocatedPrb, remainingPrb);
+#endif
+
+      sliceCbNode = sliceCbNode->next;
+   }
+
+   /* [Step4]: Traverse each UE to fill the scheduling result */
+   ueNode = ueDlNewTransmission->first;
+   while(ueNode)
+   {
+      ueId = *(uint8_t *)(ueNode->node);
+      SchDlHqProcCb **hqP = &ueNewHarqList[ueId-1];
+      ueCb = &cellCb->ueCb[ueId-1];
+      ueSliceBasedCb = (SchSliceBasedUeCb *)ueCb->schSpcUeCb;
+      GET_CRNTI(crnti,ueId);
+      accumalatedSize = 0;
+
+      /* Get PDCCH and PDSCH resources for the UE */
+      if((*hqP)->hqEnt->cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueCb->ueId -1] == NULL)
+      {
+         SCH_ALLOC(dciSlotAlloc, sizeof(DlMsgSchInfo));
+         if(!dciSlotAlloc)
+         {
+            DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for ded DL msg alloc");
+            return false;
+         }
+         (*hqP)->hqEnt->cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueCb->ueId -1] = dciSlotAlloc;
+         memset(dciSlotAlloc, 0, sizeof(DlMsgSchInfo));
+      }
+      else
+      {
+         dciSlotAlloc = (*hqP)->hqEnt->cell->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueCb->ueId -1];
+      }
+
+      /* Dl ded Msg info is copied, this was earlier filled in macSchDlRlcBoInfo */
+      fillDlMsgInfo(dciSlotAlloc, crnti, isRetx, *hqP);
+      dciSlotAlloc->transportBlock[0].ndi = isRetx;
+
+      /* [Step5]: Traverse each LC to fill the exact scheduled bytes of this LC and reset the LC Info node */
+      sliceCbNode = schSpcCell->sliceCbList.first;
+
+      if (isRetx == FALSE)
+      {
+         /* Update default slice allocation result to DCI in terms of LC */
+         if(defLcList.count != 0)
+            schSliceBasedUpdateGrantSizeForBoRpt(&defLcList, dciSlotAlloc, NULLP, &accumalatedSize, FALSE);
+         
+         /* Update dedicated slice allocation result to DCI in terms of LC */
+         while(sliceCbNode)
+         {
+            sliceCb = (SchSliceBasedSliceCb *)sliceCbNode->node;
+            
+            if(sliceCb->lcInfoList[ueId-1].count != 0)
+               schSliceBasedUpdateGrantSizeForBoRpt(&sliceCb->lcInfoList[ueId-1], dciSlotAlloc, NULLP, \
+                                                   &accumalatedSize, TRUE);
+               
+            sliceCbNode = sliceCbNode->next;
+         }
+      }
+      else
+      {
+         accumalatedSize = (*hqP)->tbInfo[0].tbSzReq;
+      }
+
+      /* Below case will hit if NO LC(s) are allocated due to resource crunch */
+      if(!accumalatedSize)
+      {
+         if(remainingPrb == 0)
+         {
+            DU_LOG("\nERROR  --> SCH : NO FREE PRB!!");
+         }
+         else
+         {
+            /*Schedule the LC for next slot*/
+            DU_LOG("\nDEBUG  -->  SCH : No LC has been scheduled");
+         }
+         /* Not Freeing dlMsgAlloc as ZERO BO REPORT to be sent to RLC so that
+         * Allocation can be done in next slot*/
+         accumalatedSize = 0;
+         
+         /* If failed, traverse next UE.*/
+         ueNode = ueNode->next;
+         continue;
+      }
+
+      /* [Step6]: Fill the scheduling result into PDCCH and PDSCH configuration */
+      if((schDlRsrcAllocDlMsg(cellCb, pdschTime, crnti, accumalatedSize, dciSlotAlloc, startPrb, pdschStartSymbol, \
+                              pdschNumSymbols, isRetx, *hqP)) != ROK)
+      {
+         DU_LOG("\nERROR  --> SCH : Scheduling of DL dedicated message failed");
+         /* Free the dl ded msg info allocated in macSchDlRlcBoInfo */
+         if(!dciSlotAlloc->dlMsgPdschCfg)
+         {
+            SCH_FREE(dciSlotAlloc, sizeof(DlMsgSchInfo));
+            cellCb->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId -1] = NULL;
+         }       
+         /* If failed, traverse next UE */
+         ueNode = ueNode->next;
+         continue;
+      }
+  
+      if (isRetx != TRUE)
+      {
+         accumalatedSize += TX_PAYLOAD_HDR_LEN;
+      }
+      numPRB = schCalcNumPrb(accumalatedSize, ueCb->ueCfg.dlModInfo.mcsIndex, pdschNumSymbols);
+      startPrb += numPRB; /*JOJO: accumulate start PRB.*/
+
+      /* [Step7]: Check if both DCI and DL_MSG are sent in the same slot.
+       * If not, allocate memory for DL_MSG PDSCH slot to store PDSCH 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));
+            cellCb->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
+            return false;
+         }
+         memcpy(dciSlotAlloc->dlMsgPdschCfg, &dciSlotAlloc->dlMsgPdcchCfg->dci.pdschCfg,  sizeof(PdschCfg));
+      }
+      else
+      {
+         /* Allocate memory to schedule dlMsgAlloc to send DL_Msg, pointer will be checked at schProcessSlotInd() */
+         if(cellCb->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1] == NULLP)
+         {
+            SCH_ALLOC(dlMsgAlloc, sizeof(DlMsgSchInfo));
+            if(dlMsgAlloc == NULLP)
+            {
+               DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for dlMsgAlloc");
+               SCH_FREE(dciSlotAlloc->dlMsgPdcchCfg, sizeof(PdcchCfg));
+               if(dciSlotAlloc->dlMsgPdschCfg == NULLP)
+               {
+                  SCH_FREE(dciSlotAlloc, sizeof(DlMsgSchInfo));
+                  cellCb->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
+               }
+               return false;
+            }
+            cellCb->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1] = dlMsgAlloc;
+            memset(dlMsgAlloc, 0, sizeof(DlMsgSchInfo));
+         }
+         else
+            dlMsgAlloc = cellCb->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1];
+
+         /* Copy all DL_MSG info */
+         dlMsgAlloc->crnti =crnti;
+         dlMsgAlloc->bwp = dciSlotAlloc->bwp;
+         SCH_ALLOC(dlMsgAlloc->dlMsgPdschCfg, sizeof(PdschCfg));
+         if(dlMsgAlloc->dlMsgPdschCfg)
+         {
+            memcpy(dlMsgAlloc->dlMsgPdschCfg, &dciSlotAlloc->dlMsgPdcchCfg->dci.pdschCfg, sizeof(PdschCfg));
+         }
+         else
+         {
+            SCH_FREE(dciSlotAlloc->dlMsgPdcchCfg, sizeof(PdcchCfg));    
+            if(dciSlotAlloc->dlMsgPdschCfg == NULLP)
+            {
+               SCH_FREE(dciSlotAlloc, sizeof(DlMsgSchInfo));
+               cellCb->schDlSlotInfo[pdcchTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
+
+            }
+            SCH_FREE(dlMsgAlloc, sizeof(DlMsgSchInfo));
+            cellCb->schDlSlotInfo[pdschTime.slot]->dlMsgAlloc[ueId-1] = NULLP;
+            DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for dlMsgAlloc->dlMsgPdschCfg");
+            return false;
+         }
+      }
+
+      /* [Step8]: Allocate the PUCCH resource for HARQ to this UE */
+      schAllocPucchResource(cellCb, pucchTime, crnti, ueCb, isRetx, *hqP);
+
+      cellCb->schDlSlotInfo[pdcchTime.slot]->pdcchUe = ueId;
+      cellCb->schDlSlotInfo[pdschTime.slot]->pdschUe = ueId;
+      cellCb->schUlSlotInfo[pucchTime.slot]->pucchUe = ueId;
+
+      ueSliceBasedCb->isTxPayloadLenAdded = FALSE;
+      cmLListDeleteLList(&defLcList);
+
+      /* [Step9]: Reset the BO of each LC and boIndBitMap for this UE */
+      /* Re-setting the BO's of all DL LCs in this UE */
+      for(lcIdx = 0; lcIdx < MAX_NUM_LC; lcIdx++)
+      {
+         ueCb->dlInfo.dlLcCtxt[lcIdx].bo = 0;
+      }
+
+      /* After allocation is done, unset the bo bit for that ue */
+      UNSET_ONE_BIT(ueId, cellCb->boIndBitMap);
+      ueSliceBasedCb->isDlMsgScheduled = true;
+      
+      ueNode = ueNode->next;
+   }
+
+   return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Main UL scheduling
+ *
+ * @details
+ *
+ *    Function : schSliceBasedUlScheduling
+ *
+ *    Functionality: Main UL scheduling
+ *
+ * @params[in] Pointer to Cell Control Block
+ *             Slot timing info
+ *             UE ID
+ *             Retransmission boolean
+ *             The address of pointer to UL HARQ Process Control Block
+ * 
+ * @return true     - success
+ *         false    - failure
+ *
+ * ****************************************************************/
+bool schSliceBasedUlScheduling(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 = NULLP;
+   SchK2TimingInfoTbl *k2InfoTbl=NULLP;
+   SlotTimingInfo dciTime, puschTime;
+   uint16_t startPrb = 0;
+   uint16_t maxFreePRB = 0;
+   uint16_t totalRemainingPrb = 0;
+   uint16_t currSliceCnt = 0;
+   SchSliceBasedCellCb *schSpcCell = NULLP;
+   CmLList *sliceCbNode = NULLP; 
+   SchSliceBasedSliceCb *sliceCb = NULLP;
+   
+   if(cell == NULLP)
+   {
+      DU_LOG("\nERROR  -->  SCH: schSliceBasedUlScheduling() : Cell is NULL");
+      return false;
+   }
+
+   ueCb = &cell->ueCb[ueId-1];
+   
+   if(ueCb == NULLP)
+   {
+      DU_LOG("\nERROR  -->  SCH: schSliceBasedUlScheduling() : 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;
+      }
+   }
+
+   schSpcCell = (SchSliceBasedCellCb *)cell->schSpcCell;
+   sliceCbNode = schSpcCell->sliceCbList.first;
+
+   maxFreePRB = searchLargestFreeBlock((*hqP)->hqEnt->cell, puschTime, &startPrb, DIR_UL);
+   totalRemainingPrb = maxFreePRB;
+
+   
+   if (isRetx == FALSE)
+   {
+
+#ifdef SCH_MULTI_THREAD
+      SchSliceBasedUlThreadArg *threadArg[schSpcCell->sliceCbList.count];
+      pthread_t intraSliceThread[schSpcCell->sliceCbList.count];
+      uint8_t threadRes;
+#endif
+
+      while(sliceCbNode)
+      {
+         sliceCb = (SchSliceBasedSliceCb *)sliceCbNode->node;
+         
+#ifdef SCH_MULTI_THREAD
+         SCH_ALLOC(threadArg[currSliceCnt], sizeof(SchSliceBasedUlThreadArg));
+         
+         if(!threadArg[currSliceCnt])
+         {
+            DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for thread argument");
+            return false;
+         }
+
+         /* Pack the argument for thread function */
+         threadArg[currSliceCnt]->cell = cell;
+         threadArg[currSliceCnt]->puschTime = puschTime;
+         threadArg[currSliceCnt]->puschNumSymbols = symbLen;
+         threadArg[currSliceCnt]->totalRemainingPrb = &totalRemainingPrb;
+         threadArg[currSliceCnt]->maxFreePRB = maxFreePRB;
+         threadArg[currSliceCnt]->sliceCb = sliceCb;
+         threadArg[currSliceCnt]->ueId = ueId;
+
+         /* Run the intra-slice scheduling with multi-thread feature */
+         threadRes = pthread_create(&intraSliceThread[currSliceCnt], NULL, schSliceBasedUlIntraSliceThreadScheduling, \
+                                    (void *)threadArg[currSliceCnt]);
+
+         if(threadRes != 0)
+         {
+            DU_LOG("\nERROR  -->  SCH : Thread Creation failed for UL intra-slice scheduling");
+            return false;
+         }
+
+         currSliceCnt++;
+         sliceCbNode = sliceCbNode->next;
+      }
+
+      for(int sliceCnt=0; sliceCnt < schSpcCell->sliceCbList.count; sliceCnt++)
+      {
+         if (pthread_join(intraSliceThread[sliceCnt], NULL)) 
+         {
+            DU_LOG("\nERROR  -->  SCH : Thread Join failed for UL intra-slice scheduling");
+            return false;
+         }
+
+         /* Garbage collection */
+         SCH_FREE(threadArg[sliceCnt], sizeof(SchSliceBasedUlThreadArg));
+      }
+
+#else
+         if(schSliceBasedUlIntraSliceScheduling(cell, puschTime, symbLen, &totalRemainingPrb, maxFreePRB, sliceCb, ueId) != ROK)
+         {
+            DU_LOG("\nDennis --> UL Intra Slice Scheduling Failed");
+            return false;
+         }
+
+         sliceCbNode = sliceCbNode->next;
+      }
+#endif
+
+   }  
+
+   if(schSliceBasedUlFinalScheduling(cell, puschTime, dciTime, startSymb, symbLen, ueId, isRetx, hqP, totalRemainingPrb, startPrb) != ROK)
+   {
+      DU_LOG("\nDennis --> UL Final Scheduling Failed");
+      return false;
+   }
+
+   return true;
+}
+
+/*******************************************************************
+ *
+ * @brief UL Intra-slice scheduling
+ *
+ * @details
+ *
+ *    Function : schSliceBasedUlIntraSliceScheduling
+ *
+ *    Functionality: UL Intra-slice scheduling
+ *
+ * @params[in] Pointer to Cell Control Block
+ *             Current Slot timing info
+ *             PDCCH Slot timing info
+ *             Number of PDSCH Symbols
+ *             Max FreePRB Block
+ *             Pointer to Slice Control Block
+ *             UE ID
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t schSliceBasedUlIntraSliceScheduling(SchCellCb *cellCb, SlotTimingInfo puschTime, uint8_t puschNumSymbols, \
+                                            uint16_t *totalRemainingPrb, uint16_t maxFreePRB, \
+                                            SchSliceBasedSliceCb *sliceCb, uint8_t ueId)
+{  
+   uint16_t crnti = 0;
+   uint16_t minimumPrb = 0, remainingPrb = 0;
+   uint16_t mcsIdx = 0;
+   SchUeCb *ueCb = NULLP;
+   DlMsgSchInfo *dciSlotAlloc;
+   SchSliceBasedUeCb *ueSliceBasedCb = NULLP;
+
+   /* Calculate the slice PRB quota according to RRMPolicyRatio and MaxFreePRB */
+   sliceCb->dedicatedPrb = (uint16_t)(((sliceCb->rrmPolicyRatioInfo.dedicatedRatio)*(maxFreePRB))/100);
+   sliceCb->prioritizedPrb = (uint16_t)(((sliceCb->rrmPolicyRatioInfo.minRatio - sliceCb->rrmPolicyRatioInfo.dedicatedRatio)\
+                                             *(maxFreePRB))/100);
+   sliceCb->sharedPrb = (uint16_t)(((sliceCb->rrmPolicyRatioInfo.maxRatio - sliceCb->rrmPolicyRatioInfo.minRatio)\
+                                          *(maxFreePRB))/100);
+   minimumPrb = sliceCb->dedicatedPrb + sliceCb->prioritizedPrb;
+
+   DU_LOG("\n\n===============Dennis  -->  SCH UL Intra-Slice : Start to run IntraSliceScheduling [SST:%d, MinimumPRB Quota:%d]===============", \
+   sliceCb->snssai.sst, minimumPrb);
+
+   GET_CRNTI(crnti,ueId);
+   ueCb = &cellCb->ueCb[ueId-1];
+   ueSliceBasedCb = (SchSliceBasedUeCb *)ueCb->schSpcUeCb;
+         
+   /* Update the requested BO of each LC in current slice */
+   schSliceBasedUpdateLcListReqBo(&sliceCb->lcInfoList[ueId-1], ueCb, DIR_UL);
+
+   if(minimumPrb != 0)
+   {
+      mcsIdx = ueCb->ueCfg.ulModInfo.mcsIndex;
+      remainingPrb = minimumPrb;
+      schSliceBasedPrbAllocUsingRRMPolicy(&sliceCb->lcInfoList[ueId-1], mcsIdx, puschNumSymbols, &remainingPrb, NULLP, &(ueCb->srRcvd));
+   }
+
+   sliceCb->allocatedPrb = minimumPrb - remainingPrb;
+   DU_LOG("\nDennis  -->  SCH UL Intra-Slice Result : [SST: %d, Allocated PRB: %d, Unallocated PRB: %d]", sliceCb->snssai.sst, \
+             sliceCb->allocatedPrb, remainingPrb);
+
+   
+   /* Deal with the problem which slice PRB quotas may be not integer */
+   if(sliceCb->allocatedPrb > sliceCb->dedicatedPrb)
+   {
+      *totalRemainingPrb = *totalRemainingPrb - sliceCb->allocatedPrb;
+   }
+   else
+   {
+      *totalRemainingPrb = *totalRemainingPrb - sliceCb->dedicatedPrb;
+   }
+
+   return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief UL Intra-slice scheduling for multi-thread feature
+ *
+ * @details
+ *
+ *    Function : schSliceBasedUlIntraSliceThreadScheduling
+ *
+ *    Functionality: UL Intra-slice scheduling for multi-thread feature
+ *
+ * @params[in] Pointer to thread argument
+ * @return void
+ *
+ * ****************************************************************/
+void *schSliceBasedUlIntraSliceThreadScheduling(void *threadArg)
+{
+   uint16_t crnti = 0;
+   uint16_t minimumPrb = 0, remainingPrb = 0;
+   uint16_t mcsIdx = 0;
+   SchUeCb *ueCb = NULLP;
+   DlMsgSchInfo *dciSlotAlloc;
+   SchSliceBasedUeCb *ueSliceBasedCb = NULLP;
+
+   SchSliceBasedUlThreadArg *ulThreadArg;
+   SchCellCb *cellCb;
+   SlotTimingInfo puschTime;
+   uint8_t puschNumSymbols;
+   uint16_t *totalRemainingPrb;
+   uint16_t maxFreePRB;
+   SchSliceBasedSliceCb *sliceCb;
+   uint8_t ueId;
+
+   ulThreadArg = (SchSliceBasedUlThreadArg *)threadArg;
+   cellCb = ulThreadArg->cell;
+   puschTime = ulThreadArg->puschTime;
+   puschNumSymbols = ulThreadArg->puschNumSymbols;
+   totalRemainingPrb = ulThreadArg->totalRemainingPrb;
+   maxFreePRB = ulThreadArg->maxFreePRB;
+   sliceCb = ulThreadArg->sliceCb;
+   ueId = ulThreadArg->ueId;
+
+   /* Calculate the slice PRB quota according to RRMPolicyRatio and MaxFreePRB */
+   sliceCb->dedicatedPrb = (uint16_t)(((sliceCb->rrmPolicyRatioInfo.dedicatedRatio)*(maxFreePRB))/100);
+   sliceCb->prioritizedPrb = (uint16_t)(((sliceCb->rrmPolicyRatioInfo.minRatio - sliceCb->rrmPolicyRatioInfo.dedicatedRatio)\
+                                             *(maxFreePRB))/100);
+   sliceCb->sharedPrb = (uint16_t)(((sliceCb->rrmPolicyRatioInfo.maxRatio - sliceCb->rrmPolicyRatioInfo.minRatio)\
+                                          *(maxFreePRB))/100);
+   minimumPrb = sliceCb->dedicatedPrb + sliceCb->prioritizedPrb;
+
+   DU_LOG("\n\n===============Dennis  -->  SCH UL Intra-Slice : Start to run IntraSliceScheduling [SST:%d, MinimumPRB Quota:%d]===============", \
+   sliceCb->snssai.sst, minimumPrb);
+
+   /* TODO: It should support multi-UEs per TTI scheduling */
+   //for(ueId=0; ueId<MAX_NUM_UE; ueId++)
+   GET_CRNTI(crnti,ueId);
+   ueCb = &cellCb->ueCb[ueId-1];
+   ueSliceBasedCb = (SchSliceBasedUeCb *)ueCb->schSpcUeCb;
+         
+   /* Update the requested BO of each LC in current slice */
+   schSliceBasedUpdateLcListReqBo(&sliceCb->lcInfoList[ueId-1], ueCb, DIR_UL);
+
+   if(minimumPrb != 0)
+   {
+      mcsIdx = ueCb->ueCfg.ulModInfo.mcsIndex;
+      remainingPrb = minimumPrb;
+      schSliceBasedPrbAllocUsingRRMPolicy(&sliceCb->lcInfoList[ueId-1], mcsIdx, puschNumSymbols, &remainingPrb, NULLP, &(ueCb->srRcvd));
+   }
+
+   sliceCb->allocatedPrb = minimumPrb - remainingPrb;
+   DU_LOG("\nDennis  -->  SCH UL Intra-Slice Result : [SST: %d, Allocated PRB: %d, Unallocated PRB: %d]", sliceCb->snssai.sst, \
+             sliceCb->allocatedPrb, remainingPrb);
+
+   
+   /* Deal with the problem which slice PRB quotas may be not integer */
+   if(sliceCb->allocatedPrb > sliceCb->dedicatedPrb)
+   {
+      *totalRemainingPrb = *totalRemainingPrb - sliceCb->allocatedPrb;
+   }
+   else
+   {
+      *totalRemainingPrb = *totalRemainingPrb - sliceCb->dedicatedPrb;
+   }
+
+
+   pthread_exit(NULL);  
+   return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief UL Final scheduling
+ *
+ * @details
+ *
+ *    Function : schSliceBasedUlFinalScheduling
+ *
+ *    Functionality: UL Final scheduling
+ *
+ * @params[in] Pointer to Cell Control Block
+ *             PUSCH Slot timing info
+ *             DCI Slot timing info
+ *             Number of PUSCH Symbols
+ *             Max FreePRB Block
+ *             Pointer to Slice Control Block
+ *             UE ID
+ *             Retranmission Flag
+ *             Double Pointer to HARQ UL Process Controll Block
+ *             Remaining PRBs after intra-slice scheduling
+ *             Start PRB Index
+ * 
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t schSliceBasedUlFinalScheduling(SchCellCb *cellCb, SlotTimingInfo puschTime, SlotTimingInfo dciTime, \
+                  uint8_t puschStartSymbol, uint8_t puschNumSymbols, uint8_t ueId, \
+                  bool isRetx, SchUlHqProcCb **hqP, uint16_t remainingPrb, uint16_t startPrb)
+{  
+   uint8_t lcIdx = 0;
+   uint16_t mcsIdx = 0;
+   uint16_t crnti = 0;
+   uint16_t availablePrb = 0;
+   uint32_t accumalatedSize = 0;
+   SchUeCb *ueCb = NULLP;
+   DciInfo  *dciInfo = NULLP;
+   SchPuschInfo *puschInfo;
+   SchSliceBasedCellCb *schSpcCell = NULLP;
+   CmLList *sliceCbNode = NULLP; 
+   CmLListCp defLcList;
+   SchSliceBasedSliceCb *sliceCb = NULLP;
+   SchSliceBasedUeCb *ueSliceBasedCb = NULLP;
+   
+   DU_LOG("\n\n===============Dennis  -->  SCH UL Final : Start to run final-scheduling [Remaining PRB is:%d]===============", remainingPrb);
+
+   /* TODO: It should support multi-UEs per TTI scheduling */
+   // For(loop the uePriorityList)
+   GET_CRNTI(crnti,ueId);
+   ueCb = &cellCb->ueCb[ueId-1];
+   ueSliceBasedCb = (SchSliceBasedUeCb *)ueCb->schSpcUeCb;
+
+   mcsIdx = ueCb->ueCfg.ulModInfo.mcsIndex;
+   if(remainingPrb != 0)
+   {
+      cmLListInit(&defLcList);
+
+      /* Allocate the remaining PRB to default slice */
+      for(lcIdx = 0; lcIdx < MAX_NUM_LOGICAL_CHANNEL_GROUPS; lcIdx++)
+      {
+         if(ueCb->ulInfo.ulLcCtxt[lcIdx].snssai == NULLP && ueCb->bsrInfo[lcIdx].dataVol != 0)
+         {
+            /*[Step2]: Update the reqPRB and Payloadsize for this LC in the appropriate List*/
+            if(updateLcListReqPRB(&defLcList, ueCb->ulInfo.ulLcCtxt[lcIdx].lcId,\
+                     ueCb->bsrInfo[lcIdx].dataVol) != ROK)
+            {
+               DU_LOG("\nERROR  --> SCH : Updation in LC List Failed");
+            }
+            else
+            {
+               DU_LOG("\nDennis  -->  SCH UL : Append LC to default LL [LCID, reqBO] [%d, %d]", lcIdx, \
+               ueCb->bsrInfo[lcIdx].dataVol);
+            }
+         }
+      }
+
+      availablePrb = remainingPrb;
+      schSliceBasedPrbAllocUsingRRMPolicy(&defLcList, mcsIdx, puschNumSymbols, &availablePrb, NULLP, &(ueCb->srRcvd));
+      DU_LOG("\nDennis  -->  SCH UL Final Default Slice : [Allocated PRB: %d, Remaining PRB: %d]", remainingPrb - availablePrb, availablePrb);
+      remainingPrb = availablePrb;
+   }
+
+   /* Allocate the remaining PRB to slice according to slice priority
+    * I assume that slice priority is implicit in the RAN Control indication from RIC */
+   schSpcCell = (SchSliceBasedCellCb *)cellCb->schSpcCell;
+   sliceCbNode = schSpcCell->sliceCbList.first;
+
+   while(sliceCbNode)
+   {
+      sliceCb = (SchSliceBasedSliceCb *)sliceCbNode->node;
+
+      /* TODO: It should support multi-UEs per TTI scheduling */
+      //For(loop the uePriorityList)
+      GET_CRNTI(crnti,ueId);
+      ueCb = &cellCb->ueCb[ueId-1];
+      ueSliceBasedCb = (SchSliceBasedUeCb *)ueCb->schSpcUeCb;
+      
+      DU_LOG("\n\n===============Dennis  -->  SCH UL Final : Start to run FinalScheduling [SST:%d, Shared PRB Quota:%d, Remaining PRB:%d]===============", \
+      sliceCb->snssai.sst, sliceCb->sharedPrb, remainingPrb);
+
+      if(remainingPrb != 0)
+      {
+         mcsIdx = ueCb->ueCfg.ulModInfo.mcsIndex;
+
+         if(sliceCb->sharedPrb >= remainingPrb)
+         {
+            availablePrb = remainingPrb; 
+            schSliceBasedPrbAllocUsingRRMPolicy(&sliceCb->lcInfoList[ueId-1], mcsIdx, puschNumSymbols, &availablePrb, NULLP, &(ueCb->srRcvd));
+            sliceCb->allocatedPrb += remainingPrb - availablePrb;
+            remainingPrb = availablePrb;
+         }
+         else
+         {
+            availablePrb = sliceCb->sharedPrb;
+            schSliceBasedPrbAllocUsingRRMPolicy(&sliceCb->lcInfoList[ueId-1], mcsIdx, puschNumSymbols, &availablePrb, NULLP, &(ueCb->srRcvd));
+            sliceCb->allocatedPrb += sliceCb->sharedPrb - availablePrb;
+            remainingPrb = remainingPrb - (sliceCb->sharedPrb - availablePrb);
+         }
+      }
+      DU_LOG("\nDennis  -->  SCH UL Final Scheduling Result : [SST: %d, Allocated PRB: %d, Remaining PRB: %d]", sliceCb->snssai.sst, \
+             sliceCb->allocatedPrb, remainingPrb);
+      sliceCbNode = sliceCbNode->next;
+   }
+
+   /* TODO: It should support multi-UEs per TTI scheduling */
+   // For(loop the uePriorityList)
+   GET_CRNTI(crnti,ueId);
+   ueCb = &cellCb->ueCb[ueId-1];
+   
+   /*[Step5]:Traverse each LCID in LcList to calculate the exact Scheduled Bytes
+    * using allocated BO per LC and Update dlMsgAlloc BO report for MAC */
+   sliceCbNode = schSpcCell->sliceCbList.first;
+
+   if (isRetx == FALSE)
+   {
+      /* Update default slice allocation result of accumalatedSize */
+      if(defLcList.count != 0)
+         schSliceBasedUpdateGrantSizeForBoRpt(&defLcList, NULLP, ueCb->bsrInfo, &accumalatedSize, FALSE);
+      
+      /* Update dedicated slice allocation result of accumalatedSize */
+      while(sliceCbNode)
+      {
+         sliceCb = (SchSliceBasedSliceCb *)sliceCbNode->node;
+         
+         if(sliceCb->lcInfoList[ueId-1].count != 0)
+            schSliceBasedUpdateGrantSizeForBoRpt(&sliceCb->lcInfoList[ueId-1], NULLP, ueCb->bsrInfo, &accumalatedSize, TRUE);
+            
+         sliceCbNode = sliceCbNode->next;
+      }
+   }
+
+   if(!accumalatedSize)
+   {
+      if((ueCb->srRcvd) || (isRetx))
+      {
+         accumalatedSize = schCalcTbSize(UL_GRANT_SIZE);
+         startPrb = MAX_NUM_RB;
+      }
+      else if(remainingPrb == 0)
+      {
+         /*Schedule the LC for next slot*/
+         DU_LOG("\nERROR  --> SCH : NO FREE PRB!!");
+         accumalatedSize = 0;
+         return RFAILED;
+      }
+      else
+      {
+          /*Schedule the LC for next slot*/
+         DU_LOG("\nDEBUG  -->  SCH : No LC has been scheduled");
+         accumalatedSize = 0;
+         return RFAILED;
+      }    
+   }
+
+   if(accumalatedSize > 0)
+   {
+      SCH_ALLOC(dciInfo, sizeof(DciInfo));
+      if(!dciInfo)
+      {
+         DU_LOG("\nERROR  -->  SCH : Memory Allocation failed for dciInfo alloc");
+         cmLListDeleteLList(&defLcList);
+         return RFAILED;
+      }
+      cellCb->schDlSlotInfo[dciTime.slot]->ulGrant = dciInfo;
+      memset(dciInfo,0,sizeof(DciInfo));
+      /* Update PUSCH allocation */
+      if(schFillPuschAlloc(ueCb, puschTime, accumalatedSize, puschStartSymbol, puschNumSymbols, startPrb, isRetx, *hqP) == ROK)
+      {
+         if(cellCb->schUlSlotInfo[puschTime.slot]->schPuschInfo)
+         {
+            puschInfo = cellCb->schUlSlotInfo[puschTime.slot]->schPuschInfo;
+            if(puschInfo != NULLP)
+            {
+               /* Fill DCI for UL grant */
+               schFillUlDci(ueCb, puschInfo, dciInfo, isRetx, *hqP);
+               ueCb->srRcvd = false;
+               ueCb->bsrRcvd = false;
+               cellCb->schUlSlotInfo[puschTime.slot]->puschUe = ueCb->ueId;
+               cmLListAdd2Tail(&(ueCb->hqUlmap[puschTime.slot]->hqList), &(*hqP)->ulSlotLnk);                  
+            }
+         }
+      }
+   }
+   cmLListDeleteLList(&defLcList);
+
+   return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Update the req BO for Lcinfo list for each slice
+ *
+ * @details
+ *
+ *    Function : schSliceBasedUpdateLcListReqBo
+ *
+ *    Functionality: Update the req BO for Lcinfo list for each slice
+ * 
+ * @params[in] Pointer to LC Info Control Block List
+ *             Pointer to UE Control Block
+ *             Direction
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t schSliceBasedUpdateLcListReqBo(CmLListCp *lcInfoList, SchUeCb *ueCb, Direction dir)
+{
+   CmLList *node = NULLP; 
+   SchSliceBasedLcInfo *lcInfoNode = NULLP;
+   uint8_t lcIdx;
+
+   node = lcInfoList->first;
+
+   if(!node)
+   {
+#ifdef SLICE_BASED_DEBUG_LOG
+      DU_LOG("\nDennis  -->  Dedicated LC LL is empty");
+#endif
+      return RFAILED;
+   }
+   else
+   {
+      while (node)
+      {
+         lcInfoNode = (SchSliceBasedLcInfo *)node->node;
+
+         lcIdx = lcInfoNode->lcId;
+
+         if(dir == DIR_DL)
+         {
+            if(ueCb->dlInfo.dlLcCtxt[lcIdx].bo)
+            {
+               lcInfoNode->reqBO = ueCb->dlInfo.dlLcCtxt[lcIdx].bo + MAC_HDR_SIZE;
+               lcInfoNode->allocBO = 0;
+               lcInfoNode->allocPRB = 0;
+#ifdef SLICE_BASED_DEBUG_LOG
+               DU_LOG("\nDennis  -->  SCH Intra-Slice : Update reqBO of DL LC [LcID:%d, reqBO:%d]", lcIdx, lcInfoNode->reqBO);
+#endif
+            }
+         }
+         else if(dir == DIR_UL)
+         {
+            /*TODO: lcgIdx and LCID has been implemented as one to one mapping.
+            * Need to check the mapping to figure out the LCID and lcgIdx once L2
+            * spec specifies any logic*/
+            if(lcIdx >= MAX_NUM_LOGICAL_CHANNEL_GROUPS)
+            {
+               DU_LOG("\nDennis  -->  SCH Intra-Slice : schSliceBasedUpdateLcListReqBo() LC Index is out of max number of LCG");
+               node = node->next;
+               continue;
+            }
+            else
+            {
+               if(ueCb->bsrInfo[lcIdx].dataVol)
+               {
+                  lcInfoNode->reqBO = ueCb->bsrInfo[lcIdx].dataVol;
+                  lcInfoNode->allocBO = 0;
+                  lcInfoNode->allocPRB = 0;
+#ifdef SLICE_BASED_DEBUG_LOG
+                  DU_LOG("\nDennis  -->  SCH Intra-Slice : Update reqBO of UL LC [LcID:%d, reqBO:%d]", lcIdx, lcInfoNode->reqBO);
+#endif
+               }
+            }
+            
+         }
+         
+         node = node->next;
+      }
+   }
+
+   return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Allocate PRB for each LC with FCFS algorithm (allocate the PRB by demand)
+ *
+ * @details
+ *
+ *    Function : schSliceBasedPrbAllocUsingRRMPolicy
+ *
+ *    Functionality: 
+ *      [Step1]: Traverse each Node in the LC list
+ *      [Step2]: Check whether the LC has ZERO requirement then clean this LC
+ *      [Step3]: If the LC is the First one to be allocated for this UE then add
+ *      TX_PAYLODN_LEN to reqBO 
+ *      [Step4]: Calculate the estimate PRB and estimate BO to be allocated
+ *               based on reqBO and maxPRB left.
+ *      [Step5]: Based on calculated PRB, Update Reserved PRB and Shared PRB counts
+ *      [Step6]: Deduce the reqBO based on allocBO and move the LC node to last.
+ *      [Step7]: Continue the next loop from List->head
+ *
+ *      [Loop Exit]:
+ *        [Exit1]: If PRBs are exhausted
+ *
+ * @params[in] I/P & O/P > Pointer to LC Info Control Block List
+ *             I/P > MCS Index
+ *             I/P > Number of PDSCH symbols 
+ *             I/P > Number of available PRB
+ *             I/P > isTxPayloadLenAdded[For DL] : Decision flag to add the TX_PAYLOAD_HDR_LEN
+ *             I/P > srRcvd Flag[For UL] : Decision flag to add UL_GRANT_SIZE
+ * 
+ * @return void
+ *
+ * ****************************************************************/
+void schSliceBasedPrbAllocUsingRRMPolicy(CmLListCp *lcInfoList, uint16_t mcsIdx, uint8_t numSymbols, uint16_t *availablePrb, \
+                                       bool *isTxPayloadLenAdded, bool *srRcvd)
+{
+   CmLList *node = NULLP;
+   LcInfo *lcInfoNode = NULLP;
+   uint16_t estPrb = 0;
+   uint32_t allocBO = 0;
+
+   if(lcInfoList == NULLP)
+   {
+      DU_LOG("\nERROR --> SCH: LcList not present");
+      return;
+   }
+   node = lcInfoList->first;
+
+   /* [Step1] */
+   while(node)
+   {
+#if 0
+      /*For Debugging purpose*/
+      printLcLL(lcLL);
+#endif
+      lcInfoNode = (LcInfo *)node->node;
+
+      /*[Exit 1]: If available PRBs are exhausted*/
+      /*Loop Exit: All resources exhausted*/
+      if(*availablePrb == 0)
+      {
+#ifdef SLICE_BASED_DEBUG_LOG
+         DU_LOG("\nDennis  -->  SCH: Dedicated resources exhausted for LC:%d",lcInfoNode->lcId);
+#endif
+         return;
+      }
+
+      if(lcInfoNode->reqBO != 0)
+      {
+         /* [Step3] */
+         if((isTxPayloadLenAdded != NULLP) && (*isTxPayloadLenAdded == FALSE))
+         {
+            *isTxPayloadLenAdded = TRUE;
+            DU_LOG("\nDEBUG  -->  SCH: LC:%d is the First node to be allocated which includes TX_PAYLOAD_HDR_LEN",\
+                  lcInfoNode->lcId);
+            allocBO = schSliceBasedcalculateEstimateTBSize((lcInfoNode->reqBO + TX_PAYLOAD_HDR_LEN), mcsIdx, numSymbols, *availablePrb, &estPrb);
+            allocBO -= TX_PAYLOAD_HDR_LEN;
+            lcInfoNode->allocBO += allocBO;
+         }
+         else if((srRcvd != NULLP) && (*srRcvd == TRUE))
+         {
+            DU_LOG("\nDEBUG  --> SCH: LC:%d is the First node to be allocated which includes UL_GRANT_SIZE",\
+                  lcInfoNode->lcId);
+            *srRcvd = FALSE;
+            lcInfoNode->reqBO += UL_GRANT_SIZE;
+            allocBO = schSliceBasedcalculateEstimateTBSize(lcInfoNode->reqBO, mcsIdx, numSymbols, *availablePrb, &estPrb);
+            lcInfoNode->allocBO += allocBO;
+         }
+         else
+         {
+            /* [Step4] */
+            allocBO = schSliceBasedcalculateEstimateTBSize(lcInfoNode->reqBO, mcsIdx, numSymbols, *availablePrb, &estPrb);
+            lcInfoNode->allocBO += allocBO;
+         }
+
+         /* [Step5] */
+         *availablePrb = *availablePrb - estPrb;
+         
+         /* [Step6] */
+         lcInfoNode->reqBO -= allocBO;  /*Update the reqBO with remaining bytes unallocated*/
+         lcInfoNode->allocPRB += estPrb;
+      }
+      /* [Step7]:Next loop: Next LC to be picked from the list */
+      node = node->next; 
+   }
+   return;
+}
+
+/*******************************************************************************************
+ *
+ * @brief Check the LC List and fill the LC and GrantSize to be sent to MAC as
+ * BO Report
+ *
+ * @details
+ *
+ *    Function : schSliceBasedUpdateGrantSizeForBoRpt
+ *
+ *    Functionality:
+ *             1. Check the LC List and fill the LC and GrantSize to be sent to MAC as
+ *                BO Report in dlMsgAlloc Pointer
+ *             2. Reset the lcInfoList after filling the scheduling result to DCI
+ *
+ * @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
+ *             I/P > isDedicated Flag
+ * @return void
+ *
+ * *******************************************************************************************/
+void schSliceBasedUpdateGrantSizeForBoRpt(CmLListCp *lcLL, DlMsgSchInfo *dlMsgAlloc,\
+                                    BsrInfo *bsrInfo, uint32_t *accumalatedBOSize, bool isDedicated)
+{
+   CmLList *node = NULLP, *next = NULLP;
+   
+
+   if(lcLL == NULLP)
+   {
+      DU_LOG("\nERROR --> SCH: LcList not present");
+      return;
+   }
+
+   if(lcLL->count)
+   {
+      node = lcLL->first;
+   }
+   else
+   {
+      /*lcLL is empty*/
+      return;
+   }
+
+   if(isDedicated)
+   {
+      SchSliceBasedLcInfo *lcNode = NULLP;
+
+      while(node)
+      {
+         next = node->next;
+         lcNode = (SchSliceBasedLcInfo *)node->node;
+         if(lcNode != NULLP)
+         {
+            if(lcNode->reqBO != 0 || lcNode->allocBO != 0)
+            {
+#ifdef SLICE_BASED_DEBUG_LOG
+               DU_LOG("\nINFO   -->  SCH : LcID:%d, [reqBO, allocBO, allocPRB]:[%d,%d,%d]",\
+                  lcNode->lcId, lcNode->reqBO, lcNode->allocBO, lcNode->allocPRB);
+#endif            
+               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; 
+
+#ifdef SLICE_BASED_DEBUG_LOG
+                  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);
+#endif
+
+                  dlMsgAlloc->transportBlock[0].numLc++;
+
+                  lcNode->reqBO = 0;
+                  lcNode->allocBO = 0;
+                  lcNode->allocPRB = 0;
+               }
+               else if(bsrInfo != NULLP)
+               {
+                  *accumalatedBOSize += lcNode->allocBO;   
+                  DU_LOG("\nINFO   --> SCH: UL : LCID:%d,reqBO:%d, TotalBO Size:%d",\
+                        lcNode->lcId,lcNode->reqBO, *accumalatedBOSize);
+
+                  bsrInfo[lcNode->lcId].dataVol = lcNode->reqBO;
+                  lcNode->reqBO = 0;
+                  lcNode->allocBO = 0;
+                  lcNode->allocPRB = 0;
+               }
+            }
+         }
+         node = next;
+      }/*End of while*/
+   }
+   else
+   {
+      LcInfo *lcNode = NULLP;
+     
+      while(node)
+      {
+         next = node->next;
+         lcNode = (LcInfo *)node->node;
+         if(lcNode != NULLP)
+         {
+            if(lcNode->reqBO != 0 || lcNode->allocBO != 0)
+            {
+#ifdef SLICE_BASED_DEBUG_LOG
+               DU_LOG("\nINFO   -->  SCH : LcID:%d, [reqBO, allocBO, allocPRB]:[%d,%d,%d]",\
+                  lcNode->lcId, lcNode->reqBO, lcNode->allocBO, lcNode->allocPRB);
+#endif
+
+               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; 
+
+#ifdef SLICE_BASED_DEBUG_LOG
+                  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);
+#endif
+
+                  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);
+
+                  bsrInfo[lcNode->lcId].dataVol = lcNode->reqBO;
+                  handleLcLList(lcLL, lcNode->lcId, DELETE);
+               }
+            }
+         }
+         node = next;
+      }/*End of while*/
+   }
+
+   return;
+}
+
+/*******************************************************************
+ *
+ * @brief Allocate PRB for each LC with Round Robin alogrithm (equally allocating PRB)
+ *
+ * @details
+ *
+ *    Function : schSliceBasedRoundRobinAlgoforLc
+ *
+ *    Functionality: 
+ *       [Step1]: Calculate the quantum PRB of each LC. In RR algorithm, the quantum of each LC is equal
+ *       [Step2]: Traverse each LC in the LC list
+ *       [Step3]: If the LC is the First one to be allocated for this UE then add TX_PAYLODN_LEN to reqBO
+ *       [Step4]: Update the available PRB based on the calculated estPrb
+ *       [Step5]: Deduce the reqBO based on allocBO 
+ *       [Step6]: Calculate the remaining LC which hasn't finished
+ *       [Step7]: Next loop: Next LC to be picked from the list 
+ *       [Step8]: Check is there any remaining PRB and LC which still has reqBO       
+ *       [Step9]: Traverse each LC and allocate the remaining PRB
+ * 
+ *       [Loop Exit]:
+ *          [Exit1]: If available PRBs are exhausted
+ *          [Exit2]: All LCs are allocated and has no reqBO 
+ * 
+ * @params[in] I/P & O/P > Pointer to LC Info Control Block List
+ *             I/P > Number of PDSCH symbols
+ *             I/P > Number of available PRB
+ *             I/P > isTxPayloadLenAdded Flag: Check whether the TxPayload should be added to the first node in current slice
+ *             I/P > srRcvd Flag[For UL] : Decision flag to add UL_GRANT_SIZE
+ *
+ * @return void
+ *
+ * ****************************************************************/
+void schSliceBasedRoundRobinAlgoforLc(CmLListCp *lcInfoList, uint8_t numSymbols, uint16_t *availablePrb, \
+                                       bool *isTxPayloadLenAdded, bool *srRcvd)
+{
+   CmLList *node = NULLP;
+   SchSliceBasedLcInfo *lcInfoNode = NULLP;
+   uint16_t estPrb = 0;
+   uint32_t allocBO = 0;
+   uint32_t totalTbs = 0;
+   uint16_t quantum = 0;
+   uint32_t quantumSize = 0;
+   uint8_t remainingLc = 0;
+   uint16_t mcsIdx;
+
+   if(lcInfoList == NULLP)
+   {
+#ifdef SLICE_BASED_DEBUG_LOG
+      DU_LOG("\nERROR --> SCH: LcList not present");
+#endif
+
+      return;
+   }
+
+   if(lcInfoList->count == 0)
+   {
+#ifdef SLICE_BASED_DEBUG_LOG
+      DU_LOG("\nDennis --> SCH: There is no LC in lcInfoList");
+#endif
+
+      return;
+   }
+
+   /* [Step1]: Calculate the quantum PRB of each LC. In RR algorithm, the quantum of each LC is equal */
+   remainingLc = lcInfoList->count;
+   quantum = *availablePrb/lcInfoList->count;
+
+   node = lcInfoList->first;
+
+   /* [Step2]: Traverse each lcInfo Node in the LC list */
+   while(node && quantum != 0)
+   {
+#if 0
+      /*For Debugging purpose*/
+      printLcLL(lcLL);
+#endif
+      lcInfoNode = (SchSliceBasedLcInfo *)node->node;
+
+      /* [Exit1]: If available PRBs are exhausted */
+      if(*availablePrb == 0)
+      {
+#ifdef SLICE_BASED_DEBUG_LOG
+         DU_LOG("\nDennis  -->  SCH: Dedicated resources exhausted for LC:%d",lcInfoNode->lcId);
+#endif
+         return;
+      }
+
+      mcsIdx = lcInfoNode->ueCb->ueCfg.dlModInfo.mcsIndex;
+      if(lcInfoNode->reqBO != 0)
+      {
+         /* [Step3]: If the LC is the First one to be allocated for this UE then add TX_PAYLODN_LEN to reqBO */
+         if((isTxPayloadLenAdded != NULLP) && (*isTxPayloadLenAdded == FALSE))
+         {
+            *isTxPayloadLenAdded = TRUE;
+#ifdef SLICE_BASED_DEBUG_LOG
+            DU_LOG("\nDEBUG  -->  SCH: LC:%d is the First node to be allocated which includes TX_PAYLOAD_HDR_LEN",\
+                  lcInfoNode->lcId);
+#endif
+            allocBO = schSliceBasedcalculateEstimateTBSize(lcInfoNode->reqBO + TX_PAYLOAD_HDR_LEN, mcsIdx, numSymbols, quantum, &estPrb);
+            allocBO = allocBO - TX_PAYLOAD_HDR_LEN;
+            lcInfoNode->allocBO += allocBO;      
+         }
+         else if((srRcvd != NULLP) && (*srRcvd == TRUE))
+         {
+            DU_LOG("\nDEBUG  --> SCH: LC:%d is the First node to be allocated which includes UL_GRANT_SIZE",\
+                  lcInfoNode->lcId);
+            *srRcvd = FALSE;
+            lcInfoNode->reqBO += UL_GRANT_SIZE;
+            allocBO = schSliceBasedcalculateEstimateTBSize(lcInfoNode->reqBO, mcsIdx, numSymbols, quantum, &estPrb);
+            lcInfoNode->allocBO += allocBO;
+         }
+         else
+         {
+            allocBO = schSliceBasedcalculateEstimateTBSize(lcInfoNode->reqBO, mcsIdx, numSymbols, quantum, &estPrb);
+            lcInfoNode->allocBO += allocBO;
+         }
+
+         /* [Step4]: Update the available PRB based on the calculated estPrb */
+         *availablePrb = *availablePrb - estPrb;
+         
+         /* [Step5]: Deduce the reqBO based on allocBO */
+         lcInfoNode->reqBO -= allocBO; 
+         lcInfoNode->allocPRB += estPrb;
+#ifdef SLICE_BASED_DEBUG_LOG
+         DU_LOG("\nDennis  -->  SCH: Allocate LC [Algorithm: RR, lcId: %d, allocBO: %d, estPRB: %d]", \
+         lcInfoNode->lcId, allocBO, estPrb);
+#endif
+
+         /* [Step6]: Calculate the remaining LC which hasn't finished */
+         if(lcInfoNode->reqBO == 0)
+         {
+            remainingLc--;
+         }
+      }
+      else
+      {
+         remainingLc--;
+      }
+      /* [Step7]: Next loop: Next LC to be picked from the list */
+      node = node->next; 
+   }
+
+   /* [Step8]: Check is there any remaining PRB and LC which still has reqBO */
+   if(remainingLc > 0 && *availablePrb)
+   {
+      node = lcInfoList->first;
+
+      /* [Step9]: Traverse each LC and allocate the remaining PRB */
+      while(node)
+      {
+         lcInfoNode = (SchSliceBasedLcInfo *)node->node;
+
+         if(*availablePrb == 0)
+         {
+#ifdef SLICE_BASED_DEBUG_LOG
+            DU_LOG("\nDennis  -->  SCH: Dedicated resources exhausted for LC:%d",lcInfoNode->lcId);
+#endif
+            return;
+         }
+
+         mcsIdx = lcInfoNode->ueCb->ueCfg.dlModInfo.mcsIndex;
+         if(lcInfoNode->reqBO != 0)
+         {
+            allocBO = schSliceBasedcalculateEstimateTBSize(lcInfoNode->reqBO, mcsIdx, numSymbols, *availablePrb, &estPrb);
+            lcInfoNode->allocBO += allocBO;
+
+            *availablePrb = *availablePrb - estPrb;
+            
+            lcInfoNode->reqBO -= allocBO;  /* Update the reqBO with remaining bytes unallocated */
+            lcInfoNode->allocPRB += estPrb;
+         }
+
+#ifdef SLICE_BASED_DEBUG_LOG
+         DU_LOG("\nDennis  -->  SCH: (Final) Allocate LC [Algorithm: RR, lcId: %d, allocBO: %d, estPRB: %d]",lcInfoNode->lcId, allocBO, estPrb);
+#endif
+         /* Next loop: Next LC to be picked from the list */
+         node = node->next; 
+      }
+   }
+   /* [Exit2]: All LCs are allocated and has no reqBO  */
+   return;
+
+}
+
+/*******************************************************************
+ *
+ * @brief Allocate PRB for each LC with WFQ alogrithm (proportionally allocating PRB based on weight)
+ *
+ * @details
+ *
+ *    Function : schSliceBasedWeightedFairQueueAlgoforLc
+ *
+ *    Functionality:
+ *       [Step1]: Traverse each LC in the LC list
+ *       [Step2]: Calculate the quantum PRB of each LC
+ *                In WFQ algorithm, the quantum of each LC is calculated according to the weight proportionally
+ *       [Step3]: If the LC is the First one to be allocated for this UE then add TX_PAYLODN_LEN to reqBO
+ *       [Step4]: Update the available PRB based on the calculated estPrb
+ *       [Step5]: Deduce the reqBO based on allocBO 
+ *       [Step6]: Calculate the remaining LC which hasn't finished
+ *       [Step7]: Next loop: Next LC to be picked from the list 
+ *       [Step8]: Check is there any remaining PRB and LC which still has reqBO       
+ *       [Step9]: Traverse each LC and allocate the remaining PRB
+ * 
+ *       [Loop Exit]:
+ *          [Exit1]: If available PRBs are exhausted
+ *          [Exit2]: All LCs are allocated and has no reqBO 
+ * 
+ * @params[in] I/P & O/P > Pointer to LC Info Control Block List
+ *             I/P > Number of PDSCH symbols
+ *             I/P > Number of available PRB
+ *             I/P > isTxPayloadLenAdded Flag: Check whether the TxPayload should be added to the first node in current slice
+ *             I/P > srRcvd Flag[For UL] : Decision flag to add UL_GRANT_SIZE
+ * 
+ * @return void
+ *
+ * ****************************************************************/
+void schSliceBasedWeightedFairQueueAlgoforLc(CmLListCp *lcInfoList, uint8_t numSymbols, uint16_t *availablePrb, \
+                                       bool *isTxPayloadLenAdded, bool *srRcvd)
+{
+   CmLList *node = NULLP;
+   SchSliceBasedLcInfo *lcInfoNode = NULLP;
+
+   uint16_t estPrb = 0;
+   uint32_t allocBO = 0;
+   uint16_t quantum = 0;
+   uint32_t quantumSize = 0;
+   uint8_t remainingLc = 0;
+   uint16_t mcsIdx;
+   uint16_t totalAvaiPrb = *availablePrb;
+
+   if(lcInfoList == NULLP)
+   {
+      DU_LOG("\nERROR --> SCH: LcList not present");
+      return;
+   }
+
+   if(lcInfoList->count == 0)
+   {
+#ifdef SLICE_BASED_DEBUG_LOG
+      DU_LOG("\nDennis --> SCH: There is no LC in lcInfoList");
+#endif
+      return;
+   }
+
+   remainingLc = lcInfoList->count;
+   node = lcInfoList->first;
+
+   /* [Step1]: Traverse each LC in the LC list */
+   while(node)
+   {
+#if 0
+      /*For Debugging purpose*/
+      printLcLL(lcLL);
+#endif
+      lcInfoNode = (SchSliceBasedLcInfo *)node->node;
+
+      /* [Exit1]: If available PRBs are exhausted */
+      if(*availablePrb == 0)
+      {
+#ifdef SLICE_BASED_DEBUG_LOG
+         DU_LOG("\nDennis  -->  SCH: Dedicated resources exhausted for LC:%d",lcInfoNode->lcId);
+#endif
+         return;
+      }
+
+      mcsIdx = lcInfoNode->ueCb->ueCfg.dlModInfo.mcsIndex;
+
+      if(lcInfoNode->reqBO != 0)
+      {
+         /* [Step2]: Calculate the quantum PRB of each LC */
+         quantum = totalAvaiPrb * lcInfoNode->weight;
+
+         /* Special case when totalAvaiPrb * lcInfoNode->weight < 1 */
+         if(quantum == 0)
+         {
+            break;
+         }
+
+         /* [Step3]: If the LC is the First one to be allocated for this UE then add TX_PAYLODN_LEN to reqBO */
+         if((isTxPayloadLenAdded != NULLP) && (*isTxPayloadLenAdded == FALSE))
+         {
+            *isTxPayloadLenAdded = TRUE;
+            DU_LOG("\nDEBUG  -->  SCH: LC:%d is the First node to be allocated which includes TX_PAYLOAD_HDR_LEN",\
+                  lcInfoNode->lcId);
+            allocBO = schSliceBasedcalculateEstimateTBSize(lcInfoNode->reqBO + TX_PAYLOAD_HDR_LEN, mcsIdx, numSymbols, quantum, &estPrb);
+            allocBO = allocBO - TX_PAYLOAD_HDR_LEN;
+            lcInfoNode->allocBO += allocBO;
+         }
+         else if((srRcvd != NULLP) && (*srRcvd == TRUE))
+         {
+            DU_LOG("\nDEBUG  --> SCH: LC:%d is the First node to be allocated which includes UL_GRANT_SIZE",\
+                  lcInfoNode->lcId);
+            *srRcvd = FALSE;
+            lcInfoNode->reqBO += UL_GRANT_SIZE;
+            allocBO = schSliceBasedcalculateEstimateTBSize(lcInfoNode->reqBO, mcsIdx, numSymbols, quantum, &estPrb);
+            lcInfoNode->allocBO += allocBO;
+         }
+         else
+         {
+            allocBO = schSliceBasedcalculateEstimateTBSize(lcInfoNode->reqBO, mcsIdx, numSymbols, quantum, &estPrb);
+            lcInfoNode->allocBO += allocBO;
+         }
+
+         /* [Step4]: Update the available PRB based on the calculated estPrb */
+         *availablePrb = *availablePrb - estPrb;
+         
+         /* [Step5]: Deduce the reqBO based on allocBO  */
+         lcInfoNode->reqBO -= allocBO;
+         lcInfoNode->allocPRB += estPrb;
+#ifdef SLICE_BASED_DEBUG_LOG
+         DU_LOG("\nDennis  -->  SCH: Allocate LC [Algorithm: WFQ, Priority Level: %d, lcId: %d, reqBO: %d, \
+         allocBO: %d, estPRB: %d]",lcInfoNode->priorLevel, lcInfoNode->lcId, lcInfoNode->reqBO, allocBO, estPrb);
+#endif
+
+         /* [Step6]: Calculate the remaining LC which hasn't finished */
+         if(lcInfoNode->reqBO == 0)
+         {
+            remainingLc--;
+         }
+      }
+      else
+      {
+         remainingLc--;
+      }
+      /* [Step7]: Next loop: Next LC to be picked from the list */
+      node = node->next; 
+   }
+
+   /* [Step8]: Check is there any remaining PRB and LC which still has reqBO */
+   if(remainingLc > 0 && *availablePrb)
+   {
+      node = lcInfoList->first;
+
+      /* [Step9]: Traverse each LC and allocate the remaining PRB */
+      while(node)
+      {
+         lcInfoNode = (SchSliceBasedLcInfo *)node->node;
+
+         /* [Exit1]: If available PRBs are exhausted */
+         if(*availablePrb == 0)
+         {
+#ifdef SLICE_BASED_DEBUG_LOG
+            DU_LOG("\nDennis  -->  SCH: (Final) Dedicated resources exhausted for LC:%d",lcInfoNode->lcId);
+#endif
+            return;
+         }
+
+         mcsIdx = lcInfoNode->ueCb->ueCfg.dlModInfo.mcsIndex;
+         if(lcInfoNode->reqBO != 0)
+         {
+            allocBO = schSliceBasedcalculateEstimateTBSize(lcInfoNode->reqBO, mcsIdx, numSymbols, *availablePrb, &estPrb);
+            lcInfoNode->allocBO += allocBO;
+
+            *availablePrb = *availablePrb - estPrb;
+
+            lcInfoNode->reqBO -= allocBO;  /*Update the reqBO with remaining bytes unallocated*/
+            lcInfoNode->allocPRB += estPrb;
+         }
+
+#ifdef SLICE_BASED_DEBUG_LOG
+         DU_LOG("\nDennis  -->  SCH: (Final) Allocate LC [Algorithm: RR, lcId: %d, allocBO: %d, estPRB: %d]",lcInfoNode->lcId, allocBO, estPrb);
+#endif
+
+         node = node->next; 
+      }
+   }
+   /* [Exit2]: All LCs are allocated and has no reqBO */
+   return;
+
+}
+
+
+
+/****************************************************************************
+ *
+ * @brief Calculate the Estimated TBS Size based on Spec 38.421 , Sec 5.3.1.2
+ *
+ * @details
+ *
+ *    Function : schSliceBasedcalculateEstimateTBSize
+ *
+ *    Functionality:
+ *       TBS Size calculation requires numPRB. Since exactPRB for reqBO is unknown thus 
+ *       will give the PRB value(from 0 to maxRB) one by one and 
+ *       try to find the TBS size closest to reqBO
+ *
+ * @params[in] I/P > reqBO, mcsIdx, num PDSCH symbols, 
+ *             I/P > maxRB: Maximum PRB count to reach for calculating the TBS
+ *             O/P > estPrb : Suitable PRB count for reaching the correct TBS
+ *       
+ *
+ * @return TBS Size > Size which will can be allocated for this LC
+ *        
+ *
+ *************************************************************************/
+uint32_t schSliceBasedcalculateEstimateTBSize(uint32_t reqBO, uint16_t mcsIdx, uint8_t numSymbols,\
+                                   uint16_t maxPRB, uint16_t *estPrb)
+{
+   uint32_t tbs = 0, effecBO = 0;
+
+   *estPrb = MIN_PRB;
+   
+   /*Loop Exit: [Special Case for maxPRB = 1]*/
+   if(maxPRB == 1)
+   {
+      tbs = schCalcTbSizeFromNPrb(*estPrb, mcsIdx, numSymbols);
+      tbs = tbs >> 3;
+      effecBO = MIN(tbs,reqBO);
+      return (effecBO);
+   }
+
+   /*Loop Exit: Either estPRB reaches the maxRB or TBS is found greater than equal to reqBO*/
+   do
+   {
+      tbs = schCalcTbSizeFromNPrb(*estPrb, mcsIdx, numSymbols);
+
+      /*TBS size calculated in above function is in Bits. 
+       * So to convert it into Bytes , we right shift by 3. 
+       * Eg: tbs=128 bits(1000 0000) ; Right Shift by 3: Tbs = 0001 0000(16 bytes)*/
+      tbs = tbs >> 3;
+      *estPrb += 1;
+   }while((tbs < reqBO) && (*estPrb < maxPRB));
+
+   /*Effective BO is the Grant which can be provided for this LC.
+    * Here,it is decided based on whether we can fully cater its requirment (reqBO) 
+    * or has to provide lesser grant due to resource limitation.
+    * Thus effective BO/Grant for this LC will be min of TBS calculated and reqBO*/
+   effecBO = MIN(tbs,reqBO);
+   return (effecBO);
+}
+
+/*******************************************************************
+ *
+ * @brief Allocate resource for each UE and LC with RR algorithm (equally allocating PRB)
+ *
+ * @details
+ *
+ *    Function : schSliceBasedRoundRobinAlgo
+ *
+ *    Functionality:
+ *       1. Select a scheduling method to run the scheduling algorithm:
+ *                Flat: Consider the LC level to schedule resource which means the LC of each UE would mix up to a LL
+ *                Hierarchy: Consider the UE level to scheduler resource which means allocate resource based on UE LL               
+ *       2. Run the scheduling for LC      
+ * 
+ * @params[in] I/P > Pointer to Cell Control Block
+ *             I/P > Pointer to UE List
+ *             I/P > Pointer to LC Info Control Block List
+ *             I/P > Number of PDSCH symbols
+ *             I/P & O/P > Number of available PRB and output remaining PRB
+ *             I/P > Scheduling Method (0:Flat, 1:Hierarchy)
+ *             I/P > srRcvd Flag[For UL] : Decision flag to add UL_GRANT_SIZE   
+ *   
+ * @return void
+ *
+ * ****************************************************************/
+void schSliceBasedRoundRobinAlgo(SchCellCb *cellCb, CmLListCp *ueList, CmLListCp *lcInfoList, uint8_t numSymbols, \
+                                 uint16_t *availablePrb, SchAlgoMethod algoMethod, bool *srRcvd)
+{
+   SchUeCb *ueCb = NULLP;
+   uint8_t  ueId;
+   CmLList *ueNode;
+   CmLList *lcNode;
+   CmLList *next;
+   CmLListCp casLcInfoList; /* Cascade LC Info LL */
+   SchSliceBasedUeCb *ueSliceBasedCb = NULLP;
+   SchSliceBasedCellCb  *schSpcCell;
+   uint16_t ueQuantum, remainingPrb;
+   
+   schSpcCell = (SchSliceBasedCellCb *)cellCb->schSpcCell;
+
+   ueNode = ueList->first;
+
+   /* Select a scheduling method to run the scheduling algorithm */
+   if(algoMethod == HIERARCHY)
+   {    
+      ueQuantum = *availablePrb / ueList->count;
+
+      /* Allocate resource to each UE */
+      while(ueNode)
+      {
+         ueId = *(uint8_t *)(ueNode->node);
+         ueCb = &cellCb->ueCb[ueId-1];
+         ueSliceBasedCb = (SchSliceBasedUeCb *)ueCb->schSpcUeCb;    
+         remainingPrb = ueQuantum;
+
+         schSliceBasedRoundRobinAlgoforLc(&lcInfoList[ueId-1], numSymbols, &remainingPrb, \
+                                          &ueSliceBasedCb->isTxPayloadLenAdded, srRcvd);
+                 
+         *availablePrb -= ueQuantum - remainingPrb;
+         ueNode = ueNode->next;
+      }
+
+      /* If there are remaining PRBs, do the scheduling again */
+      ueNode = ueList->first;
+      while(ueNode && *availablePrb > 0)
+      {
+         ueId = *(uint8_t *)(ueNode->node);
+         ueCb = &cellCb->ueCb[ueId-1];
+         ueSliceBasedCb = (SchSliceBasedUeCb *)ueCb->schSpcUeCb;
+
+         schSliceBasedRoundRobinAlgoforLc(&lcInfoList[ueId-1], numSymbols, availablePrb, \
+                                          &ueSliceBasedCb->isTxPayloadLenAdded, srRcvd);
+               
+         ueNode = ueNode->next;
+      }     
+   }
+
+   else if(algoMethod == FLAT)
+   {
+      cmLListInit(&casLcInfoList);
+
+      /* Cascade the LC Info List of each UEs */
+      while(ueNode)
+      {
+         ueId = *(uint8_t *)(ueNode->node);
+         ueCb = &cellCb->ueCb[ueId-1];
+         ueSliceBasedCb = (SchSliceBasedUeCb *)ueCb->schSpcUeCb;
+
+         lcNode = lcInfoList[ueId-1].first;
+
+         while(lcNode)
+         {
+            if(addNodeToLList(&casLcInfoList, lcNode->node, NULLP) != ROK)
+            {
+               DU_LOG("\nERROR  --> Dennis : Failed to add the LC Info in FLAT algorithm method");
+            }
+            lcNode = lcNode->next;
+         }
+         ueNode = ueNode->next;
+      }
+
+      /* Sort the cascade LC Info List in terms of priority level */
+      schSliceBasedSortLcByPriorLevel(&casLcInfoList, 1);
+
+      /* Allocate the resouce for cascade LC Info list */
+      schSliceBasedRoundRobinAlgoforLc(&casLcInfoList, numSymbols, availablePrb, \
+                                          &ueSliceBasedCb->isTxPayloadLenAdded, srRcvd);
+
+      /* Free the cascade LC Info list */
+      lcNode = casLcInfoList.first;
+      while(lcNode)
+      {
+         next = lcNode->next;
+         SCH_FREE(lcNode, sizeof(CmLList));
+         lcNode = next;
+      }
+   }
+   else
+   {
+      DU_LOG("\n In schSliceBasedRoundRobinAlgo(), invalid algoMethod");
+   }
+}
+
+/*******************************************************************
+ *
+ * @brief Allocate resource for each UE and LC with WeightFairQueue algorithm 
+ *        (Proportionally allocating resource by weight)
+ *
+ * @details
+ *
+ *    Function : schSliceBasedWeightedFairQueueAlgo
+ * 
+ *    Functionality:
+ *       1. Select a scheduling method to run the scheduling algorithm:
+ *                Flat: Consider the LC level to schedule resource which means the LC of each UE would mix up to a LL
+ *                Hierarchy: Consider the UE level to scheduler resource which means allocate resource based on UE LL               
+ *       2. Run the scheduling for LC      
+ * 
+ * @params[in] I/P > Pointer to Cell Control Block
+ *             I/P > Pointer to UE List
+ *             I/P > Pointer to LC Info Control Block List
+ *             I/P > Number of PDSCH symbols
+ *             I/P & O/P > Number of available PRB and output remaining PRB
+ *             I/P > Scheduling Method (0:Flat, 1:Hierarchy)
+ *             I/P > srRcvd Flag[For UL] : Decision flag to add UL_GRANT_SIZE   
+ *     
+ * @return void
+ *
+ * ****************************************************************/
+void schSliceBasedWeightedFairQueueAlgo(SchCellCb *cellCb, CmLListCp *ueList, CmLListCp *lcInfoList, uint8_t numSymbols, \
+                                 uint16_t *availablePrb, SchAlgoMethod algoMethod, bool *srRcvd)
+{
+   SchUeCb *ueCb = NULLP;
+   uint8_t  ueId;
+   CmLList *ueNode;
+   CmLList *lcNode;
+   CmLList *next;
+   CmLListCp casLcInfoList; /* Cascade LC Info LL */
+   SchSliceBasedUeCb *ueSliceBasedCb = NULLP;
+   SchSliceBasedLcInfo *lcInfoNode = NULLP;
+   uint16_t ueQuantum, remainingPrb, totalAvaiPrb;
+   float_t totalPriorityLevel = 0;
+
+   totalAvaiPrb = *availablePrb;
+   
+   ueNode = ueList->first;
+
+   if(algoMethod == HIERARCHY)
+   {    
+      
+      while(ueNode)
+      {
+         ueId = *(uint8_t *)(ueNode->node);
+         ueCb = &cellCb->ueCb[ueId-1];
+         ueSliceBasedCb = (SchSliceBasedUeCb *)ueCb->schSpcUeCb;
+         ueQuantum = *availablePrb * ueSliceBasedCb->prbWeight;
+         remainingPrb = ueQuantum;
+
+         /* Although this is WFQ algorithm, but it is for UE level (HIERARCHY) */
+         /* In LC level, we are still using RR */
+         schSliceBasedRoundRobinAlgoforLc(&lcInfoList[ueId-1], numSymbols, &remainingPrb, \
+                                          &ueSliceBasedCb->isTxPayloadLenAdded, srRcvd);
+                 
+         *availablePrb -= ueQuantum - remainingPrb;
+         ueNode = ueNode->next;
+      }
+
+      /* If there are remaining PRBs, do the scheduling again */
+      ueNode = ueList->first;
+      while(ueNode && *availablePrb > 0)
+      {
+         ueId = *(uint8_t *)(ueNode->node);
+         ueCb = &cellCb->ueCb[ueId-1];
+         ueSliceBasedCb = (SchSliceBasedUeCb *)ueCb->schSpcUeCb;
+
+         schSliceBasedRoundRobinAlgoforLc(&lcInfoList[ueId-1], numSymbols, availablePrb, \
+                                          &ueSliceBasedCb->isTxPayloadLenAdded, srRcvd);
+               
+         ueNode = ueNode->next;
+      }     
+   }
+
+   else if(algoMethod == FLAT)
+   {
+      cmLListInit(&casLcInfoList);
+
+      /* Cascade the LC Info List of each UEs */
+      while(ueNode)
+      {
+         ueId = *(uint8_t *)(ueNode->node);
+         ueCb = &cellCb->ueCb[ueId-1];
+         ueSliceBasedCb = (SchSliceBasedUeCb *)ueCb->schSpcUeCb;
+
+         lcNode = lcInfoList[ueId-1].first;
+
+         while(lcNode)
+         {
+            lcInfoNode = (SchSliceBasedLcInfo *)lcNode->node;
+            totalPriorityLevel += lcInfoNode->priorLevel;
+
+            if(addNodeToLList(&casLcInfoList, lcNode->node, NULLP) != ROK)
+            {
+               DU_LOG("\nERROR  --> Dennis : Failed to add the LC Info in FLAT algorithm method");
+            }
+            lcNode = lcNode->next;
+         }
+         ueNode = ueNode->next;
+      }
+
+      /* Sort the cascade LC Info List in terms of priority level */
+      schSliceBasedSortLcByPriorLevel(&casLcInfoList, totalPriorityLevel);
+
+      /* Allocate the resouce for cascade LC Info list */
+      schSliceBasedWeightedFairQueueAlgoforLc(&casLcInfoList, numSymbols, availablePrb, \
+                                          &ueSliceBasedCb->isTxPayloadLenAdded, srRcvd);
+
+      /* Free the cascade LC Info list */
+      lcNode = casLcInfoList.first;
+      while(lcNode)
+      {
+         next = lcNode->next;
+         SCH_FREE(lcNode, sizeof(CmLList));
+         lcNode = next;
+      }
+   }
+   else
+   {
+      DU_LOG("\n In schSliceBasedRoundRobinAlgo(), invalid algoMethod");
+   }
+}
+
+/*******************************************************************
+ *
+ * @brief Timer for experiment
+ *
+ * @details
+ *
+ *    Function : setRrmPolicyWithTimer
+ *
+ *    Functionality: Timer for experiment
+ *
+ * @params[in] Pointer to Cell
+ *            
+ * @return void
+ *
+ * ****************************************************************/
+void setRrmPolicyWithTimer(SchCellCb *cell)
+{
+   SchSliceBasedCellCb  *schSpcCell;
+   SchSliceBasedSliceCb *sliceCb = NULLP;
+   CmLList *sliceCbNode = NULLP;
+
+   schSpcCell = (SchSliceBasedCellCb *)cell->schSpcCell;
+
+   schSpcCell->slot_ind_count++;
+
+   // if(schSpcCell->slot_ind_count >= 30)
+   // {
+   //    schSpcCell->algoDelay++;
+   //    schSpcCell->slot_ind_count = 0;
+   // }
+   if(schSpcCell->slot_ind_count >= 500)
+   {
+      schSpcCell->timer_sec++;
+      DU_LOG("\nDennis --> Timer: %d s", schSpcCell->timer_sec);
+      schSpcCell->slot_ind_count = 0;
+   }
+
+
+   if(schSpcCell->timer_sec == 30)
+   {
+      sliceCbNode = schSpcCell->sliceCbList.first;
+      
+      while(sliceCbNode)
+      {
+         sliceCb = (SchSliceBasedSliceCb *)sliceCbNode->node;
+         
+         /* Adjust the RRMPolicyRatio of first slice */
+         if(sliceCbNode == schSpcCell->sliceCbList.first)
+         {
+            sliceCb->rrmPolicyRatioInfo.dedicatedRatio = 10;
+            sliceCb->rrmPolicyRatioInfo.minRatio = 50;
+            sliceCb->rrmPolicyRatioInfo.maxRatio = 100;
+
+         }
+         /* Adjust the RRMPolicyRatio of second slice */
+         else
+         {
+            sliceCb->rrmPolicyRatioInfo.dedicatedRatio = 10;
+            sliceCb->rrmPolicyRatioInfo.minRatio = 50;
+            sliceCb->rrmPolicyRatioInfo.maxRatio = 100;
+            sliceCb->algorithm = WFQ;
+         }
+
+         sliceCbNode = sliceCbNode->next;
+      }
+      schSpcCell->timer_sec = 0;
+   }
+   // else if(schSpcCell->timer_sec == 40)
+   // {
+   //    sliceCbNode = schSpcCell->sliceCbList.first;
+
+   //    while(sliceCbNode)
+   //    {
+   //       sliceCb = (SchSliceBasedSliceCb *)sliceCbNode->node;
+         
+   //       /* Adjust the RRMPolicyRatio of first slice */
+   //       if(sliceCbNode == schSpcCell->sliceCbList.first)
+   //       {
+   //          sliceCb->rrmPolicyRatioInfo.dedicatedRatio = 10;
+   //          sliceCb->rrmPolicyRatioInfo.minRatio = 50;
+   //          sliceCb->rrmPolicyRatioInfo.maxRatio = 100;
+   //       }
+   //       /* Adjust the RRMPolicyRatio of second slice */
+   //       else
+   //       {
+   //          sliceCb->rrmPolicyRatioInfo.dedicatedRatio = 10;
+   //          sliceCb->rrmPolicyRatioInfo.minRatio = 30;
+   //          sliceCb->rrmPolicyRatioInfo.maxRatio = 100;
+   //       }
+
+   //       sliceCbNode = sliceCbNode->next;
+   //    }   
+   // }
+   // else if(schSpcCell->timer_sec == 60)
+   // {    
+   //    sliceCbNode = schSpcCell->sliceCbList.first;
+
+   //    while(sliceCbNode)
+   //    {
+   //       sliceCb = (SchSliceBasedSliceCb *)sliceCbNode->node;
+         
+   //       /* Adjust the RRMPolicyRatio of first slice */
+   //       if(sliceCbNode == schSpcCell->sliceCbList.first)
+   //       {
+   //          sliceCb->rrmPolicyRatioInfo.dedicatedRatio = 10;
+   //          sliceCb->rrmPolicyRatioInfo.minRatio = 50;
+   //          sliceCb->rrmPolicyRatioInfo.maxRatio = 100;
+   //       }
+   //       /* Adjust the RRMPolicyRatio of second slice */
+   //       else
+   //       {
+   //          sliceCb->rrmPolicyRatioInfo.dedicatedRatio = 10;
+   //          sliceCb->rrmPolicyRatioInfo.minRatio = 50;
+   //          sliceCb->rrmPolicyRatioInfo.maxRatio = 100;
+   //       }
+
+   //       sliceCbNode = sliceCbNode->next;
+   //    }
+   //   }
+
+}
+
 /*******************************************************************
  *
  * @brief Initializes all function pointers to Slice Based function handler
@@ -1355,6 +4409,8 @@ void schSliceBasedAllApisInit(SchAllApis *allSliceBasedApi)
     allSliceBasedApi->SchDlRlcBoInfo = schSliceBasedDlRlcBoInfo;
     allSliceBasedApi->SchSrUciInd = schSliceBasedSrUciInd;
     allSliceBasedApi->SchBsr = schSliceBasedBsr;
+    allSliceBasedApi->SchSliceCfgReq = SchSliceBasedSliceCfgReq;
+    allSliceBasedApi->SchSliceRecfgReq = SchSliceBasedSliceRecfgReq;
 
     /* Internal API function pointers */
     allSliceBasedApi->SchAddToDlHqRetxList = schSliceBasedAddToDlHqRetxList;
index 2763aba..3dfe4df 100644 (file)
 ################################################################################
 *******************************************************************************/
 
-typedef struct schSliceBasedCellCb
+// #define SCH_MULTI_THREAD      /* Enable the multi-thread intra-slice scheduling feature */
+// #define SLICE_BASED_DEBUG_LOG    /* Enable the debug log */
+#define NUM_SLICE 2     /* Define the number of slices for multi thread feature */
+
+typedef enum
 {
-   CmLListCp     ueToBeScheduled;                   /*!< Linked list to store UEs pending to be scheduled, */
-}SchSliceBasedCellCb;
+   FLAT,
+   HIERARCHY
+}SchAlgoMethod;
+
+typedef enum
+{
+   RR, /* Round Robin */
+   WFQ /* Weight Fair Queue */
+}SchAlgorithm;
+
+/*Following structures to keep record and estimations of PRB allocated for each
+ * LC taking into consideration the RRM policies*/
+typedef struct schSliceBasedLcInfo
+{
+   uint8_t  lcId;     /*LCID for which BO are getting recorded*/
+   SchUeCb *ueCb;    /* To store which UE this LC belongs to */
+   uint16_t priorLevel; /* Priority Level which is associated with this LC */
+   float_t weight; /*  Weight (0 ~ 1) which is used for WFQ algorithm, could be calculated */
+   uint32_t reqBO;    /*Size of the BO requested/to be allocated for this LC*/
+   uint32_t allocBO;  /*TBS/BO Size which is actually allocated*/
+   uint8_t  allocPRB; /*PRB count which is allocated based on RRM policy/FreePRB*/
+}SchSliceBasedLcInfo;
 
 typedef struct schSliceBasedLcCb
 {
    /* TODO: For Multiple RRMPolicies, Make DedicatedLcInfo as array/Double Pointer 
-    * and have separate DedLCInfo for each RRMPolcyMemberList*/
-   /* Dedicated LC List will be allocated, if any available*/
+    * and have separate DedLCInfo for each RRMPolcyMemberList */
+   /* Dedicated LC List will be allocated, if any available */
    CmLListCp dedLcList;        /*Contain LCInfo per RRMPolicy*/
    CmLListCp defLcList; /*Linklist of LC assoc with Default S-NSSAI(s)*/
    /* SharedPRB number can be used by any LC.
@@ -47,11 +71,127 @@ typedef struct schSliceBasedHqCb
 typedef struct schSliceBasedUeCb
 {
    SchSliceBasedHqCb   hqRetxCb;
+   float_t prbWeight; /* prbWeight (0 ~ 1) is used for calculate the number of PRB within this TTI */
+   float_t weight; /* Weight (0 ~ 1) which is used for WFQ algorithm */
+
+   /* Ready for multi-UEs per TTI scheduling */
+   bool isTxPayloadLenAdded;
+   bool isDlMsgPending;
+   bool isDlMsgScheduled;
+   bool isUlGrantPending; 
+   bool isUlGrantScheduled;
 }SchSliceBasedUeCb;
 
+/* Store the information of slices */
+typedef struct schSliceBasedSliceCb
+{
+   Snssai  snssai;
+   /* Linked list to store SchSliceBasedLcInfo of each UE which is associated with this slice */
+   CmLListCp lcInfoList[MAX_NUM_UE]; 
+   uint16_t dedicatedPrb;  /* As per 3GPP 28.541 Sec: 4.3.36 */
+   uint16_t prioritizedPrb;   /* As per 3GPP 28.541 Sec: 4.3.36 */
+   uint16_t sharedPrb;  /* As per 3GPP 28.541 Sec: 4.3.36 */
+   uint16_t allocatedPrb; /* Store the allocated PRB per slice within 1 TTI */
+   SchRrmPolicyRatio rrmPolicyRatioInfo;
+   SchAlgoMethod algoMethod; /* Specify the scheduling method (0: flat, 1: hierarchy) */
+   SchAlgorithm algorithm; /* Specify the scheduling algorithm (0: Round Robin, 1: Weight Fair Queue) */
+}SchSliceBasedSliceCb;
+
+/* Parameter for DL multi-thread intra-slice scheduling */
+typedef struct schSliceBasedDlThreadArg   
+{
+   uint8_t *triggerFlag;
+   SchCellCb *cell;
+   SlotTimingInfo *pdcchTime;
+   uint8_t *pdschNumSymbols;
+   uint16_t *totalRemainingPrb;
+   uint16_t *maxFreePRB;
+   SchSliceBasedSliceCb *sliceCb;
+   CmLListCp *ueDlNewTransmission;
+}SchSliceBasedDlThreadArg;
+
+/* Multi-thread feature: Parameter for UL multi-thread intra-slice scheduling */
+typedef struct schSliceBasedUlThreadArg
+{
+   SchCellCb *cell;
+   SlotTimingInfo puschTime;
+   uint8_t puschNumSymbols;
+   uint16_t *totalRemainingPrb;
+   uint16_t maxFreePRB;
+   SchSliceBasedSliceCb *sliceCb;
+   uint8_t ueId;
+}SchSliceBasedUlThreadArg;
+
+typedef struct schSliceBasedCellCb
+{
+   CmLListCp     ueToBeScheduled;           /* Linked list to store UEs pending to be scheduled */
+   CmLListCp     sliceCbList;               /* Linked list to store slice control block with priority, the last node */
+
+   /* For experiment */
+   bool isTimerStart;
+   uint16_t slot_ind_count;
+   uint16_t timer_sec;
+   uint16_t algoDelay;
+
+   /* Multi-thread feature: For thread creating */
+   SchSliceBasedDlThreadArg *threadArg[NUM_SLICE];
+   pthread_t intraSliceThread[NUM_SLICE];
+   
+}SchSliceBasedCellCb;
+
 uint8_t schSliceBasedAddUeToSchedule(SchCellCb *cellCb, uint16_t ueIdToAdd);
+void SchSliceBasedSliceCfgReq(SchCellCb *cellCb);
+void SchSliceBasedSliceRecfgReq(SchCellCb *cellCb);
 void schSliceBasedAllApisInit(SchAllApis *allSliceBasedApi);
 
+/* Utility function for Slice-Based Scheduling */
+uint8_t schSliceBasedFillLcInfoToSliceCb(CmLListCp *sliceCbList, SchUeCb *ueCb);
+uint16_t schSliceBasedCalculatePriorLevel(uint16_t fiveQi);
+void schSliceBasedSortLcByPriorLevel(CmLListCp *lcInfoList, float_t totalPriorLevel);
+void schSliceBasedSortUeByWeight(SchCellCb *cellCb, CmLListCp *ueList, float_t totalWeight);
+uint8_t schSliceBasedUpdateLcListReqBo(CmLListCp *lcInfoList, SchUeCb *ueCb, Direction dir);
+void schSliceBasedUpdateGrantSizeForBoRpt(CmLListCp *lcLL, DlMsgSchInfo *dlMsgAlloc,\
+                                    BsrInfo *bsrInfo, uint32_t *accumalatedBOSize, bool isDedicated);
+uint32_t schSliceBasedcalculateEstimateTBSize(uint32_t reqBO, uint16_t mcsIdx, uint8_t numSymbols,\
+                                   uint16_t maxPRB, uint16_t *estPrb);                                  
+
+/* DL Slice-Based Main Function */
+bool schSliceBasedDlScheduling(SchCellCb *cell, SlotTimingInfo currTime, uint8_t ueId, bool isRetx, SchDlHqProcCb **hqP);
+uint8_t schSliceBasedDlIntraSliceScheduling(SchCellCb *cellCb, SlotTimingInfo pdcchTime, uint8_t pdschNumSymbols, \
+                                             CmLListCp *ueDlNewTransmission, uint16_t maxFreePRB, \
+                                             uint16_t *totalRemainingPrb, SchSliceBasedSliceCb *sliceCb);
+void *schSliceBasedDlIntraSliceThreadScheduling(void *threadArg);
+uint8_t schSliceBasedDlFinalScheduling(SchCellCb *cellCb, SlotTimingInfo pdschTime, SlotTimingInfo pdcchTime, \
+                                       SlotTimingInfo pucchTime, uint8_t pdschStartSymbol, uint8_t pdschNumSymbols, 
+                                       CmLListCp *ueDlNewTransmission, bool isRetx, SchDlHqProcCb **ueNewHarqList, \
+                                       uint16_t remainingPrb, uint16_t startPrb);
+
+/* UL Slice-Based Main Function (To be finished) */
+bool schSliceBasedUlScheduling(SchCellCb *cell, SlotTimingInfo currTime, uint8_t ueId, bool isRetx, SchUlHqProcCb **hqP);
+uint8_t schSliceBasedUlIntraSliceScheduling(SchCellCb *cellCb, SlotTimingInfo puschTime, uint8_t puschNumSymbols, \
+                                            uint16_t *totalRemainingPrb, uint16_t maxFreePRB, \
+                                            SchSliceBasedSliceCb *sliceCb, uint8_t ueId);
+void *schSliceBasedUlIntraSliceThreadScheduling(void *threadArg);
+uint8_t schSliceBasedUlFinalScheduling(SchCellCb *cellCb, SlotTimingInfo puschTime, SlotTimingInfo dciTime, \
+                  uint8_t puschStartSymbol, uint8_t puschNumSymbols, uint8_t ueId, \
+                  bool isRetx, SchUlHqProcCb **hqP, uint16_t remainingPrb, uint16_t startPrb);
+
+/* Scheduling Algorithm */
+void schSliceBasedRoundRobinAlgo(SchCellCb *cellCb, CmLListCp *ueList, CmLListCp *lcInfoList, uint8_t numSymbols, \
+                                 uint16_t *availablePrb, SchAlgoMethod algoMethod, bool *srRcvd);
+void schSliceBasedWeightedFairQueueAlgo(SchCellCb *cellCb, CmLListCp *ueList, CmLListCp *lcInfoList, \
+                                 uint8_t numSymbols, uint16_t *availablePrb, SchAlgoMethod algoMethod, bool *srRcvd);
+
+/* Scheduling Algorithm for Logical Channel Level */
+void schSliceBasedRoundRobinAlgoforLc(CmLListCp *lcInfoList, uint8_t numSymbols, uint16_t *availablePrb, \
+                                       bool *isTxPayloadLenAdded, bool *srRcvd);
+void schSliceBasedWeightedFairQueueAlgoforLc(CmLListCp *lcInfoList, uint8_t numSymbols, uint16_t *availablePrb, \
+                                       bool *isTxPayloadLenAdded, bool *srRcvd);
+void schSliceBasedPrbAllocUsingRRMPolicy(CmLListCp *lcInfoList, uint16_t mcsIdx, uint8_t numSymbols, \
+                                          uint16_t *availablePrb, bool *isTxPayloadLenAdded, bool *srRcvd);
+
+/* For experiment */
+void setRrmPolicyWithTimer(SchCellCb *cell);
 /**********************************************************************
     End of file
  *********************************************************************/
index 00ea9b9..945561f 100644 (file)
@@ -31,6 +31,7 @@ File:     sch_slot_ind.c
 /** @file sch_slot_ind.c
   @brief This module processes slot indications
  */
+#include <time.h>
 #include "common_def.h"
 #include "tfu.h"
 #include "lrg.h"
@@ -41,6 +42,7 @@ File:     sch_slot_ind.c
 #include "mac_sch_interface.h"
 #include "sch.h"
 #include "sch_utils.h"
+#include "sch_slice_based.h"
 #ifdef NR_DRX 
 #include "sch_drx.h"
 #endif
index 1711ecb..3d84830 100644 (file)
@@ -124,7 +124,21 @@ void fillSchDlLcCtxt(SchDlLcCtxt *ueCbLcCfg, SchLcCfg *lcCfg)
    if(lcCfg->drbQos)
    {
      ueCbLcCfg->pduSessionId = lcCfg->drbQos->pduSessionId;
+
+     if(lcCfg->drbQos->fiveQiType == SCH_QOS_NON_DYNAMIC) /* Non-Dynamic 5QI */
+     {
+         ueCbLcCfg->fiveQi = lcCfg->drbQos->u.nonDyn5Qi.fiveQi;
+     }
+     else /* Dynamic 5QI */
+     {
+         ueCbLcCfg->fiveQi = lcCfg->drbQos->u.dyn5Qi.fiveQi;
+     }
+   }
+   else /* DRB has no 5QI */
+   {
+      ueCbLcCfg->fiveQi = 0;
    }
+
    if(lcCfg->snssai)
    {
      if(ueCbLcCfg->snssai == NULLP)/*In CONFIG_MOD case, no need to allocate SNSSAI memory*/
@@ -1203,6 +1217,7 @@ uint8_t SchModUeConfigReq(Pst *pst, SchUeRecfgReq *ueRecfg)
          SchSendUeRecfgRspToMac(ueRecfg, inst, RSP_OK, &recfgRsp);
       }
    }
+   cellCb->api->SchModUeConfigReq(ueCb);
    return ret;
 }
 
index 9d65480..3ae1c38 100644 (file)
@@ -765,6 +765,42 @@ uint8_t pucchResourceSet[MAX_PUCCH_RES_SET_IDX][4] = {
 { 1,   0, 14,  0 }, /* index 15 */
 };
 
+/* QoS Configuration */
+/* 5QI value and Table Index Mapping */
+uint16_t fiveQiIdxTable[MAX_5QI_TABLE_IDX] = {1, 2, 3, 4, 65, 66, 67, 75, 71, 72, 73, 74, 76, 5, 6, 7, 8, 9, 69, 70, 79, 80, 82, 83, 84, 85, 86};
+
+/* 3GPP TS 23.501 Table 5.7.4-1: Standardized 5QI to QoS characteristics mapping */
+/* Resource type(0 = GBR, 1 = Non-GBR, 2 = delay critical GBR) ,  Default Priority Level */
+uint16_t fiveQiTable[MAX_5QI_TABLE_IDX][2] = {
+      {0,   20},
+      {0,   40},
+      {0,   30},
+      {0,   50},
+      {0,   7},
+      {0,   20},
+      {0,   15},
+      {0,   0}, /* 5QI Value = 75 doesn't define default priority level */
+      {0,   56},
+      {0,   56},
+      {0,   56},
+      {0,   56},
+      {0,   56},
+      {1,   10},
+      {1,   60},
+      {1,   70},
+      {1,   80},
+      {1,   90},
+      {1,   5},
+      {1,   55},
+      {1,   65},
+      {1,   68},
+      {2,   19},
+      {2,   22},
+      {2,   24},
+      {2,   21},
+      {2,   18}
+};
+
 /* Minimum Msg3 scheduling time should be calculated based on N1+N2+NTAmax+0.5
  * ms formula.
  * Refer spec 38.213 section 8.3.
index 094a1b7..792507f 100644 (file)
@@ -34,6 +34,7 @@
 #define DEFAULT_UL_ACK_LIST_COUNT 8 /* Max number of pusch time domain uplink allocation */
 #define MASK_BIT64_ON 0xFFFFFFFFFFFFFFFF
 #define MIN_PRB 1
+#define MAX_5QI_TABLE_IDX 27
 
 #define SET_BITS_MSB(_startBit, _numBits, _byte) \
 {                                                \
@@ -108,6 +109,9 @@ uint8_t puschDeltaTable[MAX_MU_PUSCH];
 uint16_t prachCfgIdxTable[MAX_PRACH_CONFIG_IDX][8];
 uint16_t numRbForPrachTable[MAX_RACH_NUM_RB_IDX][5];
 uint8_t schCmnDlRvTbl[4];
+uint16_t fiveQiIdxTable[MAX_5QI_TABLE_IDX];
+uint16_t fiveQiTable[MAX_5QI_TABLE_IDX][2];
+
 /* Functions declarations : Linked list handler */
 uint8_t addNodeToLList(CmLListCp *llist, void *blockToAdd, CmLList *currNode);
 uint8_t deleteNodeFromLList(CmLListCp *llist, CmLList *node);
index ffc921e..6877399 100644 (file)
 #define MAX_NUM_RB TOTAL_PRB_20MHZ_MU0 /* value for numerology 0, 20 MHz */
 #endif
 
-#define ODU_UE_THROUGHPUT_PRINT_TIME_INTERVAL      5     /* in milliseconds */
-#define ODU_SNSSAI_THROUGHPUT_PRINT_TIME_INTERVAL  60000 /* in milliseconds */
+#define ODU_UE_THROUGHPUT_PRINT_TIME_INTERVAL      500     /* in milliseconds */
+#define ODU_SNSSAI_THROUGHPUT_PRINT_TIME_INTERVAL  500     /* in milliseconds */
+#define ODU_DRB_THROUGHPUT_PRINT_TIME_INTERVAL     500      /* in milliseconds */
 
 /*Spec 38.331 Sec 6.4: Maximum number of paging occasion per paging frame*/
 #define MAX_PO_PER_PF 4
index 89d0d74..5c7e697 100755 (executable)
@@ -58,7 +58,7 @@ extern "C" {
 #ifdef XEON_SPECIFIC_CHANGES   /* This change is done to avoid Heap allocation with 16UE/TTI config  */
 #define RGU_MAX_LC     8    /*!< Maximum Number of dedicated Logical Channels.*/
 #else
-#define RGU_MAX_LC     4    /*!< Maximum Number of dedicated Logical Channels.*/
+#define RGU_MAX_LC     8    /*!< Maximum Number of dedicated Logical Channels.*/
 #endif
 
 /* Event corresponding to each primitive at this interface */
index 7801726..8d32301 100644 (file)
@@ -324,21 +324,60 @@ uint8_t readMacCfg()
 #ifndef O1_ENABLE
 
    /*Note: Static Configuration, when O1 is not configuring the RRM policy*/
-   RrmPolicyList rrmPolicy;
-   rrmPolicy.id[0] = 1;
-   rrmPolicy.resourceType = PRB;
-   rrmPolicy.rRMMemberNum = 1;
-   memcpy(rrmPolicy.rRMPolicyMemberList[0].mcc,duCfgParam.macCellCfg.cellCfg.plmnInfoList[0].plmn.mcc, 3*sizeof(uint8_t));
-   memcpy(rrmPolicy.rRMPolicyMemberList[0].mnc,duCfgParam.macCellCfg.cellCfg.plmnInfoList[0].plmn.mnc, 3*sizeof(uint8_t));
-   rrmPolicy.rRMPolicyMemberList[0].sst = 1;
-   rrmPolicy.rRMPolicyMemberList[0].sd[0] = 2;
-   rrmPolicy.rRMPolicyMemberList[0].sd[1] = 3;
-   rrmPolicy.rRMPolicyMemberList[0].sd[2] = 4;
-   rrmPolicy.rRMPolicyMaxRatio = 90;
-   rrmPolicy.rRMPolicyMinRatio = 30;
-   rrmPolicy.rRMPolicyDedicatedRatio = 10;
-
-   cpyRrmPolicyInDuCfgParams(&rrmPolicy, 1, &duCfgParam.tempSliceCfg);
+   RrmPolicyList rrmPolicy[NUM_OF_SUPPORTED_SLICE];
+   rrmPolicy[0].id[0] = 1;
+   rrmPolicy[0].resourceType = PRB;
+   rrmPolicy[0].rRMMemberNum = 1;
+   memcpy(rrmPolicy[0].rRMPolicyMemberList[0].mcc,duCfgParam.macCellCfg.cellCfg.plmnInfoList[0].plmn.mcc, 3*sizeof(uint8_t));
+   memcpy(rrmPolicy[0].rRMPolicyMemberList[0].mnc,duCfgParam.macCellCfg.cellCfg.plmnInfoList[0].plmn.mnc, 3*sizeof(uint8_t));
+   rrmPolicy[0].rRMPolicyMemberList[0].sst = 1;
+   rrmPolicy[0].rRMPolicyMemberList[0].sd[0] = 2;
+   rrmPolicy[0].rRMPolicyMemberList[0].sd[1] = 3;
+   rrmPolicy[0].rRMPolicyMemberList[0].sd[2] = 4;
+   rrmPolicy[0].rRMPolicyMaxRatio = 100;
+   rrmPolicy[0].rRMPolicyMinRatio = 50;
+   rrmPolicy[0].rRMPolicyDedicatedRatio = 10;
+
+   rrmPolicy[1].id[0] = 2;
+   rrmPolicy[1].resourceType = PRB;
+   rrmPolicy[1].rRMMemberNum = 1;
+   memcpy(rrmPolicy[1].rRMPolicyMemberList[0].mcc,duCfgParam.macCellCfg.cellCfg.plmnInfoList[0].plmn.mcc, 3*sizeof(uint8_t));
+   memcpy(rrmPolicy[1].rRMPolicyMemberList[0].mnc,duCfgParam.macCellCfg.cellCfg.plmnInfoList[0].plmn.mnc, 3*sizeof(uint8_t));
+   rrmPolicy[1].rRMPolicyMemberList[0].sst = 2;
+   rrmPolicy[1].rRMPolicyMemberList[0].sd[0] = 3;
+   rrmPolicy[1].rRMPolicyMemberList[0].sd[1] = 3;
+   rrmPolicy[1].rRMPolicyMemberList[0].sd[2] = 4;
+   rrmPolicy[1].rRMPolicyMaxRatio = 100;
+   rrmPolicy[1].rRMPolicyMinRatio = 50;
+   rrmPolicy[1].rRMPolicyDedicatedRatio = 10;
+
+   // rrmPolicy[2].id[0] = 3;
+   // rrmPolicy[2].resourceType = PRB;
+   // rrmPolicy[2].rRMMemberNum = 1;
+   // memcpy(rrmPolicy[2].rRMPolicyMemberList[0].mcc,duCfgParam.macCellCfg.cellCfg.plmnInfoList[0].plmn.mcc, 3*sizeof(uint8_t));
+   // memcpy(rrmPolicy[2].rRMPolicyMemberList[0].mnc,duCfgParam.macCellCfg.cellCfg.plmnInfoList[0].plmn.mnc, 3*sizeof(uint8_t));
+   // rrmPolicy[2].rRMPolicyMemberList[0].sst = 3;
+   // rrmPolicy[2].rRMPolicyMemberList[0].sd[0] = 4;
+   // rrmPolicy[2].rRMPolicyMemberList[0].sd[1] = 3;
+   // rrmPolicy[2].rRMPolicyMemberList[0].sd[2] = 4;
+   // rrmPolicy[2].rRMPolicyMaxRatio = 100;
+   // rrmPolicy[2].rRMPolicyMinRatio = 33;
+   // rrmPolicy[2].rRMPolicyDedicatedRatio = 10;
+
+   // rrmPolicy[3].id[0] = 4;
+   // rrmPolicy[3].resourceType = PRB;
+   // rrmPolicy[3].rRMMemberNum = 1;
+   // memcpy(rrmPolicy[3].rRMPolicyMemberList[0].mcc,duCfgParam.macCellCfg.cellCfg.plmnInfoList[0].plmn.mcc, 3*sizeof(uint8_t));
+   // memcpy(rrmPolicy[3].rRMPolicyMemberList[0].mnc,duCfgParam.macCellCfg.cellCfg.plmnInfoList[0].plmn.mnc, 3*sizeof(uint8_t));
+   // rrmPolicy[3].rRMPolicyMemberList[0].sst = 3;
+   // rrmPolicy[3].rRMPolicyMemberList[0].sd[0] = 4;
+   // rrmPolicy[3].rRMPolicyMemberList[0].sd[1] = 3;
+   // rrmPolicy[3].rRMPolicyMemberList[0].sd[2] = 4;
+   // rrmPolicy[3].rRMPolicyMaxRatio = 100;
+   // rrmPolicy[3].rRMPolicyMinRatio = 25;
+   // rrmPolicy[3].rRMPolicyDedicatedRatio = 10;
+
+   cpyRrmPolicyInDuCfgParams(rrmPolicy, NUM_OF_SUPPORTED_SLICE, &duCfgParam.tempSliceCfg);
 
 #endif
 
@@ -611,7 +650,7 @@ uint8_t readCfg()
 
 #ifndef O1_ENABLE
    /* Note: Added these below variable for local testing*/
-   Snssai snssai[NUM_OF_SUPPORTED_SLICE] = {{1,{2,3,4}},{5,{6,7,8}}};
+   Snssai snssai[NUM_OF_SUPPORTED_SLICE] = {{1,{2,3,4}},{2,{3,3,4}},{3,{4,3,4}},{4,{5,3,4}}};
 #endif
 
    /* Gnb Id */