1 /*******************************************************************************
2 ################################################################################
3 # Copyright (c) [2017-2019] [Radisys] #
5 # Licensed under the Apache License, Version 2.0 (the "License"); #
6 # you may not use this file except in compliance with the License. #
7 # You may obtain a copy of the License at #
9 # http://www.apache.org/licenses/LICENSE-2.0 #
11 # Unless required by applicable law or agreed to in writing, software #
12 # distributed under the License is distributed on an "AS IS" BASIS, #
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
14 # See the License for the specific language governing permissions and #
15 # limitations under the License. #
16 ################################################################################
17 *******************************************************************************/
19 /********************************************************************20**
21 Name: LTE-RLC Layer - Lower Interface Functions
25 Desc: Source code for RLC Lower Interface Module.
26 This file contains following functions
37 **********************************************************************/
38 static const char* RLOG_MODULE_NAME="LIM";
39 static int RLOG_MODULE_ID=2048;
40 static int RLOG_FILE_ID=196;
44 * @brief RLC Lower Interface module
47 #define KW_MODULE KW_DBGMASK_INF
50 /* header (.h) include files */
51 #include "common_def.h"
52 #include "lkw.h" /* LKW defines */
53 #include "ckw.h" /* CKW defines */
54 #include "kwu.h" /* KWU defines */
55 #include "rgu.h" /* RGU defines */
57 #include "kw_env.h" /* RLC environment options */
59 #include "kw.h" /* RLC defines */
64 /* extern (.x) include files */
65 #include "lkw.x" /* LKW */
66 #include "ckw.x" /* CKW */
67 #include "kwu.x" /* KWU */
68 #include "rgu.x" /* RGU */
77 #endif /* __cplusplus */
80 /*****************************************************************************
82 ****************************************************************************/
84 * @brief Handler for bind confirmation from MAC.
87 * This function handles the bind confirmation received from MAC. If the
88 * bind was successful changes the state of the SAP to KW_SAP_BND
89 * else KW_SAP_CFG. Sends an alarm to LM in any case
91 * @param[in] pst Post structure
92 * @param[in] suId Service User ID
93 * @param[in] status Status whether the bind was successful or not
101 PUBLIC S16 KwLiRguBndCfm
108 PUBLIC S16 KwLiRguBndCfm (pst, suId, status)
114 U16 event; /* Event */
115 U16 cause; /* Cause */
116 KwRguSapCb *rguSap; /* RGU SAP Control Block */
121 #if (ERRCLASS & ERRCLS_INT_PAR)
122 if (pst->dstInst >= KW_MAX_RLC_INSTANCES)
127 tKwCb = KW_GET_KWCB(pst->dstInst);
129 RLOG2(L_DEBUG,"KwLiRguBndCfm(suId(%d), status(%d)", suId, status);
131 #if (ERRCLASS & ERRCLS_INT_PAR)
132 if (tKwCb->init.cfgDone != TRUE)
134 RLOG0(L_FATAL,"General configuration not done");
136 KW_SEND_SAPID_ALARM(tKwCb,suId,LKW_EVENT_LI_BND_CFM, LCM_CAUSE_INV_STATE);
141 if ((suId >= tKwCb->genCfg.maxRguSaps) || (suId < 0))
143 RLOG0(L_ERROR, "Invalid suId");
145 KW_SEND_SAPID_ALARM(tKwCb,suId, LKW_EVENT_LI_BND_CFM, LCM_CAUSE_INV_SUID);
149 #endif /* ERRCLASS & ERRCLS_INT_PAR */
151 rguSap = (tKwCb->genCfg.rlcMode == LKW_RLC_MODE_DL) ?
152 &(tKwCb->u.dlCb->rguDlSap[suId]) : &(tKwCb->u.ulCb->rguUlSap[suId]);
154 RLOG1(L_DEBUG, "KwLiRguBndCfm: For RGU SAP state=%d", rguSap->state)
156 switch (rguSap->state)
160 kwStopTmr (tKwCb,(PTR)rguSap, KW_EVT_WAIT_BNDCFM);
162 rguSap->retryCnt = 0;
164 if (status == CM_BND_OK)
166 rguSap->state = KW_SAP_BND;
167 event = LCM_EVENT_BND_OK;
168 cause = LKW_CAUSE_SAP_BNDENB;
172 rguSap->state = KW_SAP_CFG;
173 event = LCM_EVENT_BND_FAIL;
174 cause = LKW_CAUSE_UNKNOWN;
180 event = LKW_EVENT_RGU_BND_CFM;
181 cause = LCM_CAUSE_INV_STATE;
185 /* Send an alarm with proper event and cause */
186 KW_SEND_SAPID_ALARM(tKwCb, suId, event, cause);
189 } /* KwLiRguBndCfm */
192 * @brief Handler to process PDU received from MAC
195 * This function receives the PDU from MAC.
196 * seggregates common and dedicated logical channel
197 * PDU and call respective handler.
199 * @param[in] pst Post structure
200 * @param[in] suId Service User ID
201 * @param[in] datInd Data Indication Information
209 PUBLIC S16 RlcMacProcUlData(Pst *pst, SuId suId, RlcMacData *ulData)
212 U8 lcId; /* Logical Channel */
213 U8 numDLch = 0; /* Number of dedicated logical channel */
214 Bool dLchPduPres; /* PDU received on dedicated logical channel */
215 RguLchDatInd dLchData[RGU_MAX_LC]; /* PDU info on dedicated logical channel */
216 RguDDatIndInfo *dLchUlDat; /* UL data on dedicated logical channel */
217 RguCDatIndInfo *cLchUlDat; /* UL data on common logical channel */
219 /* Initializing dedicated logical channel Database */
220 for(idx = 0; idx < RGU_MAX_LC; idx++)
222 dLchData[idx].lcId = idx;
223 dLchData[idx].pdu.numPdu = 0;
228 /* Seggregate PDUs received on common and dedicated channels
229 * and call common channel's handler */
230 for(idx = 0; idx< ulData->nmbPdu; idx++)
232 if(ulData->pduInfo[idx].commCh)
234 KW_SHRABL_STATIC_BUF_ALLOC(pst->region, pst->pool, cLchUlDat, sizeof(RguCDatIndInfo));
235 cmMemset((U8*)cLchUlDat, (U8)0, sizeof(RguCDatIndInfo));
237 cLchUlDat->cellId = ulData->cellId;
238 cLchUlDat->rnti = ulData->rnti;
239 cLchUlDat->lcId = ulData->pduInfo[idx].lcId;
240 cLchUlDat->pdu = ulData->pduInfo[idx].pduBuf;
242 KwLiRguCDatInd(pst, suId, cLchUlDat);
248 KW_SHRABL_STATIC_BUF_ALLOC(pst->region, pst->pool, dLchUlDat, sizeof(RguDDatIndInfo));
252 lcId = ulData->pduInfo[idx].lcId;
253 dLchData[lcId].pdu.mBuf[dLchData[lcId].pdu.numPdu] = ulData->pduInfo[idx].pduBuf;
254 dLchData[lcId].pdu.numPdu++;
258 /* If any PDU received on dedicated logical channel, copy into RguDDatIndInfo
259 * and call its handler */
262 dLchUlDat->cellId = ulData->cellId;
263 dLchUlDat->rnti = ulData->rnti;
265 for(idx = 0; idx < RGU_MAX_LC; idx++)
267 if(dLchData[idx].pdu.numPdu)
269 cmMemcpy((U8 *)&dLchUlDat->lchData[numDLch], (U8 *)&dLchData[idx], sizeof(RguLchDatInd));
273 dLchUlDat->numLch = numDLch;
274 KwLiRguDDatInd(pst, suId, dLchUlDat);
278 KW_FREE_SHRABL_BUF(pst->region, pst->pool, ulData, sizeof(RlcMacData));
281 }/* End of RlcMacProcUlData */
283 PUBLIC int rlcDDatIndRcvd;
284 PUBLIC int rlcCDatIndRcvd;
286 * @brief Handler to process PDU received from MAC for common logical channels.
289 * This function receives the PDU from MAC for common logical channels
290 * does checks before handing over the PDU to the TM module
292 * @param[in] pst Post structure
293 * @param[in] suId Service User ID
294 * @param[in] datInd Data Indication Information
302 PUBLIC S16 KwLiRguCDatInd
306 RguCDatIndInfo *datInd
309 PUBLIC S16 KwLiRguCDatInd(pst,suId,datInd)
312 RguCDatIndInfo *datInd;
321 #if (ERRCLASS & ERRCLS_INT_PAR)
322 if (pst->dstInst >= KW_MAX_RLC_INSTANCES)
324 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, datInd, sizeof(RguCDatIndInfo));
329 tKwCb = KW_GET_KWCB(pst->dstInst);
332 #if (ERRCLASS & ERRCLS_DEBUG)
333 if (tKwCb->genCfg.rlcMode == LKW_RLC_MODE_DL)
335 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, datInd, sizeof(RguCDatIndInfo));
340 /* kw006.201 ccpu00120058, Added array boundary condition check */
341 #if (ERRCLASS & ERRCLS_DEBUG)
342 if(KW_MAX_LCH_PER_CELL <= datInd->lcId)
344 RLOG_ARG1(L_ERROR,DBG_LCID,datInd->lcId, "Invalid LcId, Max is [%d]",
345 KW_MAX_LCH_PER_CELL);
346 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, datInd, sizeof(RguCDatIndInfo));
349 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
351 /* Fetch RbCb from lcId */
352 kwDbmFetchUlRbCbFromLchId(tKwCb, 0, datInd->cellId, datInd->lcId, &rbCb);
355 RLOG_ARG1(L_ERROR, DBG_CELLID,datInd->cellId, "LcId [%d] not found",
357 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, datInd, sizeof(RguCDatIndInfo));
361 /* Dispatch to TM Module */
363 kwTmmRcvFrmLi(tKwCb, rbCb, datInd->rnti, datInd->pdu);
365 kwTmmRcvFrmLi(tKwCb, rbCb, datInd->pdu);
366 #endif /* CCPU_OPT */
368 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, datInd, sizeof(RguCDatIndInfo));
371 } /* KwLiRguCDatInd */
374 * @brief Handler to process PDU received from MAC for
375 * dedicated logical channels.
378 * This function receives the PDU from MAC for one or more dedicated
379 * logical channels and passes it to the UTL module for further processing
381 * @param[in] pst Post structure
382 * @param[in] suId Service User ID
383 * @param[in] datInd Data Indication Information
392 PUBLIC S16 KwLiRguDDatInd
396 RguDDatIndInfo *datInd
399 PUBLIC S16 KwLiRguDDatInd(pst, suId, datInd)
402 RguDDatIndInfo *datInd;
408 #if (ERRCLASS & ERRCLS_INT_PAR)
409 if (pst->dstInst >= KW_MAX_RLC_INSTANCES)
411 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, datInd, sizeof(RguDDatIndInfo));
416 #if (ERRCLASS & ERRCLS_DEBUG)
417 if (((KwCb*)KW_GET_KWCB(pst->dstInst))->genCfg.rlcMode == LKW_RLC_MODE_DL)
419 RLOG1(L_DEBUG,"KwLiRguDDatInd(pst, suId(%d))recieved in DL Inst",suId);
420 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, datInd, sizeof(RguDDatIndInfo));
424 kwUtlRcvFrmLi(KW_GET_KWCB(pst->dstInst),datInd);
426 #ifdef SS_LOCKLESS_MEMORY
427 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, datInd, sizeof(RguDDatIndInfo));
429 KW_PST_FREE(pst->region, pst->pool, datInd, sizeof(RguDDatIndInfo));
434 } /* KwLiRguDDatInd */
437 /*******************************************************************
439 * @brief Handler for extracting common and dedicated channel
440 * Scheduling result report.
444 * Function : RlcMacProcSchedRep
447 * Handler for extracting common and dedicated channel
448 * Scheduling result report
451 * @return ROK - success
454 * ****************************************************************/
455 PUBLIC uint16_t RlcMacProcSchedRep(Pst *pst, SuId suId, RlcMacSchedRepInfo *schRep)
457 U8 idx; /* Iterator */
458 U8 nmbDLch = 0; /* Number of dedicated logical channles */
459 RguCStaIndInfo *cLchSchInfo; /* Common logical channel scheduling result */
460 RguDStaIndInfo *dLchSchInfo; /* Dedicated logical channel scheduling result */
462 DU_LOG("\nRLC : Received scheduling report from MAC");
464 for(idx=0; idx < schRep->nmbLch; idx++)
466 /* If it is common channel, fill status indication information
467 * and trigger the handler for each common lch separately */
468 if(schRep->lchSta[idx].commCh)
470 KW_SHRABL_STATIC_BUF_ALLOC(pst->region, pst->pool, cLchSchInfo, sizeof(RguCStaIndInfo));
471 cmMemset((U8*)cLchSchInfo, (U8)0, sizeof(RguCStaIndInfo));
473 cLchSchInfo->cellId = schRep->cellId;
474 cLchSchInfo->lcId = schRep->lchSta[idx].lchStaInd.lcId;
475 //cLchSchInfo->transId = schRep->timeToTx; /* TODO : fill transId suing timeToTx */
476 cLchSchInfo->rnti = schRep->rnti;
478 KwLiRguCStaInd(pst, suId, cLchSchInfo);
483 /* Fill status info structure if at least one dedicated channel
484 * scheduling report is received */
487 KW_SHRABL_STATIC_BUF_ALLOC(pst->region, pst->pool, dLchSchInfo, sizeof(RguDStaIndInfo));
489 dLchSchInfo->cellId = schRep->cellId;
490 dLchSchInfo->nmbOfUeGrantPerTti = 1;
491 dLchSchInfo->staInd[0].rnti = schRep->rnti;
492 //dLchSchInfo->staInd[0].transId = schRep->timeToTx; /* TODO : fill transId suing timeToTx */
493 dLchSchInfo->staInd[0].nmbOfTbs = 1;
494 //dLchSchInfo->staInd[0].fillCrlPdu = /* TODO : Check the value needed to be filled */
497 /* Fill logical channel scheduling info */
498 cmMemcpy((U8 *)&dLchSchInfo->staInd[0].staIndTb[0].lchStaInd[nmbDLch], (U8 *)&schRep->lchSta[idx].lchStaInd, sizeof(RguLchStaInd));
505 /* Calling handler for all dedicated channels scheduling*/
508 dLchSchInfo->staInd[0].staIndTb[0].nmbLch = nmbDLch;
509 KwLiRguDStaInd(pst, suId, dLchSchInfo);
512 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, schRep, sizeof(RlcMacSchedRepInfo));
518 * @brief Handler for trigerring the data transfer from RLC to MAC
519 * for common logical channels.
522 * This function receives the size of the PDU to be transmitted
523 * and acts as a trigger for forming PDU and sending it to MAC.
525 * @param[in] pst Post structure
526 * @param[in] suId Service User ID
527 * @param[in] staInd Status Indication Information for Common Logical
536 PUBLIC S16 KwLiRguCStaInd
540 RguCStaIndInfo *staInd
543 PUBLIC S16 KwLiRguCStaInd(pst,suId,staInd)
546 RguCStaIndInfo *staInd;
554 #if (ERRCLASS & ERRCLS_INT_PAR)
555 if (pst->dstInst >= KW_MAX_RLC_INSTANCES)
557 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, staInd, sizeof(RguCStaIndInfo));
562 tKwCb = KW_GET_KWCB(pst->dstInst);
565 #if (ERRCLASS & ERRCLS_INT_PAR)
566 if ((suId >= tKwCb->genCfg.maxRguSaps) || (suId < 0))
572 "KwLiRguCStaInd: Invalid RGU suId\n");
575 if (tKwCb->genCfg.rlcMode == LKW_RLC_MODE_UL)
577 RLOG_ARG1(L_ERROR,DBG_LCID,staInd->lcId,
578 "Received in RLC UL CELLID:%d",
580 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, staInd, sizeof(RguCStaIndInfo));
587 /* kw006.201 ccpu00120058, added boundary condition check */
588 #if (ERRCLASS & ERRCLS_DEBUG)
589 if(KW_MAX_LCH_PER_CELL < staInd->lcId)
591 RLOG_ARG2(L_ERROR,DBG_LCID,staInd->lcId,
592 "Invalid LcId, Max is [%d] CELLID:%d",
595 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, staInd, sizeof(RguCStaIndInfo));
598 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
599 /* Fertch RbCb from lcId */
600 kwDbmFetchDlRbCbFromLchId(tKwCb,0, staInd->cellId, staInd->lcId, &rbCb);
603 RLOG_ARG1(L_ERROR, DBG_CELLID,staInd->cellId,
604 "LcId [%d] not found CELLID:%d",
606 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, staInd, sizeof(RguCStaIndInfo));
610 /* Dispatch to TM Module */
611 rbCb->transId = staInd->transId;
613 /* If trace flag is enabled send the trace indication */
614 if(tKwCb->init.trc == TRUE)
616 /* Populate the trace params */
617 kwLmmSendTrc(tKwCb,EVTRGUCSTAIND, NULLP);
619 kwTmmSndToLi(tKwCb, suId, rbCb, staInd);
621 #ifdef SS_LOCKLESS_MEMORY
622 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, staInd, sizeof(RguCStaIndInfo));
624 KW_PST_FREE(pst->region, pst->pool, staInd, sizeof(RguCStaIndInfo));
627 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, staInd, sizeof(RguCStaIndInfo));
630 } /* KwLiRguCStaInd */
633 * @brief Handler for trigerring the data transfer from RLC to MAC
634 * for dedicated logical channels.
637 * This function receives the size of the PDUs to be transmitted to
638 * MAC via one or more dedicated logical channels and acts as a trigger
639 * for forming PDUs and sending them to MAC.
641 * @param[in] pst Post structure
642 * @param[in] suId Service User ID
643 * @param[in] staInd Status Indication Information for Dedicated Logical
652 PUBLIC S16 KwLiRguDStaInd
656 RguDStaIndInfo *staInd
659 PUBLIC S16 KwLiRguDStaInd(pst, suId, staInd)
662 RguDStaIndInfo *staInd;
668 #if (ERRCLASS & ERRCLS_INT_PAR)
669 if (pst->dstInst >= KW_MAX_RLC_INSTANCES)
671 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, staInd, sizeof(RguDStaIndInfo));
676 gCb = KW_GET_KWCB(pst->dstInst);
678 #if (ERRCLASS & ERRCLS_INT_PAR)
679 if (((KwCb*)KW_GET_KWCB(pst->dstInst))->genCfg.rlcMode == LKW_RLC_MODE_UL)
681 RLOG_ARG0(L_ERROR,DBG_CELLID,staInd->cellId,"Received in RLC UL ");
682 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, staInd, sizeof(RguDStaIndInfo));
685 if ((suId >= gCb->genCfg.maxRguSaps) || (suId < 0))
691 "KwLiRguDStaInd: Invalid RGU suId\n");
695 kwUtlSndToLi(gCb, suId, staInd);
697 /* kw002.201 :Freeing from proper region */
698 KW_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, staInd, sizeof(RguDStaIndInfo));
700 } /* KwLiRguDStaInd */
703 * @brief Handler for handling the flow cntrl Ind from MAC
707 * This function receives the flow control indication from
708 * MAC and calls kwUtlTrigPdbFlowCntrl
710 * @param[in] pst Post structure
711 * @param[in] suId Service User ID
712 * @param[in] flowCntrlInd flow control Indication Information
721 PUBLIC S16 KwLiRguFlowCntrlInd
725 RguFlowCntrlInd *flowCntrlInd
728 PUBLIC S16 KwLiRguFlowCntrlInd(pst, suId, flowCntrlInd)
731 RguFlowCntrlInd *flowCntrlInd;
735 KwDlRbCb *rbCb = NULLP;
739 tKwCb = KW_GET_KWCB(pst->dstInst);
740 for (idx = 0; idx < flowCntrlInd->numUes; idx++)
742 for (lcIdx = 0; lcIdx < flowCntrlInd->ueFlowCntrlInfo[idx].numLcs; lcIdx++)
744 RguLcFlowCntrlInfo *lcInfo = &(flowCntrlInd->ueFlowCntrlInfo[idx].lcInfo[lcIdx]);
745 kwDbmFetchDlRbCbFromLchId(tKwCb, flowCntrlInd->ueFlowCntrlInfo[idx].ueId, flowCntrlInd->cellId, lcInfo->lcId, &rbCb);
749 if (lcInfo->pktAdmitCnt == 0) /* Special case */
751 kwUtlTrigPdbFlowCntrl(tKwCb, rbCb, lcInfo->pktAdmitCnt);
754 if (rbCb->mode == CM_LTE_MODE_AM)
756 if ((rbCb->m.amDl.retxLst.count != 0) ||
757 ((rbCb->m.amDl.bo == 0) ||
758 (rbCb->m.amDl.bo < lcInfo->maxBo4FlowCtrl)))
765 if ((rbCb->m.umDl.bo == 0) ||
766 (rbCb->m.umDl.bo < lcInfo->maxBo4FlowCtrl))
771 kwUtlTrigPdbFlowCntrl(tKwCb, rbCb, lcInfo->pktAdmitCnt);
777 /* kw005.201 added support for L2 Measurement */
784 * Handler for indicating the Harq Status of the data sent.
788 * This function receives the harq status of the data sent to MAC.
789 * This information is used for two things.
790 * 1. Computing the UuLoss of UM
791 * 2. Computing the DL Delay for UM and AM.
793 * @param[in] pst - Post structure
794 * @param[in] suId - Service User ID
795 * @param[in] staInd - Harq Status Indication Information.
803 PUBLIC S16 KwLiRguHqStaInd
807 RguHarqStatusInd *staInd
810 PUBLIC S16 KwLiRguHqStaInd(pst,suId,staInd)
813 RguHarqStatusInd *staInd;
823 TRC3(KwLiRguHqStaInd)
825 tKwCb = KW_GET_KWCB(pst->dstInst);
826 ueKey.cellId = staInd->cellId;
827 ueKey.ueId = staInd->ueId;
829 ret = kwDbmFetchDlUeCb(tKwCb, ueKey.ueId, ueKey.cellId, &ueCb);
835 /*Call kwUtlProcHarqInd as many times as number of Tbs present*/
836 for ( tbIdx = 0; tbIdx < staInd->numTbs; tbIdx++)
838 kwUtlProcHarqInd(tKwCb, staInd, ueCb, tbIdx);
842 } /* KwLiRguHqStaInd */
843 #endif /* LTE_L2_MEAS */
847 #endif /* __cplusplus */
849 /********************************************************************30**
851 **********************************************************************/