Initial commit
[o-du/l2.git] / src / 5gnrrlc / kw_tmm_dl.c
diff --git a/src/5gnrrlc/kw_tmm_dl.c b/src/5gnrrlc/kw_tmm_dl.c
new file mode 100755 (executable)
index 0000000..730f365
--- /dev/null
@@ -0,0 +1,575 @@
+/*******************************************************************************
+################################################################################
+#   Copyright (c) [2017-2019] [Radisys]                                        #
+#                                                                              #
+#   Licensed under the Apache License, Version 2.0 (the "License");            #
+#   you may not use this file except in compliance with the License.           #
+#   You may obtain a copy of the License at                                    #
+#                                                                              #
+#       http://www.apache.org/licenses/LICENSE-2.0                             #
+#                                                                              #
+#   Unless required by applicable law or agreed to in writing, software        #
+#   distributed under the License is distributed on an "AS IS" BASIS,          #
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
+#   See the License for the specific language governing permissions and        #
+#   limitations under the License.                                             #
+################################################################################
+*******************************************************************************/
+
+/**********************************************************************
+
+     Name:     LTE-RLC Layer 
+  
+     Type:     C file
+  
+     Desc:     Source code for RLC Transparent mode assembly and
+               reassembly.This file contains following functions
+                
+                  --kwTmmQSdu
+                  --kwTmmSndToLi
+                  --kwTmmRcvFrmLi
+                  --kwTmmReEstablish 
+
+     File:     kw_tmm_dl.c
+
+**********************************************************************/
+static const char* RLOG_MODULE_NAME="TMM";
+static int RLOG_MODULE_ID=2048;
+static int RLOG_FILE_ID=200;
+/** 
+ * @file kw_tmm_dl.c
+ * @brief RLC Transparent Mode module
+*/
+\f
+/* header (.h) include files */
+#include "envopt.h"        /* environment options */
+#include "envdep.h"        /* environment dependent */
+#include "envind.h"        /* environment independent */
+
+#include "gen.h"           /* general */
+#include "ssi.h"           /* system services */
+#include "cm5.h"           /* common timer defines */
+#include "cm_tkns.h"       /* common tokens defines */
+#include "cm_mblk.h"       /* common memory allocation library defines */
+#include "cm_llist.h"      /* common link list  defines  */
+#include "cm_hash.h"       /* common hash list  defines */
+#include "cm_lte.h"        /* common LTE defines */
+#include "lkw.h"           /* LKW defines */
+#include "ckw.h"           /* CKW defines */
+#include "kwu.h"           /* KWU defines */
+#include "rgu.h"           /* RGU defines */
+#include "kw_env.h"        /* RLC environment options */
+
+#include "kw.h"            /* RLC defines */
+#include "kw_err.h"            /* RLC defines */
+#include "kw_udx.h"
+#include "kw_dl.h"
+
+/* extern (.x) include files */
+#include "gen.x"           /* general */
+#include "ssi.x"           /* system services */
+
+#include "cm5.x"           /* common timer library */
+#include "cm_tkns.x"       /* common tokens */
+#include "cm_mblk.x"       /* common memory allocation */
+#include "cm_llist.x"      /* common link list */
+#include "cm_hash.x"       /* common hash list */
+#include "cm_lte.x"        /* common LTE includes */
+#include "cm_lib.x"        /* common memory allocation library */
+#include "lkw.x"           /* LKW */
+#include "ckw.x"           /* CKW */
+#include "kwu.x"           /* KWU */
+#include "rgu.x"           /* RGU */
+
+#include "kw.x"
+#include "kw_udx.x"
+#include "kw_dl.x"
+
+#define KW_MODULE (KW_DBGMASK_TM | KW_DBGMASK_DL)
+
+PRIVATE Void kwTmmSndStaRsp ARGS((KwCb *gCb, KwDlRbCb *rbCb, 
+                                 MsgLen bo, KwuDatReqInfo *datReqInfo));
+extern U32 rgMacGT ;  
+/** @addtogroup tmmode */
+/*@{*/
+
+/**
+ * @brief 
+ *    Handler to queue the SDU in the SDU queue and update BO and report it to
+ *    the lower layer.
+ *
+ * @details 
+ *    This function is used to queue the received SDU in the SDU queue 
+ *    maintained in the radio bearer control block. After queuing the SDU, BO 
+ *    is updated and is reported to the lower layer. 
+ *            
+ *  @param[in] rbCb         RB control block. 
+ *  @param[in] datReqInfo   Data Request Information.
+ *  @param[in] mBuf         SDU Buffer.
+ *
+ *  @return  S16
+ *      -# ROK 
+ *      -# RFAILED 
+ */
+#ifdef ANSI
+PUBLIC Void kwTmmQSdu
+(
+KwCb            *gCb,
+KwDlRbCb        *rbCb,      
+KwuDatReqInfo   *datReqInfo, 
+Buffer          *mBuf       
+)
+#else
+PUBLIC Void kwTmmQSdu(gCb,rbCb,datReqInfo,mBuf)
+KwCb            *gCb;
+KwDlRbCb        *rbCb;       
+KwuDatReqInfo   *datReqInfo;  
+Buffer          *mBuf;         
+#endif
+{
+   KwSdu   *sdu;              
+   TRC2(kwTmmQSdu) 
+
+
+   KW_ALLOC(gCb,sdu,sizeof(KwSdu));
+#if (ERRCLASS & ERRCLS_ADD_RES)
+   if ( sdu == NULLP )
+   {
+      RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
+            "Memory Allocation failed UEID:%d CELLID:%d",   
+            rbCb->rlcId.ueId,
+            rbCb->rlcId.cellId);   
+      RETVOID;
+   }
+#endif /* ERRCLASS & ERRCLS_ADD_RES */
+#ifdef CCPU_OPT   
+   if ( rbCb->lch.lChType == CM_LTE_LCH_BCCH || 
+        rbCb->lch.lChType == CM_LTE_LCH_PCCH )
+   {
+      sdu->mode.tm.sfn = datReqInfo->tm.tmg.sfn;
+      sdu->mode.tm.subframe = datReqInfo->tm.tmg.subframe;
+#ifdef EMTC_ENABLE
+     if(rbCb->lch.lChType == CM_LTE_LCH_PCCH)
+     {
+        sdu->mode.tm.pnb = datReqInfo->pnb;
+     }
+#endif
+   }
+   else
+   {
+      sdu->mode.tm.rnti = datReqInfo->tm.rnti;
+   }
+#endif
+   sdu->arrTime = rgMacGT;
+   SFndLenMsg(mBuf,&sdu->sduSz); 
+   sdu->mBuf = mBuf;
+   
+   cmLListAdd2Tail(&(rbCb->m.tm.sduQ), &(sdu->lstEnt));  
+   sdu->lstEnt.node = (PTR)sdu; 
+
+   kwTmmSndStaRsp(gCb, rbCb, sdu->sduSz, datReqInfo); 
+   RETVOID;
+}
+
+/**
+* @brief 
+*    Handler to form a pdu and send it to the lower layer.
+* 
+* @details 
+*    This function forms one pdu from the first SDU in the SDU queue and sends 
+*    it to the lower layer.
+*             
+* @param[in] gCb     RLC Instance Control Block
+* @param[in] rbCb    RB control block. 
+* @param[in] staInd  Status Indication of common logical channel 
+*
+* @return  S16
+*    -# ROK 
+*    -# RFAILED         
+*/
+#ifdef ANSI
+PUBLIC Void kwTmmSndToLi
+(
+KwCb             *gCb,
+SuId             suId,
+KwDlRbCb         *rbCb,              
+RguCStaIndInfo   *staInd
+)
+#else
+PUBLIC Void kwTmmSndToLi(gCb, suId, rbCb, staInd)
+KwCb             *gCb;
+SuId             suId;
+KwDlRbCb         *rbCb;             
+RguCStaIndInfo   *staInd;
+#endif
+{
+   CmLList          *node;          /* Current Link List Node */
+   KwSdu            *sdu;           /* SDU */
+   RguCDatReqInfo   *cDatReqInfo;   /* Data Request Information */
+   S16   timeDiff = 0;
+   Ticks curTime  = 0;
+
+   TRC2(kwTmmSndToLi)
+
+
+   CM_LLIST_FIRST_NODE(&(rbCb->m.tm.sduQ), 
+                       node);
+
+   /* (Sfn,subframe) at which the message should be transmitted is 
+    * validated with alloted (sfn,subframe)in the MAC layer */
+   while (node != NULLP)
+   {
+      sdu = (KwSdu *)(node->node);
+      if ( rbCb->lch.lChType == CM_LTE_LCH_BCCH ||
+            rbCb->lch.lChType == CM_LTE_LCH_PCCH )
+      {
+         U16 sfn, subframe;
+         /* MS_FIX: syed sfn is of 10 bytes rather than 8 */
+#ifdef EMTC_ENABLE
+         /* As part of CATM feature cross subframe scheduling is implemented , so there is some delta(currently 2)
+            between MPDCCH and PDSCH,RLC expects cell crntTime of transmission of control dlsf, so one extra 
+            information is provided in staInd, so that sfn,subframe should calculate from paging Timing information 
+            in case of EMTC paging, instead of transId */
+         if(staInd->isEmtcPaging)
+         {
+            sfn      = staInd->pagingTimingInfo.sfn;
+            subframe = staInd->pagingTimingInfo.subframe;
+         }
+         else
+#endif
+         {
+            sfn = (staInd->transId >> 8) & 0x3FF;
+            subframe = staInd->transId & 0xFF;
+         }
+
+         /* Table
+          * tm.subframe - current subframe 
+          * 0,sfn        7,sfn-1
+          * 4,sfn        1,sfn
+          * 5,sfn        2,sfn
+          * 9,sfn        6,sfn
+          */
+         /* MS_FIX: syed Incorrect sfn determination. 
+          * Take care of SFN wraparound. TODO: It is better for RLC
+          * not to be aware of SCH DELTAs. So we should look for 
+          * sending actual transmission time to RLC. */
+         if ((subframe + TFU_DELTA) >= 10)
+         {
+            sfn = (sfn + 1)%1024;
+         }
+
+         if ((sdu->mode.tm.sfn != sfn) ||
+               (sdu->mode.tm.subframe != ((subframe+TFU_DELTA)%10)))
+         {
+            node = node->next;
+            RLOG_ARG4(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
+                  "Releasing SDU of RNTI = %d for RNTI = %d UEID:%d CELLID:%d",
+                  sdu->mode.tm.rnti, 
+                  staInd->rnti,
+                  rbCb->rlcId.ueId,
+                  rbCb->rlcId.cellId);   
+            RLOG_ARG4(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
+                  "sfn %d subframe %d  UEID:%d CELLID:%d",
+                  sfn, 
+                  subframe,
+                  rbCb->rlcId.ueId,
+                  rbCb->rlcId.cellId);   
+            cmLListDelFrm(&(rbCb->m.tm.sduQ), &sdu->lstEnt);
+            KW_FREE_BUF(sdu->mBuf);
+            KW_FREE(gCb, sdu, sizeof(KwSdu));
+         }
+         else
+         {
+            break;
+         }
+      }
+      else
+      {
+         curTime = rgMacGT;
+         if (curTime < sdu->arrTime)
+         {
+            timeDiff = (10240 - sdu->arrTime) + curTime;
+         }
+         else
+         {
+            timeDiff = curTime - sdu->arrTime;
+         }
+         RLOG_ARG4(L_DEBUG, DBG_RBID,rbCb->rlcId.rbId,
+               "TMM: TmSdu Sta Indication received for Rnti %d Sdu Rnti %d "
+               " UEID:%d CELLID:%d", 
+               staInd->rnti, 
+               sdu->mode.tm.rnti,
+               rbCb->rlcId.ueId,
+               rbCb->rlcId.cellId);   
+         RLOG_ARG4(L_DEBUG, DBG_RBID,rbCb->rlcId.rbId,
+               "TMM: TmSdu Sta Indication received : timeDiff %d SduQCnt %lu"
+               " UEID:%d CELLID:%d", 
+               timeDiff, 
+               rbCb->m.tm.sduQ.count,
+               rbCb->rlcId.ueId,
+               rbCb->rlcId.cellId);   
+         if (timeDiff > 40)
+         {
+            /* Memory leak needs to be fixed */
+            node = node->next;
+            RLOG_ARG3(L_DEBUG, DBG_RBID,rbCb->rlcId.rbId,
+                  " timeDiff greater than 40, so deleting the Sdu %u "
+                  " UEID:%d CELLID:%d", 
+                  sdu->mode.tm.rnti,
+                  rbCb->rlcId.ueId,
+                  rbCb->rlcId.cellId);   
+            cmLListDelFrm(&(rbCb->m.tm.sduQ), &sdu->lstEnt);
+            KW_FREE_BUF(sdu->mBuf);
+            KW_FREE(gCb, sdu, sizeof(KwSdu));
+            continue;
+         }
+
+         if (sdu->mode.tm.rnti != staInd->rnti)
+         {
+            /* Memory leak needs to be fixed */
+            node = node->next;
+            RLOG_ARG4(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId, 
+                  "TMM: Searching for Rnti %d Skipping Sdu for Rnti %d"
+                  " UEID:%d CELLID:%d", 
+                  staInd->rnti,
+                  sdu->mode.tm.rnti, 
+                  rbCb->rlcId.ueId,
+                  rbCb->rlcId.cellId);   
+            RLOG_ARG4(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId, 
+                  " timeDiff %d sdu->arrTime %d"
+                  " UEID:%d CELLID:%d", 
+                  timeDiff, 
+                  sdu->arrTime,
+                  rbCb->rlcId.ueId,
+                  rbCb->rlcId.cellId);   
+            RLOG_ARG4(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId, 
+                  "curTime %d SduQCnt %lu and continuing"
+                  " UEID:%d CELLID:%d", 
+                   curTime, 
+                   rbCb->m.tm.sduQ.count,
+                  rbCb->rlcId.ueId,
+                  rbCb->rlcId.cellId);   
+            continue;
+         }
+         else
+         {
+            RLOG_ARG3(L_DEBUG, DBG_RBID,rbCb->rlcId.rbId,
+                  "TMM: TmSdu found %u UEID:%d CELLID:%d",
+                  sdu->mode.tm.rnti,
+                  rbCb->rlcId.ueId,
+                  rbCb->rlcId.cellId);   
+            break;
+         }
+      }
+
+   }
+   if ( node == NULLP )
+   {
+      RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
+               "SDU not found TM Queue is empty UEID:%d CELLID:%d",
+               rbCb->rlcId.ueId,
+               rbCb->rlcId.cellId);   
+      RETVOID;
+   }
+   sdu = (KwSdu *)node->node;
+
+    KW_ALLOC_SHRABL_BUF(gCb->u.dlCb->rguDlSap[suId].pst.region,
+                        gCb->u.dlCb->rguDlSap[suId].pst.pool,
+                        cDatReqInfo,(Size)sizeof(RguCDatReqInfo));
+#if (ERRCLASS & ERRCLS_ADD_RES)
+   if ( cDatReqInfo == NULLP )
+   {
+      RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
+            "Memory Allocation failed UEID:%d CELLID:%d",   
+               rbCb->rlcId.ueId,
+               rbCb->rlcId.cellId);   
+      RETVOID; 
+   }
+#endif /* ERRCLASS & ERRCLS_ADD_RES */
+#ifdef CCPU_OPT
+   if ( rbCb->lch.lChType == CM_LTE_LCH_BCCH ||  
+        rbCb->lch.lChType == CM_LTE_LCH_PCCH )
+   {
+      cDatReqInfo->u.timeToTx.sfn = sdu->mode.tm.sfn;
+      cDatReqInfo->u.timeToTx.subframe = sdu->mode.tm.subframe;
+#ifdef EMTC_ENABLE
+       if(rbCb->lch.lChType == CM_LTE_LCH_PCCH)
+       {
+         cDatReqInfo->pnb = sdu->mode.tm.pnb; 
+       }
+#endif
+   }
+   else
+   {
+      cDatReqInfo->u.rnti = sdu->mode.tm.rnti;
+   }
+#endif 
+   cDatReqInfo->pdu = sdu->mBuf; 
+   cDatReqInfo->transId = rbCb->transId;
+   cDatReqInfo->cellId  = rbCb->rlcId.cellId;
+   cDatReqInfo->lcId   = rbCb->lch.lChId; 
+   cDatReqInfo->lcType = rbCb->lch.lChType; 
+
+   /* kw005.201 ccpu00117318, updating the statistics */
+   gCb->genSts.bytesSent += sdu->sduSz;
+   gCb->genSts.pdusSent++;
+
+   kwUtlIncrementKwuStsSduTx(gCb->u.dlCb->kwuDlSap + rbCb->kwuSapId);   
+
+   /* remove SDU from queue */ 
+   sdu->mBuf = NULLP;
+   cmLListDelFrm(&(rbCb->m.tm.sduQ),
+                 &sdu->lstEnt); 
+   KW_FREE(gCb,sdu, sizeof(KwSdu));
+
+   /* If trace flag is enabled send the trace indication */
+   if(gCb->init.trc == TRUE)
+   {
+      /* Populate the trace params */
+      kwLmmSendTrc(gCb,EVTRGUCDATREQ, NULLP);
+   }
+   KwLiRguCDatReq (&(gCb->u.dlCb->rguDlSap[suId].pst), 
+                   gCb->u.dlCb->rguDlSap[suId].spId, 
+                   cDatReqInfo);
+   
+   RETVOID;
+}
+
+/**
+ *
+ * @brief 
+ *    Handler to process the re-establishment request received from the upper 
+ *    layer. 
+ *
+ * @details
+ *    This function empties the SDU queue for the RB in the downlink.
+ *            
+ * @param[in] gCb   RLC Instance Control Block 
+ * @param[in] rbCb  RB control block. 
+ *
+ * @return  S16
+ *    -# ROK 
+ */
+#ifdef ANSI
+PUBLIC Void kwDlTmmReEstablish
+(
+KwCb       *gCb,
+KwDlRbCb   *rbCb    
+)
+#else
+PUBLIC Void kwDlTmmReEstablish(gCb,rbCb)
+KwCb       *gCb;
+KwDlRbCb   *rbCb;     
+#endif
+{
+   TRC2(kwDlTmmReEstablish)
+
+
+#ifdef LTE_L2_MEAS_RLC
+   kwUtlEmptySduQ(gCb, rbCb, &rbCb->m.tm.sduQ);
+#else
+   kwUtlEmptySduQ(gCb,&rbCb->m.tm.sduQ);
+#endif
+   
+   RETVOID;
+}
+/**
+ *
+ * @brief 
+ *    Handler to send Status Response to the lower layer.
+ *
+ * @details
+ *    This function is used to the BO to the lower layer after receiving a data
+ *    request from the upper layer. 
+ *            
+ * @param[in] gCb          RLC Instance Control Block 
+ * @param[in] rbCb         RB control block. 
+ * @param[in] bo           Buffer Occupancy 
+ * @param[in] datReqInfo   Data Request Information.
+ *
+ * @return  S16
+ *    -# ROK 
+ *    -# RFAILED 
+ */
+
+#ifdef ANSI
+PRIVATE Void kwTmmSndStaRsp
+(
+KwCb            *gCb,
+KwDlRbCb        *rbCb,                 
+MsgLen          bo,                    
+KwuDatReqInfo   *datReqInfo         
+)
+#else
+PRIVATE Void kwTmmSndStaRsp(rbCb,bo,datReqInfo)
+KwCb            *gCb;
+KwDlRbCb        *rbCb;               
+MsgLen          bo;                
+KwuDatReqInfo   *datReqInfo;   
+#endif
+{
+   RguCStaRspInfo   *staRspInfo;   /* Status Response Information */
+   KwRguSapCb       *rguSap;       /* SAP Information */
+
+   TRC3(kwTmmSndStaRsp)
+
+
+   rguSap = &(gCb->u.dlCb->rguDlSap[rbCb->rguSapId]);
+
+   KW_ALLOC_SHRABL_BUF(gCb->u.dlCb->rguDlSap[rbCb->rguSapId].pst.region,
+                       gCb->u.dlCb->rguDlSap[rbCb->rguSapId].pst.pool,
+                       staRspInfo,sizeof(RguCStaRspInfo));
+#if (ERRCLASS & ERRCLS_ADD_RES)
+   if ( staRspInfo == NULLP )
+   {
+      RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
+            "Memory Allocation failed UEID:%d CELLID:%d",
+            rbCb->rlcId.ueId,
+            rbCb->rlcId.cellId);   
+      RETVOID;
+   }
+#endif /* ERRCLASS & ERRCLS_ADD_RES */
+   staRspInfo->bo = bo;
+   staRspInfo->cellId = rbCb->rlcId.cellId;
+   staRspInfo->lcId   = rbCb->lch.lChId;
+   staRspInfo->lcType = rbCb->lch.lChType;
+#ifdef CCPU_OPT    
+   if ( rbCb->lch.lChType == CM_LTE_LCH_BCCH ||
+        rbCb->lch.lChType == CM_LTE_LCH_PCCH )
+   {
+      staRspInfo->u.timeToTx.sfn      = datReqInfo->tm.tmg.sfn;
+      staRspInfo->u.timeToTx.subframe = datReqInfo->tm.tmg.subframe;
+#ifdef EMTC_ENABLE
+      if(rbCb->lch.lChType == CM_LTE_LCH_PCCH)
+      {
+         staRspInfo->emtcDiReason = datReqInfo->emtcDiReason;
+         staRspInfo->pnb = datReqInfo->pnb;
+      }
+#endif
+   }
+   else if ( rbCb->lch.lChType == CM_LTE_LCH_CCCH )
+   {
+       staRspInfo->u.rnti = datReqInfo->tm.rnti;
+   }
+#endif
+
+   /* If trace flag is enabled send the trace indication */
+   if(gCb->init.trc == TRUE)
+   {
+      /* Populate the trace params */
+      kwLmmSendTrc(gCb,EVTRGUCSTARSP, NULLP);
+   }
+
+   KwLiRguCStaRsp(&rguSap->pst,rguSap->spId,staRspInfo);
+
+   RETVOID;
+} 
+
+#ifdef _cplusplus
+}
+#endif
+/*@}*/
+/********************************************************************30**
+         End of file
+**********************************************************************/