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: RLC - TMR module file
25 Desc: Source code for timer functions such as,
34 *********************************************************************21*/
36 /* header (.h) include files */
37 #include "common_def.h"
38 #include "lkw.h" /* LKW defines */
39 #include "ckw.h" /* CKW defines */
40 #include "kwu.h" /* KWU defines */
41 #include "rgu.h" /* RGU defines */
42 #include "rlc_env.h" /* RLC environment options */
43 #include "rlc_err.h" /* Error defines */
45 /* extern (.x) include files */
46 #include "lkw.x" /* LKW */
47 #include "ckw.x" /* CKW */
48 #include "kwu.x" /* KWU */
49 #include "rgu.x" /* RGU */
51 #include "du_app_rlc_inf.h"
52 #include "rlc_utils.h" /* RLC defines */
53 #include "rlc_dl_ul_inf.h"
60 * @brief RLC Timer Module
64 * @def RLC_TMR_CALCUATE_WAIT
66 * This macro calculates and assigns wait time based on the value of the
67 * timer and the timer resolution. Timer value of 0 signifies that the
68 * timer is not configured
70 * @param[out] _wait Time for which to arm the timer changed to proper
71 * value according to the resolution
72 * @param[in] _tmrVal Value of the timer
73 * @param[in] _timerRes Resolution of the timer
76 #define RLC_TMR_CALCUATE_WAIT(_wait, _tmrVal, _timerRes) \
78 (_wait) = ((_tmrVal) * SS_TICKS_SEC)/((_timerRes) * 1000); \
79 if((0 != (_tmrVal)) && (0 == (_wait))) \
85 /* private function declarations */
86 static Void rlcBndTmrExpiry(PTR cb);
89 * @brief Handler to start timer
91 * @param[in] gCb Pointer to the RLC instance control block
92 * @param[in] cb Control block depending on the type of the timer event.
93 * It can be uplink/downlink rbCb or rgu sap control block
94 * @param[in] tmrEvnt Timer event to be started
98 void rlcStartTmr(RlcCb *gCb, PTR cb, int16_t tmrEvnt)
100 /* kw005.201 added support for L2 Measurement */
102 RlcL2MeasEvtCb *measEvtCb = NULLP;
108 /* kw002.201 Adjusting the wait time as per timeRes configured by layer manager */
111 case EVENT_RLC_UMUL_REASSEMBLE_TMR:
113 RlcUmUl* umUl = &(((RlcUlRbCb *)cb)->m.umUl);
114 /* kw005.201 Changed wait calculation ccpu00117634*/
115 RLC_TMR_CALCUATE_WAIT(arg.wait, umUl->reAsmblTmrInt, gCb->genCfg.timeRes);
117 arg.timers = &umUl->reAsmblTmr;
118 arg.max = RLC_MAX_UM_TMR;
121 case EVENT_RLC_AMUL_REASSEMBLE_TMR:
123 RlcAmUl* amUl = &(((RlcUlRbCb *)cb)->m.amUl);
124 /* kw005.201 Changed wait calculation ccpu00117634*/
125 RLC_TMR_CALCUATE_WAIT(arg.wait, amUl->reAsmblTmrInt, gCb->genCfg.timeRes);
127 arg.timers = &amUl->reAsmblTmr;
128 arg.max = RLC_MAX_AM_TMR;
131 case EVENT_RLC_AMUL_STA_PROH_TMR:
133 RlcAmUl* amUl = &(((RlcUlRbCb *)cb)->m.amUl);
134 /* kw005.201 Changed wait calculation ccpu00117634*/
135 RLC_TMR_CALCUATE_WAIT(arg.wait,
137 gCb->genCfg.timeRes);
139 arg.timers = &amUl->staProhTmr;
140 arg.max = RLC_MAX_AM_TMR;
143 case EVENT_RLC_AMDL_POLL_RETX_TMR:
145 RlcAmDl* amDl = &(((RlcDlRbCb *)cb)->m.amDl);
146 /* kw005.201 Changed wait calculation ccpu00117634*/
147 RLC_TMR_CALCUATE_WAIT(arg.wait,
148 amDl->pollRetxTmrInt,
149 gCb->genCfg.timeRes);
151 arg.timers = &amDl->pollRetxTmr;
152 arg.max = RLC_MAX_AM_TMR;
155 case EVENT_RLC_WAIT_BNDCFM:
157 RlcRguSapCb* rguSap = (RlcRguSapCb *)cb;
158 /* kw005.201 Changed wait calculation ccpu00117634*/
159 RLC_TMR_CALCUATE_WAIT(arg.wait, rguSap->bndTmrInt, gCb->genCfg.timeRes);
161 arg.timers = &rguSap->bndTmr;
162 arg.max = RLC_MAX_RGUSAP_TMR;
165 /* kw005.201 added support for L2 Measurement */
167 case EVENT_RLC_L2_TMR:
169 measEvtCb = (RlcL2MeasEvtCb *)cb;
170 /* kw005.201 Changed wait calculation ccpu00117634*/
171 RLC_TMR_CALCUATE_WAIT(arg.wait,
172 measEvtCb->l2TmrCfg.val,
173 gCb->genCfg.timeRes);
175 arg.timers = &measEvtCb->l2Tmr;
176 arg.max = RLC_L2_MAX_TIMERS;
180 case EVENT_RLC_UE_THROUGHPUT_TMR:
182 RlcThpt *thptCb = (RlcThpt *)cb;
183 RLC_TMR_CALCUATE_WAIT(arg.wait, ODU_UE_THROUGHPUT_PRINT_TIME_INTERVAL, gCb->genCfg.timeRes);
184 arg.timers = &thptCb->ueTputInfo.ueThptTmr;
185 arg.max = RLC_MAX_THPT_TMR;
188 case EVENT_RLC_UE_DELETE_TMR:
190 RlcUlUeCb *ulUeCb = (RlcUlUeCb*)cb;
191 RLC_TMR_CALCUATE_WAIT(arg.wait, RLC_UE_DELETE_WAIT_TIME, gCb->genCfg.timeRes);
192 arg.timers = &ulUeCb->ueDeleteInfo.ueDelTmr;
193 arg.max = RLC_MAX_UE_TMR;
196 case EVENT_RLC_SNSSAI_THROUGHPUT_TMR:
198 RlcThpt *thptCb = (RlcThpt *)cb;
199 RLC_TMR_CALCUATE_WAIT(arg.wait, ODU_SNSSAI_THROUGHPUT_PRINT_TIME_INTERVAL, gCb->genCfg.timeRes);
200 arg.timers = &thptCb->snssaiTputInfo.snssaiThptTmr;
201 arg.max = RLC_MAX_THPT_TMR;
206 DU_LOG("\nERROR --> RLC : rlcStartTmr: Invalid tmr Evnt [%d]", tmrEvnt);
212 arg.tqCp = &gCb->rlcTqCp;
225 * @brief Handler to stop a timer
227 * @param[in] gCb Pointer to the RLC instance control block
228 * @param[in] cb Control block depending on the type of the timer event.
229 * It can be uplink/downlink rbCb or rgu sap control block
230 * @param[in] tmrType Timer event to be started
234 void rlcStopTmr(RlcCb *gCb, PTR cb, uint8_t tmrType)
237 /* kw005.201 added support for L2 Measurement */
239 RlcL2MeasEvtCb *measEvtCb = NULLP;
246 case EVENT_RLC_UMUL_REASSEMBLE_TMR:
248 arg.timers = &((RlcUlRbCb *)cb)->m.umUl.reAsmblTmr;
249 arg.max = RLC_MAX_UM_TMR;
252 case EVENT_RLC_AMUL_REASSEMBLE_TMR:
254 arg.timers = &((RlcUlRbCb *)cb)->m.amUl.reAsmblTmr;
255 arg.max = RLC_MAX_AM_TMR;
258 case EVENT_RLC_AMUL_STA_PROH_TMR:
260 arg.timers = &((RlcUlRbCb *)cb)->m.amUl.staProhTmr;
261 arg.max = RLC_MAX_AM_TMR;
264 case EVENT_RLC_AMDL_POLL_RETX_TMR:
266 arg.timers = &((RlcDlRbCb *)cb)->m.amDl.pollRetxTmr;
267 arg.max = RLC_MAX_AM_TMR;
270 case EVENT_RLC_WAIT_BNDCFM:
272 arg.timers = &((RlcRguSapCb *)cb)->bndTmr;
273 arg.max = RLC_MAX_RGUSAP_TMR;
276 /* kw005.201 added support for L2 Measurement */
278 case EVENT_RLC_L2_TMR:
280 measEvtCb = (RlcL2MeasEvtCb *)cb;
281 arg.timers = &measEvtCb->l2Tmr;
282 arg.max = RLC_L2_MAX_TIMERS;
286 case EVENT_RLC_UE_THROUGHPUT_TMR:
288 arg.timers = &((RlcThpt *)cb)->ueTputInfo.ueThptTmr;
289 arg.max = RLC_MAX_THPT_TMR;
292 case EVENT_RLC_UE_DELETE_TMR:
294 arg.timers = &((RlcUlUeCb*)cb)->ueDeleteInfo.ueDelTmr;
295 arg.max = EVENT_RLC_UE_DELETE_TMR;
298 case EVENT_RLC_SNSSAI_THROUGHPUT_TMR:
300 arg.timers = &((RlcThpt *)cb)->snssaiTputInfo.snssaiThptTmr;
301 arg.max = RLC_MAX_THPT_TMR;
306 DU_LOG("\nERROR --> RLC : rlcStopTmr: Invalid tmr Evnt[%d]", tmrType);
312 arg.tqCp = &gCb->rlcTqCp;
325 * @brief Handler to invoke events on expiry of timer.
328 * This function is used to handle expiry of timer,it invokes relevant
331 * @param[in] cb Control block depending on the type of the timer event.
332 * It can be uplink/downlink rbCb or rgu sap control block
333 * @param[in] tmrEvnt Timer event to be started
337 Void rlcTmrExpiry(PTR cb,S16 tmrEvnt)
339 /* kw005.201 added support for L2 Measurement */
343 case EVENT_RLC_UMUL_REASSEMBLE_TMR:
345 RlcUlRbCb *ulRbCb = (RlcUlRbCb *)cb;
346 rlcUmmReAsmblTmrExp(RLC_GET_RLCCB(ulRbCb->inst), ulRbCb);
350 case EVENT_RLC_AMUL_REASSEMBLE_TMR:
352 RlcUlRbCb *ulRbCb = (RlcUlRbCb *)cb;
353 rlcAmmReAsmblTmrExp(RLC_GET_RLCCB(ulRbCb->inst), ulRbCb);
356 case EVENT_RLC_AMUL_STA_PROH_TMR:
358 RlcUlRbCb *ulRbCb = (RlcUlRbCb *)cb;
359 rlcAmmStaProTmrExp(RLC_GET_RLCCB(ulRbCb->inst), ulRbCb);
363 case EVENT_RLC_AMDL_POLL_RETX_TMR:
365 RlcDlRbCb *dlRbCb = (RlcDlRbCb *)cb;
366 RlcCb *gCb = RLC_GET_RLCCB(dlRbCb->inst);
368 rlcAmmPollRetxTmrExp(gCb, dlRbCb);
370 gCb->genSts.protTimeOut++;
373 case EVENT_RLC_WAIT_BNDCFM:
378 case EVENT_RLC_UE_THROUGHPUT_TMR:
380 rlcUeThptTmrExpiry(cb);
383 case EVENT_RLC_UE_DELETE_TMR:
385 rlcUeDeleteTmrExpiry(cb);
388 case EVENT_RLC_SNSSAI_THROUGHPUT_TMR:
390 rlcSnssaiThptTmrExpiry(cb);
403 * @brief Handler to check if the timer is running
405 * @param[in] gCb Pointer to the RLC instance control block
406 * @param[in] cb Control block depending on the type of the timer event.
407 * It can be uplink/downlink rbCb or rgu sap control block
408 * @param[in] tmrEvnt Timer event to be started
410 * @return Bool indicating whether the timer is running or not
414 bool rlcChkTmr(RlcCb *gCb, PTR cb, int16_t tmrEvnt)
418 case EVENT_RLC_UMUL_REASSEMBLE_TMR:
420 return (((RlcUlRbCb *)cb)->m.umUl.reAsmblTmr.tmrEvnt ==
421 EVENT_RLC_UMUL_REASSEMBLE_TMR);
423 case EVENT_RLC_AMUL_REASSEMBLE_TMR:
425 return (((RlcUlRbCb *)cb)->m.amUl.reAsmblTmr.tmrEvnt ==
426 EVENT_RLC_AMUL_REASSEMBLE_TMR);
428 case EVENT_RLC_AMUL_STA_PROH_TMR:
430 return (((RlcUlRbCb *)cb)->m.amUl.staProhTmr.tmrEvnt ==
431 EVENT_RLC_AMUL_STA_PROH_TMR);
433 case EVENT_RLC_AMDL_POLL_RETX_TMR:
435 return (((RlcDlRbCb *)cb)->m.amDl.pollRetxTmr.tmrEvnt ==
436 EVENT_RLC_AMDL_POLL_RETX_TMR);
438 case EVENT_RLC_WAIT_BNDCFM:
440 return (((RlcRguSapCb *)cb)->bndTmr.tmrEvnt == EVENT_RLC_WAIT_BNDCFM);
442 case EVENT_RLC_UE_THROUGHPUT_TMR:
444 return (((RlcThpt *)cb)->ueTputInfo.ueThptTmr.tmrEvnt == EVENT_RLC_UE_THROUGHPUT_TMR);
446 case EVENT_RLC_UE_DELETE_TMR:
448 return (((RlcUlUeCb *)cb)->ueDeleteInfo.ueDelTmr.tmrEvnt == EVENT_RLC_UE_DELETE_TMR);
450 case EVENT_RLC_SNSSAI_THROUGHPUT_TMR:
452 return (((RlcThpt *)cb)->snssaiTputInfo.snssaiThptTmr.tmrEvnt == EVENT_RLC_SNSSAI_THROUGHPUT_TMR);
456 DU_LOG("\nERROR --> RLC : rlcChkTmr: Invalid tmr Evnt [%d]", tmrEvnt);
464 * @brief Handler to do processing on expiry of the bind timer
467 * This function processes the RLC bind timer expiry. If the number of
468 * retries is less than the maximum retry counter, bind request is sent
469 * again, else an alarm is raised to the layer manager.
471 * @param[in] cb Pointer to the Rgu sap
475 static Void rlcBndTmrExpiry(PTR cb)
477 RlcRguSapCb *rguSapCb;
479 rguSapCb = (RlcRguSapCb *) cb;
481 if (rguSapCb->state == RLC_SAP_BINDING)
483 if (rguSapCb->retryCnt < RLC_MAX_SAP_BND_RETRY)
485 /* start timer to wait for bind confirm */
486 rlcStartTmr(RLC_GET_RLCCB(rguSapCb->pst.srcInst),
488 EVENT_RLC_WAIT_BNDCFM);
490 /* Send bind request */
491 rguSapCb->retryCnt++;
492 RlcLiRguBndReq (&rguSapCb->pst, rguSapCb->suId, rguSapCb->spId);
496 rguSapCb->retryCnt = 0;
497 rguSapCb->state = RLC_SAP_CFG;
499 /* Send alarm to the layer manager */
501 rlcLmmSendAlarm(RLC_GET_RLCCB(rguSapCb->pst.srcInst),
502 LCM_CATEGORY_INTERFACE,
504 LCM_CAUSE_TMR_EXPIRED,
509 rlcLmmSendAlarm(RLC_GET_RLCCB(rguSapCb->pst.srcInst),
510 LCM_CATEGORY_INTERFACE,
512 LCM_CAUSE_TMR_EXPIRED,
523 * @brief Handler to do processing on expiry of UE throughput timer
526 * This function processes the RLC UE throughput timer expiry.
528 * @param[in] cb Pointer to the RLC throughput struct
532 void rlcUeThptTmrExpiry(PTR cb)
536 RlcThpt *rlcThptCb = (RlcThpt*)cb;
538 /* If cell is not up, throughput details cannot be printed */
539 if(gCellStatus != CELL_UP)
542 rlcStartTmr(RLC_GET_RLCCB(rlcThptCb->inst), (PTR)(rlcThptCb), EVENT_RLC_UE_THROUGHPUT_TMR);
546 /* If cell is up, print throughout for each UE attached to the cell */
547 DU_LOG("\n===================== DL Throughput Per UE==============================");
548 DU_LOG("\nNumber of UEs : %d", rlcThptCb->ueTputInfo.numActvUe);
549 if(rlcThptCb->ueTputInfo.numActvUe)
551 for(ueIdx = 0; ueIdx < MAX_NUM_UE; ueIdx++)
553 if(rlcThptCb->ueTputInfo.thptPerUe[ueIdx].ueId)
555 /* Spec 28.552, section 5.1.1.3 :
556 * Throughput in kilobits/sec = (dataVol in kiloBits * 1000)/time in milligseconds
558 * Since our dataVol is in bytes, multiplying 0.008 to covert into kilobits i.e.
559 * Throughput[kbits/sec] = (dataVol * 0.008 * 1000)/time in ms
561 tpt = (double)(rlcThptCb->ueTputInfo.thptPerUe[ueIdx].dataVol * 8)/(double)ODU_UE_THROUGHPUT_PRINT_TIME_INTERVAL;
563 DU_LOG("\nUE Id : %d DL Tpt : %.2Lf", rlcThptCb->ueTputInfo.thptPerUe[ueIdx].ueId, tpt);
564 rlcThptCb->ueTputInfo.thptPerUe[ueIdx].dataVol = 0;
568 DU_LOG("\n==================================================================");
571 rlcStartTmr(RLC_GET_RLCCB(rlcThptCb->inst), (PTR)rlcThptCb, EVENT_RLC_UE_THROUGHPUT_TMR);
577 * @brief Handler to do processing on expiry of the SNSSAI throughput timer
580 * This function processes the RLC SNSSAI throughput timer expiry.
582 * @param[in] cb Pointer to the RLC throughput struct
586 void rlcSnssaiThptTmrExpiry(PTR cb)
589 RlcThpt *rlcThptCb = (RlcThpt*)cb;
591 /* If cell is not up, throughput details cannot be printed */
592 if(gCellStatus != CELL_UP)
595 rlcStartTmr(RLC_GET_RLCCB(rlcThptCb->inst), (PTR)(rlcThptCb), EVENT_RLC_SNSSAI_THROUGHPUT_TMR);
599 DU_LOG("\n==================================================================");
600 if(rlcThptCb->snssaiTputInfo.tputPerSnssaiList != NULLP)
602 DU_LOG("\n===================== DL Throughput Per SNSSAI ==============================");
604 rlcCalculateTputPerSnssai(rlcThptCb->snssaiTputInfo.tputPerSnssaiList);
605 DU_LOG("\n==================================================================");
608 rlcStartTmr(RLC_GET_RLCCB(rlcThptCb->inst), (PTR)rlcThptCb, EVENT_RLC_SNSSAI_THROUGHPUT_TMR);
613 * @brief filling RLC UE delete configuration
616 * filling RLC UE delete configuration
618 * @params[in] RlcUlUeCb *ueCb, RlcCfgInfo *rlcUeCfg
624 void fillRlcUeDelInfo(RlcUlUeCb *ueCb, RlcCfgInfo *rlcUeCfg)
628 rlcUeCfg->ueId = ueCb->ueId;
629 rlcUeCfg->cellId = ueCb->cellId;
630 rlcUeCfg->numEnt = 0;
631 for(lcIdx=0; lcIdx<RLC_MAX_LCH_PER_UE && rlcUeCfg->numEnt < 1; lcIdx++)
633 if(ueCb->lCh[lcIdx].ulRbCb != NULLP)
635 rlcUeCfg->entCfg[rlcUeCfg->numEnt].rbId = 0;
636 rlcUeCfg->entCfg[rlcUeCfg->numEnt].rbType = 0;
637 rlcUeCfg->entCfg[rlcUeCfg->numEnt].cfgType = CKW_CFG_DELETE_UE;
644 * @brief Handler to do processing on expiry of the UE delete timer
647 * This function processes the RLC UE delete timer expiry.
649 * @param[in] cb Pointer to the RlcUlUeCb
654 uint8_t rlcUeDeleteTmrExpiry(PTR cb)
656 RlcCb *gRlcCb = NULLP;
657 RlcCfgInfo *rlcUeCfg = NULLP;
658 RlcUlUeCb *ueCb = (RlcUlUeCb*)cb;
660 gRlcCb = RLC_GET_RLCCB(ueCb->ueDeleteInfo.pst.dstInst);
661 RLC_ALLOC(gRlcCb, rlcUeCfg, sizeof(RlcCfgInfo));
662 if(rlcUeCfg == NULLP)
664 DU_LOG("\nERROR --> RLC: rlcUeDeleteTmrExpiry(): Failed to allocate memory");
667 memset(rlcUeCfg, 0, sizeof(RlcCfgInfo));
668 fillRlcUeDelInfo(ueCb, rlcUeCfg);
669 if(RlcProcCfgReq(&ueCb->ueDeleteInfo.pst, rlcUeCfg) != ROK)
671 DU_LOG("\nERROR --> RLC: rlcUeDeleteTmrExpiry(): Failed to delete UE");
672 if(sendRlcUeDeleteRspToDu(rlcUeCfg->cellId, rlcUeCfg->ueId, INVALID_UEID) != ROK)
674 DU_LOG("ERROR --> RLC: rlcUeDeleteTmrExpiry(): Failed to send UE delete response ");
681 /********************************************************************30**
684 **********************************************************************/