[Epic-ID: ODUHIGH-516][Task-ID: ODUHIGH-532] RIC Subscription Delete Req/Rsp API...
[o-du/l2.git] / src / 5gnrsch / sch.c
index 563cb5a..ace885e 100644 (file)
@@ -131,6 +131,11 @@ uint8_t SchInstCfg(RgCfg *cfg, Inst  dInst)
       return (LCM_REASON_MEM_NOAVAIL);
    }   
 
+   /* Initialize statistics related configurations */
+   memset(&schCb[inst].statistics, 0, sizeof(SchStatistics));
+   cmLListInit(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList);
+   cmLListInit(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList);
+
    /* Set Config done in TskInit */
    schCb[inst].schInit.cfgDone = TRUE;
    DU_LOG("\nINFO   -->  SCH : Scheduler gen config done");
@@ -1383,7 +1388,7 @@ uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
    }
    
    /* Update statistics of PRB usage if stats calculation is enabled */
-   if(schCb[cell->instIdx].statistics.dlTotalPrbUsage)
+   if(schCb[cell->instIdx].statistics.activeKpiList.dlTotPrbUseList.count)
       prbAlloc->numPrbAlloc += numPrb;
 
    /* Update the remaining number for free PRBs */
@@ -1520,7 +1525,7 @@ uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
    }
 
    /* Update statistics of PRB usage if stats calculation is enabled */
-   if(schCb[cell->instIdx].statistics.ulTotalPrbUsage)
+   if(schCb[cell->instIdx].statistics.activeKpiList.ulTotPrbUseList.count)
       prbAlloc->numPrbAlloc += numPrb;
 
    /* Update the remaining number for free PRBs */
@@ -2501,6 +2506,142 @@ uint8_t SchProcPhrInd(Pst *pst, SchPwrHeadroomInd *schPhrInd)
    return ret;
 }
 
+/*******************************************************************
+ *
+ * @brief Fill and send statistics response to MAC
+ *
+ * @details
+ *
+ *    Function :  SchSendStatsRspToMac
+ *
+ *    Functionality: Fill and send statistics response to MAC
+ *
+ * @params[in]  Inst inst, SchMacRsp result
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchSendStatsRspToMac(SchStatsRsp *statsRsp)
+{
+   Pst rspPst;
+   uint8_t ret = ROK;
+   SchStatsRsp  *schStatsRsp;
+
+   DU_LOG("\nINFO   --> SCH : Filling statistics response");
+   SCH_ALLOC(schStatsRsp, sizeof(SchStatsRsp));
+   if(schStatsRsp == NULLP)
+   {
+      DU_LOG("\nERROR  --> SCH : Failed to allocate memory in SchSendStatsRspToMac()");
+      return RFAILED;
+   }
+   memcpy(schStatsRsp, statsRsp, sizeof(SchStatsRsp));
+   memset(statsRsp, 0, sizeof(SchStatsRsp));
+
+   /* Filling response post */
+   memset(&rspPst, 0, sizeof(Pst));
+   FILL_PST_SCH_TO_MAC(rspPst, inst);
+   rspPst.event = EVENT_STATISTICS_RSP_TO_MAC;
+
+   ret = MacMessageRouter(&rspPst, (void *)schStatsRsp);
+   if(ret == RFAILED)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchSendStatsRspToMac(): Failed to send Statistics Response");
+      return ret;
+   }
+   return ret;
+}
+
+/*******************************************************************
+ *
+ * @brief Rejects all statistics group requested by MAC
+ *
+ * @details
+ *
+ *    Function : SchRejectAllStats
+ *
+ *    Functionality: Add all statistics group received in statistics
+ *       request from MAC, to Reject-Stats-Group-List in statistics
+ *       response to MAC
+ *
+ * @params[in]  Statistics request from MAC
+ *              Cause of rejection
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchRejectAllStats(SchStatsReq *schStatsReq, CauseOfResult cause)
+{
+   uint8_t grpIdx = 0;
+   SchStatsRsp schStatsRsp;
+
+   memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
+
+   /* Copying all stats group from stats request to stats response */
+   schStatsRsp.subscriptionId = schStatsReq->subscriptionId;
+   for(grpIdx = 0; grpIdx < schStatsReq->numStatsGroup; grpIdx++)
+   {
+      schStatsRsp.statsGrpRejectedList[grpIdx].groupId = schStatsReq->statsGrpList[grpIdx].groupId;
+      schStatsRsp.statsGrpRejectedList[grpIdx].cause = cause;
+   }
+   schStatsRsp.numGrpRejected = schStatsReq->numStatsGroup;
+
+   return SchSendStatsRspToMac(&schStatsRsp);
+}
+
+/*******************************************************************
+ *
+ * @brief Add active KPI pointers to KPI-Active-List
+ *
+ * @details
+ *
+ *    Function : schAddToKpiActiveList
+ *
+ *    Functionality: For each active statistics group for which timer
+ *       is running, add its KPI pointer to KPI-Active-List.
+ *       Use case :
+ *       When it is needed to update a KPI parameters, we need not
+ *       traverse all statistics group and all KPIs within a group
+ *       to get the specific KPI pointer to be updated.
+ *       Instead, we can traverse through KPI-Active-List and update
+ *       all entries in this list.
+ *
+ * @params[in]  Statistics request from MAC
+ *              Cause of rejection
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t schAddToKpiActiveList(Inst inst, SchStatsGrp *grpInfo)
+{
+   CmLList  *node = NULLP;
+
+   /* If DL Total PRB Usage configured for this stats group, add to list */
+   if(grpInfo->kpiStats.dlTotalPrbUsage)
+   {
+      SCH_ALLOC(node, sizeof(CmLList));
+      if(node)
+      {
+         node->node = (PTR)grpInfo->kpiStats.dlTotalPrbUsage; 
+         cmLListAdd2Tail(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, node);
+      }
+   }
+
+   /* If UL Total PRB Usage configured for this stats group, add to list */
+   node = NULLP;
+   if(grpInfo->kpiStats.ulTotalPrbUsage)
+   {
+      SCH_ALLOC(node, sizeof(CmLList));
+      if(node)
+      {
+         node->node = (PTR)grpInfo->kpiStats.ulTotalPrbUsage; 
+         cmLListAdd2Tail(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, node);
+      }
+   }
+
+   return ROK;
+}
+
 /*******************************************************************
  *
  * @brief Processes Statistics Request from MAC
@@ -2510,140 +2651,446 @@ uint8_t SchProcPhrInd(Pst *pst, SchPwrHeadroomInd *schPhrInd)
  *    Function : SchProcStatsReq
  *
  *    Functionality:
- *       Processes Statistics Request from MAC
  *
- * @params[in] 
+ *     This function process the statistics request from MAC:
+ *     [Step 1] Basic validation. If fails, all stats group in stats request are
+ *     rejected.
+ *     [Step 2] If basic validations passed, traverse all stats group and
+ *     validate each measurement types in each group.
+ *     [Step 3] If any measurement type validation fails in a group, that group
+ *     is not configured and it is added to stats-group-rejected-list in
+ *     sch-stats-response message.
+ *     [Step 4] If a group passes all validation, it is added to SCH database.
+ *     A timer is started for this group. And the group is added to 
+ *     stats-group-accepted-list in sch-stats-response message.
+ *     [Step 5] sch-stats-response is sent to du app with stats-group-rejected-list
+ *     and stats-group-accepted-list.
+ *
+ * @params[in] Post structure
+ *             Statistics Request from MAC 
  * @return ROK     - success
  *         RFAILED - failure
  *
  * ****************************************************************/
 uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq)
 {
-   uint8_t idx;
+   uint8_t grpIdx = 0, reqGrpIdx = 0, reqMeasIdx = 0;
    Inst    inst = pst->dstInst - SCH_INST_START;
-   SchMacRsp     rsp = RSP_OK;
-   CauseOfResult cause = SUCCESSFUL;
-   bool isDlTotlPrbUseCfgd = false, isUlTotlPrbUseCfgd = false;
+   bool    measTypeInvalid;
+   CauseOfResult cause;
+   SchStatsInfo  *statsInfo = NULLP;
+   SchStatsGrpInfo *grpInfo = NULLP;
+   SchStatsGrp *grpInfoDb = NULLP;
+   SchStatsRsp schStatsRsp;
 
    DU_LOG("\nINFO   -->  SCH : Received Statistics Request from MAC");
 
-   for(idx=0; idx < statsReq->numStats; idx++)
+   if(statsReq == NULLP)
    {
-      switch(statsReq->statsList[idx].type)
-      {
-         case SCH_DL_TOTAL_PRB_USAGE:
-            {
-               /* Check if duplicate configuration */
-               if(schCb[inst].statistics.dlTotalPrbUsage)
-               {
-                  DU_LOG("\nERROR   -->  SCH : SCH_DL_TOTAL_PRB_USAGE stats already configured");
-                  rsp = RSP_NOK;
-                  cause = DUPLICATE_ENTRY;
-               }
+      DU_LOG("\nERROR  -->  SCH : SchProcStatsReq(): Received Null pointer");
+      return RFAILED;
+   }
 
-               /* Allocate memory */
-               SCH_ALLOC(schCb[inst].statistics.dlTotalPrbUsage, sizeof(TotalPrbUsage));
-               if(!schCb[inst].statistics.dlTotalPrbUsage)
-               {
-                  DU_LOG("\nERROR   -->  SCH : Memory allocation failed for dlTotalPrbUsage in \
-                        SchProcStatsReq()");
-                  rsp = RSP_NOK;
-                  cause = RESOURCE_UNAVAILABLE;
-                  break;
-               }
+   /* [Step 1] Basic validation. If fails, all stats group in stats request are rejected */
+   
+   /* If maximum number of statistics already configured */
+   if(schCb[inst].statistics.numOfStatsCfgd >= MAX_NUM_STATS_CFG)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchProcStatsReq: Maximum number of statistics configured. \
+            Cannot process new request.");
+      SchRejectAllStats(statsReq, RESOURCE_UNAVAILABLE);
+      SCH_FREE(statsReq, sizeof(SchStatsReq));
+      return RFAILED;
+   }
+
+   memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
+
+   /* [Step 2] Traverse all stats group and validate each measurement types in each group */
+   statsInfo = &schCb[inst].statistics.statsInfoList[schCb[inst].statistics.numOfStatsCfgd];
+   statsInfo->numStatsGroup = 0;
+   for(reqGrpIdx=0; reqGrpIdx<statsReq->numStatsGroup && grpIdx<MAX_NUM_STATS; reqGrpIdx++)
+   {
+       measTypeInvalid = false;
+       grpInfo = &statsReq->statsGrpList[reqGrpIdx];
+       grpInfoDb = &statsInfo->statsGrpList[grpIdx];
+       for(reqMeasIdx = 0; reqMeasIdx < grpInfo->numStats; reqMeasIdx++)
+       {
+          switch(grpInfo->statsList[reqMeasIdx])
+          {
+             case SCH_DL_TOTAL_PRB_USAGE:
+                {
+                   /* Allocate memory */
+                   SCH_ALLOC(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
+                   if(!grpInfoDb->kpiStats.dlTotalPrbUsage)
+                   {
+                      DU_LOG("\nERROR   -->  SCH : Memory allocation failed for dlTotalPrbUsage in \
+                            SchProcStatsReq()");
+                      measTypeInvalid = true;
+                      cause = RESOURCE_UNAVAILABLE;
+                   }
+                   break;
+                }
+
+             case SCH_UL_TOTAL_PRB_USAGE:
+                {
+                   /* Allocate memory */
+                   SCH_ALLOC(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
+                   if(!grpInfoDb->kpiStats.ulTotalPrbUsage)
+                   {
+                      DU_LOG("\nERROR   -->  SCH : Memory allocation failed for dlTotalPrbUsage in \
+                            SchProcStatsReq()");
+                      measTypeInvalid = true;
+                      cause = RESOURCE_UNAVAILABLE;
+                   }
+                   break;
+                }
+
+             default:
+                {
+                   DU_LOG("\nERROR  -->  SCH : SchProcStatsReq: Invalid measurement type [%d]", \
+                         grpInfo->statsList[reqMeasIdx]);
+                   measTypeInvalid = true;
+                   cause = PARAM_INVALID;
+                   break;
+                }
+          }
+
+          /* [Step 3 a] If any measurement type validation fails in a group, that group
+           *  is not configured */
+          if(measTypeInvalid)
+          {
+             SCH_FREE(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
+             SCH_FREE(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
+             memset(grpInfoDb, 0, sizeof(SchStatsGrp));   
+             break;
+          }
+       }
+   
+       /* [Step 4] If a group passes all validation, it is added to SCH database.
+        * A timer is started for this group. And the group is added to
+        * stats-group-accepted-list in sch-stats-response message. */
+       if(!measTypeInvalid)
+       {
+          /* Add this group's configured KPIs to list of Active KPIs */
+          if(schAddToKpiActiveList(inst, grpInfoDb) == ROK)
+          {
+             grpInfoDb->schInst = inst;
+             grpInfoDb->subscriptionId = statsReq->subscriptionId;
+             grpInfoDb->groupId = grpInfo->groupId;
+             grpInfoDb->periodicity = grpInfo->periodicity;
+
+
+             /* Start timer */
+             cmInitTimers(&(grpInfoDb->periodTimer), 1);
+             schStartTmr(&schCb[inst], (PTR)(grpInfoDb), EVENT_STATISTICS_TMR, grpInfoDb->periodicity);
+
+             schStatsRsp.statsGrpAcceptedList[schStatsRsp.numGrpAccepted] = grpInfo->groupId;
+             schStatsRsp.numGrpAccepted++;
+             grpIdx++;
+          }
+          else
+          {
+            memset(grpInfoDb, 0, sizeof(SchStatsGrp));
+          }
+       }
+       else
+       {
+          /* [Step 3 b] The rejected group is added to stats-group-rejected-list in
+           * sch-stats-response message */
+          memset(grpInfoDb, 0, sizeof(SchStatsGrp));
+          schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].groupId = grpInfo->groupId;
+          schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].cause = cause;
+          schStatsRsp.numGrpRejected++;
+       }
+   }
+   statsInfo->numStatsGroup = grpIdx;
+   if(statsInfo->numStatsGroup)
+   {
+      schCb[inst].statistics.numOfStatsCfgd++;
+   }
+   else
+   {
+      memset(statsInfo, 0, sizeof(SchStatsInfo));
+   }
+   schStatsRsp.subscriptionId = statsReq->subscriptionId;
 
-               /* Initialize */
-               memset(schCb[inst].statistics.dlTotalPrbUsage, 0, sizeof(TotalPrbUsage));
+   SCH_FREE(statsReq, sizeof(SchStatsReq));
 
-               /* Configure */
-               schCb[inst].statistics.dlTotalPrbUsage->schInst = inst;
-               schCb[inst].statistics.dlTotalPrbUsage->periodicity = statsReq->statsList[idx].periodicity;
-               cmInitTimers(&(schCb[inst].statistics.dlTotalPrbUsage->periodTimer), 1);
+   /* [Step 5] sch-stats-response is sent to du app with stats-group-rejected-list
+    * and stats-group-accepted-list. */
+   SchSendStatsRspToMac(&schStatsRsp);
 
-               /* Start timer */
-               schStartTmr(&schCb[inst], (PTR)(schCb[inst].statistics.dlTotalPrbUsage), \
-                     EVENT_DL_TOTAL_PRB_USAGE_TMR, schCb[inst].statistics.dlTotalPrbUsage->periodicity);
+   return ROK;
+} /* End of SchProcStatsReq */
 
-               isDlTotlPrbUseCfgd = true;
-               break;
-            }
+/*******************************************************************
+ *
+ * @brief Fill and send statistics indication to MAC
+ *
+ * @details
+ *
+ *    Function :  SchSendStatsIndToMac
+ *
+ *    Functionality: Fill and send statistics indication to MAC
+ *
+ * @params[in]  SCH Instance
+ *              Measurement Type
+ *              Measurement Value
+ *              Size of value parameter
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchSendStatsIndToMac(Inst inst, SchStatsInd  *statsInd)
+{
+   Pst pst;
+   uint8_t ret = ROK;
 
-         case SCH_UL_TOTAL_PRB_USAGE:
-            {
-               /* Check if duplicate configuration */
-               if(schCb[inst].statistics.ulTotalPrbUsage)
-               {
-                  DU_LOG("\nERROR   -->  SCH : SCH_UL_TOTAL_PRB_USAGE stats already configured");
-                  rsp = RSP_NOK;
-                  cause = DUPLICATE_ENTRY;
-               }
+#ifdef DEBUG_PRINT
+   DU_LOG("\nDEBUG  --> SCH : Filling statistics indication");
+#endif
 
-               /* Allocate memory */
-               SCH_ALLOC(schCb[inst].statistics.ulTotalPrbUsage, sizeof(TotalPrbUsage));
-               if(!schCb[inst].statistics.ulTotalPrbUsage)
-               {
-                  DU_LOG("\nERROR   -->  SCH : Memory allocation failed for ulTotalPrbUsage in \
-                        SchProcStatsReq()");
-                  rsp = RSP_NOK;
-                  cause = RESOURCE_UNAVAILABLE;
-                  break;
-               }
+   /* Filling post structure */
+   memset(&pst, 0, sizeof(Pst));
+   FILL_PST_SCH_TO_MAC(pst, inst);
+   pst.event = EVENT_STATISTICS_IND_TO_MAC;
+
+   ret = MacMessageRouter(&pst, (void *)statsInd);
+   if(ret == RFAILED)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchSendStatsIndToMac(): Failed to send Statistics Indication");
+   }
+   return ret;
+}
+
+/**
+ * @brief Handler to process Timer expiry of DL Total PRB Usage calculation 
+ *
+ * @param[in] cb        Control block depending on the type of the timer event.
+ * @param[in] tmrEvnt   Timer event to be started
+ *
+ * @return  Bool indicating whether the timer is running or not
+ *      -# ROK
+ *      -# RFAILED
+*/
+double calcDlTotalPrbUsage(TotalPrbUsage *dlTotalPrbUsage)
+{
+   double percentageOfTotalPrbUsed = 0;
 
-               /* Initialize */
-               memset(schCb[inst].statistics.ulTotalPrbUsage, 0, sizeof(TotalPrbUsage));
+   if(dlTotalPrbUsage->totalPrbAvailForTx)
+      percentageOfTotalPrbUsed = ((100.0 * dlTotalPrbUsage->numPrbUsedForTx) / dlTotalPrbUsage->totalPrbAvailForTx);
+   
+   memset(dlTotalPrbUsage, 0, sizeof(TotalPrbUsage));
 
-               /* Configure */
-               schCb[inst].statistics.ulTotalPrbUsage->schInst = inst;
-               schCb[inst].statistics.ulTotalPrbUsage->periodicity = statsReq->statsList[idx].periodicity;
-               cmInitTimers(&(schCb[inst].statistics.ulTotalPrbUsage->periodTimer), 1);
+   return percentageOfTotalPrbUsed;
+}
 
-               /* Start timer */
-               schStartTmr(&schCb[inst], (PTR)(schCb[inst].statistics.ulTotalPrbUsage), \
-                     EVENT_UL_TOTAL_PRB_USAGE_TMR, schCb[inst].statistics.ulTotalPrbUsage->periodicity);
+/**
+ * @brief Handler to check if the timer is running
+ *
+ * @param[in] cb        Control block depending on the type of the timer event.
+ * @param[in] tmrEvnt   Timer event to be started
+ *
+ * @return  Bool indicating whether the timer is running or not
+ *      -# ROK
+ *      -# RFAILED
+*/
+uint8_t calcUlTotalPrbUsage(TotalPrbUsage *ulTotalPrbUsage)
+{
+   double percentageOfTotalPrbUsed = 0;
 
-               isUlTotlPrbUseCfgd = true;
-               break;
-            }
-         default:
-            {
-               DU_LOG("\nERROR   -->  SCH : Invalid statistics type [%d]", statsReq->statsList[idx].type);
-               rsp = RSP_NOK;
-               cause = PARAM_INVALID;
-            }
-      } /* End of switch */
+   if(ulTotalPrbUsage->totalPrbAvailForTx)
+      percentageOfTotalPrbUsed = ((100.0 * ulTotalPrbUsage->numPrbUsedForTx) / ulTotalPrbUsage->totalPrbAvailForTx);
 
-      if(rsp == RSP_NOK)
-      {
-         /* If failed to configure any KPI, then clear configuration of other
-          * KPIs that were configured successfully as part of this statsReq */
-         if(isDlTotlPrbUseCfgd)
-         {
-            if((schChkTmr((PTR)(schCb[inst].statistics.dlTotalPrbUsage), EVENT_DL_TOTAL_PRB_USAGE_TMR)) == FALSE)
-            {
-               schStopTmr(&schCb[inst], (PTR)(schCb[inst].statistics.dlTotalPrbUsage), EVENT_DL_TOTAL_PRB_USAGE_TMR);
-            }
-            SCH_FREE(schCb[inst].statistics.dlTotalPrbUsage, sizeof(TotalPrbUsage));
-         }
+   memset(ulTotalPrbUsage, 0, sizeof(TotalPrbUsage));
+
+   return percentageOfTotalPrbUsed;
+}
+
+/**
+ * @brief Calculates statistics in a group and sends
+ *          statistics indication for this group
+ *
+ * @param[in] Statistics group info
+ *
+ * @return
+ *      -# ROK
+ *      -# RFAILED
+*/
+uint8_t schCalcAndSendGrpStats(SchStatsGrp *grpInfo)
+{
+   uint8_t measStatsIdx = 0;
+   SchStatsInd  statsInd;
 
-         if(isUlTotlPrbUseCfgd)
+   memset(&statsInd, 0, sizeof(SchStatsInd));
+   statsInd.subscriptionId = grpInfo->subscriptionId;
+   statsInd.groupId = grpInfo->groupId;
+
+   if(grpInfo->kpiStats.dlTotalPrbUsage)
+   {
+      statsInd.measuredStatsList[measStatsIdx].type = SCH_DL_TOTAL_PRB_USAGE;  
+      statsInd.measuredStatsList[measStatsIdx].value = calcDlTotalPrbUsage(grpInfo->kpiStats.dlTotalPrbUsage);   
+      measStatsIdx++;
+   }
+   
+   if(grpInfo->kpiStats.ulTotalPrbUsage)
+   {
+      statsInd.measuredStatsList[measStatsIdx].type = SCH_UL_TOTAL_PRB_USAGE;  
+      statsInd.measuredStatsList[measStatsIdx].value = calcUlTotalPrbUsage(grpInfo->kpiStats.ulTotalPrbUsage);   
+      measStatsIdx++;
+   }
+   
+   statsInd.numStats = measStatsIdx;
+
+   return SchSendStatsIndToMac(grpInfo->schInst, &statsInd);
+}
+
+/*******************************************************************
+ *
+ * @brief Fill and send Statistics Delete Response to MAC
+ *
+ * @details
+ *
+ *    Function :  SchSendStatsDeleteRspToMac
+ *
+ *    Functionality: Fill and send Statistics Delete Response to MAC
+ *
+ * @params[in]  
+ *       Statistics Delete Request from MAC
+ *       Statistics Delete result
+ *       Cause of response
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchSendStatsDeleteRspToMac(SchStatsDeleteReq *statsDeleteReq, SchMacRsp rsp, CauseOfResult cause)
+{
+   Pst rspPst;
+   uint8_t ret = ROK;
+   SchStatsDeleteRsp  *schStatsDeleteRsp;
+
+   DU_LOG("\nINFO   --> SCH : Filling Statistics Delete Response");
+   SCH_ALLOC(schStatsDeleteRsp, sizeof(SchStatsDeleteRsp));
+   if(schStatsDeleteRsp == NULLP)
+   {
+      DU_LOG("\nERROR  --> SCH : Failed to allocate memory in SchSendStatsDeleteRspToMac()");
+      return RFAILED;
+   }
+   
+   schStatsDeleteRsp->subscriptionId=statsDeleteReq->subscriptionId;
+   schStatsDeleteRsp->rsp=rsp;
+   schStatsDeleteRsp->cause=cause;
+   /* Filling response post */
+   memset(&rspPst, 0, sizeof(Pst));
+   FILL_PST_SCH_TO_MAC(rspPst, inst);
+   rspPst.event = EVENT_STATISTICS_DELETE_RSP_TO_MAC;
+
+   ret = MacMessageRouter(&rspPst, (void *)schStatsDeleteRsp);
+   if(ret == RFAILED)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchSendStatsDeleteRspToMac(): Failed to send Statistics Response");
+      return ret;
+   }
+   return ret;
+}
+
+/*******************************************************************
+ *
+ * @brief Delete statistics information 
+ *
+ * @details
+ *
+ *    Function : deleteStatsInfo 
+ *
+ *    Functionality:
+ *    Delete statistics information
+ *
+ * @params[in] 
+ *             Instance
+ *             Subscription id 
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t deleteStatsInfo(Inst inst, uint64_t subscriptionId)
+{
+   bool statsFound=false;
+   uint8_t idx=0, statsGrpIdx=0;
+   SchStatsGrp *statsGrpInfo=NULLP;
+
+   if(schCb[inst].statistics.numOfStatsCfgd)
+   {
+      for(idx=0;idx<schCb[inst].statistics.numOfStatsCfgd; idx++)
+      {
+         for(statsGrpIdx=0;statsGrpIdx<schCb[inst].statistics.statsInfoList[idx].numStatsGroup; statsGrpIdx++)
          {
-            if((schChkTmr((PTR)(schCb[inst].statistics.ulTotalPrbUsage), EVENT_UL_TOTAL_PRB_USAGE_TMR)) == FALSE)
+            statsGrpInfo = &schCb[inst].statistics.statsInfoList[idx].statsGrpList[statsGrpIdx];
+            if(statsGrpInfo->subscriptionId ==subscriptionId)
             {
-               schStopTmr(&schCb[inst], (PTR)(schCb[inst].statistics.ulTotalPrbUsage), EVENT_UL_TOTAL_PRB_USAGE_TMR);
+               SCH_FREE(statsGrpInfo->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
+               SCH_FREE(statsGrpInfo->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
+               if(schChkTmr((PTR)statsGrpInfo, EVENT_STATISTICS_TMR) == true)
+               {
+                  schStopTmr(&schCb[inst], (PTR)statsGrpInfo, EVENT_STATISTICS_TMR);
+               }
+               memset(statsGrpInfo, 0, sizeof(SchStatsGrp));
+               statsFound = true;
             }
-            SCH_FREE(schCb[inst].statistics.ulTotalPrbUsage, sizeof(TotalPrbUsage));
          }
-         break;
       }
-   } /* End of FOR */
+   }
 
-   SCH_FREE(statsReq, sizeof(SchStatsReq));
+   if(statsFound ==false)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchProcStatsDeleteReq(): Statistics information is not present");
+      return RFAILED;
+   }
+   return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Processes Statistics Delete Request from MAC
+ *
+ * @details
+ *
+ *    Function : SchProcStatsDeleteReq
+ *
+ *    Functionality:
+ *     This function process the statistics delete request from MAC:
+ *
+ * @params[in] Post structure
+ *             Statistics Delete Request from MAC
+ * @return ROK     - success
+ *         RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchProcStatsDeleteReq(Pst *pst, SchStatsDeleteReq *statsDeleteReq)
+{
+   uint8_t ret =ROK;
+   Inst    inst = pst->dstInst - SCH_INST_START;
 
-   /* TODO : in next gerrit */
-   //SchSendStatsRspToMac(inst, rsp, cause);
+   DU_LOG("\nINFO   -->  SCH : Received Statistics Delete Request from MAC");
 
-   return ROK;
-} /* End of SchProcStatsReq */
+   if(statsDeleteReq == NULLP)
+   {
+      DU_LOG("\nERROR  -->  SCH : SchProcStatsDeleteReq(): Received Null pointer");
+      return RFAILED;
+   }
+
+   ret = deleteStatsInfo(inst, statsDeleteReq->subscriptionId);
+   if(ret == ROK)
+   {
+      SchSendStatsDeleteRspToMac(statsDeleteReq, RSP_OK, SUCCESSFUL);
+   }
+   else
+   {
+      SchSendStatsDeleteRspToMac(statsDeleteReq, RSP_NOK, STATS_ID_NOT_FOUND);
+   }
+   SCH_FREE(statsDeleteReq, sizeof(SchStatsDeleteReq));
+
+   return ret;
+} /* End of SchProcStatsDeleteReq */
 
 /**********************************************************************
   End of file