From bc06ea21c14b105b0a79db41d1e4c4733d084a5f Mon Sep 17 00:00:00 2001 From: johnson72 Date: Tue, 23 Jul 2024 18:08:01 +0800 Subject: [PATCH] FCFS.c problem fix Change-Id: Ie4defcd6436184323b4d562687de02cc2cc31d7e Signed-off-by: johnson72 --- src/5gnrrlc/rlc_cfg_dl.c | 7 + src/5gnrrlc/rlc_layer_mgr.c | 7 + src/5gnrrlc/rlc_tmr.c | 63 +- src/5gnrrlc/rlc_upr_inf_mgr.c | 257 +++- src/5gnrrlc/rlc_utils.h | 22 + src/5gnrrlc/rlc_utl_dl.c | 11 + src/5gnrsch/sch.c | 12 + src/5gnrsch/sch.h | 3 + src/5gnrsch/sch_fcfs.c | 40 + src/5gnrsch/sch_slice_based.c | 3062 ++++++++++++++++++++++++++++++++++++++++- src/5gnrsch/sch_slice_based.h | 150 +- src/5gnrsch/sch_slot_ind.c | 2 + src/5gnrsch/sch_ue_mgr.c | 15 + src/5gnrsch/sch_utils.c | 36 + src/5gnrsch/sch_utils.h | 4 + src/cm/common_def.h | 5 +- src/cm/rgu.h | 2 +- src/du_app/du_cfg.c | 71 +- 18 files changed, 3738 insertions(+), 31 deletions(-) diff --git a/src/5gnrrlc/rlc_cfg_dl.c b/src/5gnrrlc/rlc_cfg_dl.c index a42e44df1..f4728fb08 100755 --- a/src/5gnrrlc/rlc_cfg_dl.c +++ b/src/5gnrrlc/rlc_cfg_dl.c @@ -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; diff --git a/src/5gnrrlc/rlc_layer_mgr.c b/src/5gnrrlc/rlc_layer_mgr.c index 304e60e02..759ae4c06 100755 --- a/src/5gnrrlc/rlc_layer_mgr.c +++ b/src/5gnrrlc/rlc_layer_mgr.c @@ -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); } diff --git a/src/5gnrrlc/rlc_tmr.c b/src/5gnrrlc/rlc_tmr.c index 0c7234e64..eba0cfee8 100755 --- a/src/5gnrrlc/rlc_tmr.c +++ b/src/5gnrrlc/rlc_tmr.c @@ -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 diff --git a/src/5gnrrlc/rlc_upr_inf_mgr.c b/src/5gnrrlc/rlc_upr_inf_mgr.c index a717adf6a..f1b952af9 100755 --- a/src/5gnrrlc/rlc_upr_inf_mgr.c +++ b/src/5gnrrlc/rlc_upr_inf_mgr.c @@ -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 **********************************************************************/ diff --git a/src/5gnrrlc/rlc_utils.h b/src/5gnrrlc/rlc_utils.h index caf2c7e94..b3c2215ce 100755 --- a/src/5gnrrlc/rlc_utils.h +++ b/src/5gnrrlc/rlc_utils.h @@ -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, diff --git a/src/5gnrrlc/rlc_utl_dl.c b/src/5gnrrlc/rlc_utl_dl.c index 870ff96c6..595a7d590 100755 --- a/src/5gnrrlc/rlc_utl_dl.c +++ b/src/5gnrrlc/rlc_utl_dl.c @@ -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); } } diff --git a/src/5gnrsch/sch.c b/src/5gnrsch/sch.c index 2278e0976..5b36ec155 100644 --- a/src/5gnrsch/sch.c +++ b/src/5gnrsch/sch.c @@ -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); } } diff --git a/src/5gnrsch/sch.h b/src/5gnrsch/sch.h index 4feaa1828..705429454 100644 --- a/src/5gnrsch/sch.h +++ b/src/5gnrsch/sch.h @@ -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); diff --git a/src/5gnrsch/sch_fcfs.c b/src/5gnrsch/sch_fcfs.c index edfad6659..898de1a4c 100644 --- a/src/5gnrsch/sch_fcfs.c +++ b/src/5gnrsch/sch_fcfs.c @@ -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; diff --git a/src/5gnrsch/sch_slice_based.c b/src/5gnrsch/sch_slice_based.c index 149e7d975..a3da86aee 100644 --- a/src/5gnrsch/sch_slice_based.c +++ b/src/5gnrsch/sch_slice_based.c @@ -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<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; ueIdueCb[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; diff --git a/src/5gnrsch/sch_slice_based.h b/src/5gnrsch/sch_slice_based.h index 2763aba43..3dfe4dfd0 100644 --- a/src/5gnrsch/sch_slice_based.h +++ b/src/5gnrsch/sch_slice_based.h @@ -16,16 +16,40 @@ ################################################################################ *******************************************************************************/ -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 *********************************************************************/ diff --git a/src/5gnrsch/sch_slot_ind.c b/src/5gnrsch/sch_slot_ind.c index 00ea9b933..945561f52 100644 --- a/src/5gnrsch/sch_slot_ind.c +++ b/src/5gnrsch/sch_slot_ind.c @@ -31,6 +31,7 @@ File: sch_slot_ind.c /** @file sch_slot_ind.c @brief This module processes slot indications */ +#include #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 diff --git a/src/5gnrsch/sch_ue_mgr.c b/src/5gnrsch/sch_ue_mgr.c index 1711ecbe4..3d848305e 100644 --- a/src/5gnrsch/sch_ue_mgr.c +++ b/src/5gnrsch/sch_ue_mgr.c @@ -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; } diff --git a/src/5gnrsch/sch_utils.c b/src/5gnrsch/sch_utils.c index 9d65480b6..3ae1c3839 100644 --- a/src/5gnrsch/sch_utils.c +++ b/src/5gnrsch/sch_utils.c @@ -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. diff --git a/src/5gnrsch/sch_utils.h b/src/5gnrsch/sch_utils.h index 094a1b721..792507f5e 100644 --- a/src/5gnrsch/sch_utils.h +++ b/src/5gnrsch/sch_utils.h @@ -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); diff --git a/src/cm/common_def.h b/src/cm/common_def.h index ffc921ea2..6877399ad 100644 --- a/src/cm/common_def.h +++ b/src/cm/common_def.h @@ -112,8 +112,9 @@ #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 diff --git a/src/cm/rgu.h b/src/cm/rgu.h index 89d0d7454..5c7e69710 100755 --- a/src/cm/rgu.h +++ b/src/cm/rgu.h @@ -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 */ diff --git a/src/du_app/du_cfg.c b/src/du_app/du_cfg.c index 780172611..8d32301a8 100644 --- a/src/du_app/du_cfg.c +++ b/src/du_app/du_cfg.c @@ -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 */ -- 2.16.6