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 - AM DL module file
25 Desc: Source code for Acknowledged Mode Module functions such as,
27 Transmission of data/control PDUs
28 Retransmission (Feedback in terms of status)
31 Reception - reordering
32 Duplicate detection for byte segments
37 *********************************************************************21*/
38 static const char* RLOG_MODULE_NAME="AMM";
39 static int RLOG_MODULE_ID=2048;
40 static int RLOG_FILE_ID=189;
41 /* header include files (.h) */
42 #include "common_def.h"
43 #include "lkw.h" /* LKW defines */
44 #include "ckw.h" /* CKW defines */
45 #include "kwu.h" /* KWU defines */
46 #include "rgu.h" /* RGU defines */
47 #include "kw_err.h" /* Err defines */
48 #include "kw_env.h" /* RLC environment options */
50 #include "kw.h" /* RLC defines */
55 /* extern (.x) include files */
56 #include "lkw.x" /* LKW */
57 #include "ckw.x" /* CKW */
58 #include "kwu.x" /* KWU */
59 #include "rgu.x" /* RGU */
67 extern U32 rlcAmmStaPduList[512];
68 U32 rlcAmmStaPduListCnt = 0;
73 @brief RLC Acknowledged Mode Downlink Module
75 #define RLC_MODULE (RLC_DBGMASK_AM | RLC_DBGMASK_DL)
77 U32 rlcStatusPduCnt, rlcStatusAckCnt, rlcStatusNcnt, rlcSduSndCnt;
83 /* forward references */
84 EXTERN Void rlcAmmDlHndlStatusPdu ARGS ((RlcCb *gCb,
86 RlcUdxStaPdu *pStaPdu));
88 /* public variable declarations */
90 /* This structure holds all the global structs we need. */
92 /* private variable declarations */
94 #define RLC_AM_RMV_HDR(_gCb, _rbCb, _retx) do { \
95 if ((_retx)->yetToConst == FALSE) \
98 SSegMsg((_retx)->seg, (_retx)->hdrSz, &_pduInfo); \
99 RLC_FREE_BUF((_retx)->seg); \
100 (_retx)->seg = _pduInfo; \
102 (_rbCb)->m.amDl.estHdrSz -= retx->hdrSz;\
105 /* private function declarations */
107 PRIVATE Void rlcResegRetxPdus ARGS ((RlcCb *gCb,
109 RlcDatReq *rlcDatReq));
111 PRIVATE Void rlcRemRetxPdu ARGS ((RlcCb *gCb,
115 PRIVATE Void rlcAmmCreateStatusPdu ARGS ((RlcCb *gCb,
117 RlcDatReq *rlcDatReq));
119 PRIVATE Void rlcAmmDlMarkPduForReTx ARGS ((RlcCb *gCb,
123 PRIVATE Void rlcAmmDlProcessSuccessfulTxPdu ARGS((RlcCb *gCb,
126 KwuDatCfmInfo **datCfm));
128 PRIVATE Void rlcAmmDlSetTxNextAck ARGS((RlcAmDl *amDl, RlcSn sn));
130 PRIVATE Void rlcAmmDlCheckAndStopPollTmr ARGS((RlcCb *gCb,
134 PRIVATE Void rlcAssembleSdus ARGS ((RlcCb *gCb,
136 RlcDatReq *rlcDatReq));
138 bool rlcAmmDlCheckAndSetPoll ARGS ((RlcCb *gCb,
143 PRIVATE Void rlcAmmCreatePdu ARGS ((RlcCb *gCb,
146 RlcDlPduInfo *pduInfo,
149 PRIVATE Void rlcAmmSndStaInd ARGS ((RlcCb *gCb,RlcDlRbCb *rbCb, RlcRetx *retx));
151 PRIVATE Void rlcGetNxtRetx ARGS ((RlcCb *gCb, RlcRetx **retx));
153 PRIVATE Void rlcConstructAmHdr ARGS ((RlcAmHdr *amHdr,
158 PRIVATE Void rlcAmmDlUpdateTxAndReTxBufForAckSn ARGS ((RlcCb *gCb,
162 KwuDatCfmInfo **datCfm));
164 PRIVATE Void rlcAmmDlMoveFrmTxtoRetxBuffer ARGS ((RlcCb *gCb,
169 PRIVATE Void rlcAmmDlCheckIsSDUDelivered ARGS((RlcCb *gCb,
172 KwuDatCfmInfo **datCfm));
174 PRIVATE Void rlcAmmAddPduToRetxLst ARGS((RlcAmDl *amDl,
177 PRIVATE Void rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer ARGS(
182 RlcDlPduInfo *pduInfo
185 PRIVATE Void rlcAmmDlHndlStatus4SduByteSegInTxBuf ARGS(
189 RlcNackInfo *nackSnInfo,
191 KwuDatCfmInfo **datCfm
194 PRIVATE Void rlcAmmDlUpdateTxAndReTxBufForNackSn ARGS(
198 RlcNackInfo *nackSnInfo,
200 KwuDatCfmInfo **datCfm
203 PRIVATE Void RlcDlAmmGetNackSnInfoFrmNackRangeIdx ARGS(
206 RlcNackInfo *nackInfo,
208 RlcNackInfo *nackSnInfo,
212 PRIVATE Void rlcAmmDlUpdTxAndReTxBufForLessThanNackSn ARGS(
219 KwuDatCfmInfo **datCfm
221 /*****************************************************************************
223 AM Module contains the following funcitons:
227 - rlcAmmDlAssembleCntrlInfo
230 - rlcAmmDlCheckAndSetPoll
236 *******************************************************************************/
237 /** @addtogroup ammode */
241 * @brief Function to send a Status Response to MAC for a dedicated logical
245 * Function calculates the current bo and send a Status response for the
246 * dedicated logical channel if the bo is non zero
248 * @param[in] gCb RLC instance control block
249 * @param[in] rbCb Radio Bearer control block
250 * @param[in] amDl AM downlink control block
254 void rlcAmmSendDedLcBoStatus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcAmDl *amDl)
256 int32_t bo = rlcAmmCalculateBo(amDl);
260 rlcUtlSendDedLcBoStatus(gCb, rbCb, bo, amDl->estHdrSz, \
261 amDl->cntrlBo ?TRUE:FALSE,amDl->cntrlBo);
268 * @brief Function to check if the pollSn is acked and stop the poll timer
270 * @param[in] gCb RLC instance control block
271 * @param[in] rbCb Radio Bearer control block
272 * @param[in] mAckSn The last received ACKSN. The base modulus value should
278 PRIVATE Void rlcAmmDlCheckAndStopPollTmr
285 PRIVATE Void rlcAmmDlCheckAndStopPollTmr(gCb, rbCb, mAckSn)
293 MODAMT(rbCb->m.amDl.pollSn, mPollSn, rbCb->m.amDl.txNextAck,rbCb->m.amDl.snModMask);
295 if (mPollSn <= mAckSn)
297 if (rlcChkTmr(gCb, (PTR)rbCb, RLC_EVT_AMDL_POLL_RETX_TMR))
299 rlcStopTmr(gCb, (PTR)rbCb, RLC_EVT_AMDL_POLL_RETX_TMR);
307 * @brief Function to set VT(A) and VT(MS). Calculates the VT(MS) from VT(A)
309 * @param[in,out] amDl AM downlink control block
310 * @param[in]sn Sequence number to be set as VT(A)
315 PRIVATE Void rlcAmmDlSetTxNextAck
321 PRIVATE Void rlcAmmDlSetTxNextAck(amDl, sn)
326 amDl->txNextAck = sn;
332 * @brief Function to process a successfully re-transmitted PDU/segment
335 * Checks if the SDU has been completely delivered or not. Removes the PDU
336 * from the re-transmission buffer
338 * @param[in] gCb RLC instance control block
339 * @param[in] rbCb Downlink Radio Bearer control block
340 * @param[in] retx The PDU/segment which was successfully re-transmitted
345 PRIVATE Void rlcAmmDlProcessSuccessfulReTx
350 KwuDatCfmInfo **datCfm
353 PRIVATE Void rlcAmmDlProcessSuccessfulReTx(gCb, rbCb, retx, datCfm)
357 KwuDatCfmInfo **datCfm;
360 rlcAmmDlCheckIsSDUDelivered(gCb, rbCb, &(retx->sduMap), datCfm);
362 rlcRemRetxPdu(gCb, rbCb, retx);
368 * @brief Handler to Move the PDU from txBuf to re-transmission buffer
371 * This function is used to move the PDU from the txBuf to re-transmit buffer
373 * @param[in]RlcCb *gCb RLC instance control block
374 * @param[in]RlcAmDl *amDl AM Downlink Control Block
375 * @param[in]RlcRetx **retx node in the reTx buffer to be moved to, allocated by
377 * @param[in]RlcDlPduInfo *pduInfo TX PDU which needs to be moved
384 PRIVATE Void rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer
389 RlcDlPduInfo *pduInfo
392 PRIVATE Void rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb, amDl, retx, pduInfo)
396 RlcDlPduInfo *pduInfo;
399 TRC2(rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer);
402 RLC_ALLOC_WC(gCb,*retx, sizeof(RlcRetx));
404 #if (ERRCLASS & ERRCLS_ADD_RES)
407 RLOG0(L_FATAL, "Memory allocation failed");
410 #endif /* ERRCLASS & ERRCLS_RES */
412 (*retx)->seg = pduInfo->pdu;
413 (*retx)->segSz = pduInfo->pduSz;
414 /* MS_FIX for DL stall */
415 (*retx)->soEnd = (pduInfo->amHdr.so + pduInfo->pduSz - 1);
417 (*retx)->hdrSz = pduInfo->hdrSz;
418 (*retx)->retxCnt = 1;
419 (*retx)->yetToConst = 0;
420 (*retx)->pendingReTrans = TRUE;
422 /* initialize the list pointer to 0 instead of memset */
423 (*retx)->lstEnt.next = 0;
424 (*retx)->lstEnt.prev = 0;
425 /* copy the sdu maps */
426 RLC_MEM_CPY(&((*retx)->sduMap),
430 RLC_MEM_CPY(&((*retx)->amHdr), &pduInfo->amHdr, sizeof(RlcAmHdr));
431 rlcAmmAddPduToRetxLst(amDl, (*retx));
433 /* Update the BO appropriately */
434 amDl->retxBo += (*retx)->segSz;
435 amDl->estHdrSz += (*retx)->hdrSz;
437 gRlcStats.amRlcStats.numDLRetransPdus++;
440 } /*rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer */
443 * @brief Function to handle Status of Sdu byte segment for a nackSn
446 * This function is used to move the PDU from the txBuf to re-transmit buffer
448 * @param[in]RlcCb *gCb RLC instance control block
449 * @param[in]RlcDlRbCb *rbCb AM Downlink Control Block
450 * @param[in]RlcNackInfo *nackSnInfo Nack Information of a NACK_SN
451 * @param[in]RlcRetx **retx node in the reTx buffer to be moved to, allocated by
453 * @param[in]KwuDatCfmInfo **datCfm Ptr to datCfm
460 PRIVATE Void rlcAmmDlHndlStatus4SduByteSegInTxBuf
464 RlcNackInfo *nackSnInfo,
466 KwuDatCfmInfo ** datCfm
469 PRIVATE Void rlcAmmDlHndlStatus4SduByteSegInTxBuf(gCb, rbCb, nackSnInfo, retx, datCfm)
473 RlcNackInfo *nackSnInfo;
475 KwuDatCfmInfo **datCfm;
483 TRC2(rlcAmmDlHndlStatus4SduByteSegInTxBuf)
485 txBuf = rlcUtlGetTxBuf(AMDL.txBufLst, nackSnInfo->sn);
490 lnk = txBuf->pduLst.first;
493 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(lnk->node);
494 RlcSn pduSoEnd = (pduInfo->amHdr.so + pduInfo->sduMap.sduSz - 1);
496 /* If So of Sdu byte segment(pduInfo/seg) is < status pdu
497 soStart that means it's ACKED*/
498 if(pduSoEnd < nackSnInfo->soStart)
500 rlcAmmDlCheckIsSDUDelivered(gCb,
506 else if (pduSoEnd <= nackSnInfo->soEnd)
508 /* Move Sdu byte segment from TX buf to retx buf*/
509 rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb,
520 /* Delete node from the txBuf Pdu lst */
521 cmLListDelFrm(&txBuf->pduLst, lnk);
522 RLC_FREE_WC(gCb, pduInfo, sizeof(RlcDlPduInfo));
525 if(!txBuf->pduLst.count)
527 /*No more Sdu byte segment are left. Hence delete txBuf*/
528 rlcUtlDelTxBuf(AMDL.txBufLst, txBuf,gCb);
535 * @brief Function to handle Status of Sdu byte segment for a nackSn
538 * This function is used to move the PDU from the txBuf to re-transmit buffer
540 * @param[in]RlcCb *gCb RLC instance control block
541 * @param[in]RlcDlRbCb *rbCb AM Downlink Control Block
542 * @param[in]RlcNackInfo *nackSnInfo Nack Information of a NACK_SN
543 * @param[in]RlcRetx **retx node in the reTx buffer to be moved to, allocated by
545 * @param[in]KwuDatCfmInfo **datCfm Ptr to datCfm
551 PRIVATE Void rlcAmmDlUpdateTxAndReTxBufForNackSn
555 RlcNackInfo *nackSnInfo,
557 KwuDatCfmInfo **datCfm
560 PRIVATE Void rlcAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, nackSnInfo, retxNode, datCfm)
564 RlcNackInfo *nackSnInfo;
566 KwuDatCfmInfo **datCfm;
573 TRC2(rlcAmmDlUpdateTxAndReTxBufForNackSn)
575 /* Now process the NACK_SN received. Now the NACK_SN is */
576 /* either the first element of RETX or is in TX array */
577 /* To remove the remaining acks from the pdu byte segments */
579 /* if the NACK_SN is in the transmit buffer, move it to the re-
581 txBuf = rlcUtlGetTxBuf(AMDL.txBufLst, nackSnInfo->sn);
584 if(nackSnInfo->isSegment)
586 /* Go through all the AMD PDUs of a particular SN
587 and check if segment is ACKED if yes then mark succesfully sent,
588 if segment is NACKed then move it to to retx lst */
589 rlcAmmDlHndlStatus4SduByteSegInTxBuf(gCb, rbCb, nackSnInfo, &retx, datCfm);
593 /*e2= 0 and e3= 0: Move complete PDU from TX buf to retx buf*/
594 rlcAmmDlMoveFrmTxtoRetxBuffer(gCb,
600 #if (ERRCLASS & ERRCLS_ADD_RES)
604 (*retxNode) = retx->lstEnt.next;
610 /* process the pdus/segments in the re-transmit buffer with
614 retx = (RlcRetx *)((*retxNode)->node);
615 if (retx->amHdr.sn != nackSnInfo->sn)
619 if ((nackSnInfo->isSegment) &&
620 ((retx->soEnd < nackSnInfo->soStart) /*|| (retx->amHdr.so > soEnd)*/))
622 RLOG_ARG3(L_DEBUG, DBG_RBID, rbCb->rlcId.rbId,
623 "rlcHndlStaRsp: Handle ACK for byte segment, Its "
624 "sn = %d UEID:%d CELLID:%d",
628 RLOG_ARG4(L_DEBUG, DBG_RBID, rbCb->rlcId.rbId,
629 "soStart and soEnd = %d, %d, UEID:%d CELLID:%d",
630 retx->amHdr.so, retx->soEnd,
634 (*retxNode) = (*retxNode)->next;
635 rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
637 else if((!nackSnInfo->isSegment) || (retx->soEnd <= nackSnInfo->soEnd))
639 /* This case covers the NACKED segments and also the case */
640 /* when there are segments and the entire SN is nacked. */
641 /* This case also covers the case of nonsegmented retx PDU*/
643 (*retxNode) = (*retxNode)->next;
644 /* Mark the retx PDU we found for further retransmission */
645 rlcAmmDlMarkPduForReTx(gCb, rbCb, retx);
649 /* If we are here that means this segment and segments after this are ACKed*/
652 } /* end of retxNode while loop*/
657 * @brief Function to get nack Sn information from nackRange index
660 * This function is used to get nack Sn information from nackRange index
662 * @param[in]RlcAmDl *amDl,
663 * @param[in]RlcUdxStaPdu *StaPdu,
664 * @param[in]RlcNackInfo *nackSnInfo,
665 * @param[in]RlcRetx *retx;
666 * @param[in]RlcSn sn,
673 PRIVATE Void RlcDlAmmGetNackSnInfoFrmNackRangeIdx
676 RlcNackInfo *nackInfo,
678 RlcNackInfo *nackSnInfo,
682 PRIVATE Void RlcDlAmmGetNackSnInfoFrmNackRangeIdx(amDl, nackInfo, retxNode, nackSnInfo, idx)
685 RlcNackInfo *nackInfo;
687 RlcNackInfo *nackSnInfo;
696 TRC2(RlcDlAmmGetNackSnInfoFrmNackRangeIdx)
698 nackSnInfo->isSegment = FALSE;
700 if((!nackInfo->isSegment) || (!idx && nackSnInfo->nackRange && (!nackInfo->soStart)))
702 nackSnInfo->soStart = 0;
703 nackSnInfo->soEnd = 0;
706 txBuf = rlcUtlGetTxBuf(amDl->txBufLst, nackSnInfo->sn);
709 node = txBuf->pduLst.first;
712 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(node->node);
713 U16 pduSoEnd = pduInfo->amHdr.so + pduInfo->sduMap.sduSz - 1;
714 if((!idx) && (pduInfo->amHdr.so == nackInfo->soStart))
716 nackSnInfo->isSegment = TRUE;
717 nackSnInfo->soStart = pduInfo->amHdr.so;
718 nackSnInfo->soEnd = pduSoEnd;
721 else if((idx == nackSnInfo->nackRange - 1) && \
722 (pduSoEnd == nackInfo->soEnd))
724 nackSnInfo->isSegment = TRUE;
725 nackSnInfo->soStart = pduInfo->amHdr.so;
726 nackSnInfo->soEnd = pduSoEnd;
732 if(!nackSnInfo->isSegment)
736 retx = (RlcRetx *)(retxNode->node);
737 if(retx->amHdr.sn != nackSnInfo->sn)
741 if((!idx) && (retx->amHdr.so == nackInfo->soStart))
743 nackSnInfo->isSegment = TRUE;
744 nackSnInfo->soStart = retx->amHdr.so;
745 nackSnInfo->soEnd = retx->soEnd;
748 else if((idx == nackSnInfo->nackRange - 1) && \
749 (retx->soEnd == nackInfo->soEnd))
751 nackSnInfo->isSegment = TRUE;
752 nackSnInfo->soStart = retx->amHdr.so;
753 nackSnInfo->soEnd = retx->soEnd;
756 retxNode = retxNode->next;
762 * @brief Function to update transmission buffers and send confimations to
763 * PDCP on the reception of Status PDU
766 * First processes the NACKs received
767 * -# Removes the pdus which are acked by each of the NACK SN from the
768 * transmission and re-transmission buffer
769 * -# If NACKed SN in in the transmisson buffer, moves it to re-transmission
771 * -# Removes PDU segments of the NACKed SN which have been successfully
772 * received by the other end. For the un-successful ones, marks them for
774 * -# When PDUs/segments are removed from the buffer, indicates to upper
775 * layer if the SDU is completely delivered
776 * -# Removes the PDUs/segments which are acked by the ACK_SN but not by the
779 * @param[in] gCb RLC Instance control block
780 * @param[in] rbCb Downlink Radio Bearer control block
781 * @param[in] pStaPdu The decoded Status Pdu
786 Void rlcAmmDlHndlStatusPdu
790 RlcUdxStaPdu *pStaPdu
793 Void rlcAmmDlHndlStatusPdu(gCb, rbCb, pStaPdu)
796 RlcUdxStaPdu *pStaPdu;
802 KwuDatCfmInfo* datCfm;
803 RlcKwuSapCb *rlckwuSap;
806 TRC2(rlcAmmDlHndlStatusPdu)
809 rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
810 /* store the re-transmission bo, to check if it changes due to the
811 processing of the status pdu */
812 oldRetxBo = AMDL.retxBo;
814 /* Allocate memory for datCfm Info */
815 RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
817 #if (ERRCLASS & ERRCLS_ADD_RES)
820 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
821 "Memory allocation failed UEID:%d CELLID:%d",
824 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
827 #endif /* ERRCLASS & ERRCLS_RES */
829 datCfm->numSduIds = 0;
830 datCfm->rlcId = rbCb->rlcId;
832 MODAMT(pStaPdu->ackSn, mAckSn, AMDL.txNextAck,AMDL.snModMask);
833 MODAMT(AMDL.txNext,mTxNext, AMDL.txNextAck,AMDL.snModMask);
837 RLOG_ARG4(L_WARNING,DBG_RBID, rbCb->rlcId.rbId,
838 "Invalid ACK SN = %d received. Current Vta =%d"
844 /* RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo)); */
845 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
849 /* Venki - stopping the poll retx timer */
850 /*Stop PollRetx Tmr */
851 rlcAmmDlCheckAndStopPollTmr(gCb, rbCb, mAckSn);
853 /* Set the first node in retx list to retxNode */
854 retxNode = AMDL.retxLst.first;
856 /* If NACK exists in control PDU */
857 if (pStaPdu->nackCnt)
860 RlcNackInfo nackSnInfo;
863 RlcSn transWinStartSn = AMDL.txNextAck; /*used to track the SN from which
864 to start processing the transmission
868 /* if any NACKs then txNextAck should be equal to the first NACK_SN*/
869 txNextAck = pStaPdu->nackInfo[0].sn;
871 rlcStatusNcnt += pStaPdu->nackCnt;
874 while (idx < pStaPdu->nackCnt)
876 nackSnInfo.isSegment = pStaPdu->nackInfo[idx].isSegment;
877 nackSnInfo.nackRange = pStaPdu->nackInfo[idx].nackRange;
878 nackSnInfo.sn = pStaPdu->nackInfo[idx].sn;
880 RLOG_ARG3(L_DEBUG,DBG_RBID, rbCb->rlcId.rbId,
881 "rlcHndlStaRsp: NACK SN = %d UEID:%d CELLID:%d",
886 nackSnInfo.soStart = pStaPdu->nackInfo[idx].soStart;
887 nackSnInfo.soEnd = pStaPdu->nackInfo[idx].soEnd;
889 /* e2 is used as a boolean indicating presence of SOStart or SOEnd */
891 sn = transWinStartSn;
893 /* move transWinStartSn to nackSnInfo.sn + 1, as the pdu's before that
894 will be removed from the buffer */
895 transWinStartSn = (nackSnInfo.sn + (nackSnInfo.nackRange ?\
896 (nackSnInfo.nackRange - 1) : 0) + 1) & AMDL.snModMask;
898 /* Clear the acked SNs from the retx list */
899 MODAMT(nackSnInfo.sn, mNackSn, AMDL.txNextAck,AMDL.snModMask);
901 if ((mNackSn > mAckSn) || (mNackSn >= mTxNext))
903 /* Erroneous NACK_SN, we should raise an error towards L3 */
904 RLOG_ARG2(L_ERROR,DBG_RBID, rbCb->rlcId.rbId,
905 "Status Pdu is not correct UEID:%d CELLID:%d",
908 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
912 /* clear all the SNs < NACK_SN from re-transmission list */
913 rlcAmmDlUpdTxAndReTxBufForLessThanNackSn(gCb, rbCb, sn, mNackSn,
916 if(!nackSnInfo.nackRange)
918 rlcAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, &nackSnInfo, &retxNode, &datCfm);
919 gRlcStats.amRlcStats.numRlcAmCellNackRx++;
924 /* Update issegment, soStart, soEnd ,sn in nackSnInfo and handle
928 RlcDlAmmGetNackSnInfoFrmNackRangeIdx(&AMDL, &pStaPdu->nackInfo[idx],
929 retxNode, &nackSnInfo, idx1);
931 rlcAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, &nackSnInfo,
933 nackSnInfo.sn = ((nackSnInfo.sn + 1) & (AMDL.snModMask));
934 gRlcStats.amRlcStats.numRlcAmCellNackRx++;
936 }while((++idx1) < (nackSnInfo.nackRange));
940 } /* End of nackCnt while loop */
942 /* Remove the PDUs with are further acked by the ACK_SN after taking
943 care of all the NACK_SN related acknowledgments*/
944 rlcAmmDlUpdateTxAndReTxBufForAckSn(gCb,rbCb, mAckSn, retxNode, &datCfm);
946 /* Update txNextAck */
947 rlcAmmDlSetTxNextAck(&AMDL,txNextAck);
953 RLOG_ARG2(L_UNUSED,DBG_RBID, rbCb->rlcId.rbId,
954 "rlcHndlStaRsp: Received All ACKS UEID:%d CELLID:%d",
958 /* For the remaining ACKs after last nackSn */
959 rlcAmmDlUpdateTxAndReTxBufForAckSn(gCb,rbCb, mAckSn, retxNode, &datCfm);
961 /* update txNextAck */
962 rlcAmmDlSetTxNextAck(&AMDL, pStaPdu->ackSn);
965 if(datCfm->numSduIds != 0)
967 if(datCfm->numSduIds > 1024)
969 RLOG_ARG4(L_DEBUG,DBG_RBID,datCfm->rlcId.rbId,
970 "Sending [%lu] SDU Cfms to PDCP & [%lu] lost for"
973 datCfm->numSduIds-1024,
976 datCfm->numSduIds = 1024;
978 rlcSduSndCnt += datCfm->numSduIds;
979 /* Sap control block */
980 RlcUiKwuDatCfm(&rlckwuSap->pst, rlckwuSap->suId, datCfm);
984 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
987 /* Fix for memory corruption */
988 RLC_LLIST_FIRST_RETX(AMDL.retxLst, AMDL.nxtRetx);
989 /* BO update, if retransmission BO has changed. AMDL.retxBo would have
990 canged inside the above called functions */
991 if (oldRetxBo != AMDL.retxBo)
993 rlcAmmSendDedLcBoStatus(gCb, rbCb, &AMDL);
1000 * @brief Function to calculate the current buffer occupancy
1003 * Function to calculate the current bo depending on the control,
1004 * re-transmit, transmit bo's and the state of the transmit window.
1005 * If the transmit window is stalled, then the transmit bo is not
1006 * taken into account
1008 * @param[in] amDl AM mode donwlink control block
1014 S32 rlcAmmCalculateBo
1019 S32 rlcAmmCalculateBo(amDl)
1025 /* Make sure non of the bo's are negative */
1031 if (amDl->cntrlBo < 0)
1036 if (amDl->retxBo < 0)
1041 bo = amDl->cntrlBo + amDl->retxBo;
1043 /* if window is not stalled then add the transmit bo also */
1044 if (! RLC_AM_IS_TRANS_WIN_STALLED(amDl))
1054 * @brief Handler to queue the SDUs received from PDCP
1057 * This function is invoked by UIM to queue the SDU received from PDCP in the
1058 * SDU queue of the corresponding RbCb. It also updates the BO and report the
1060 * - Allocate memory for and assign received buffer to the SDU
1061 * - Add SDU in the sduQ of RlcAmDl
1062 * - Calculate bo with the buffer received
1063 * - Accumulate bo with retransmission bo and control pdu's bo if available
1064 * - Estimate the header size for the bo; Fill in StaRspInfo and send it
1067 * @param[in] gCb RLC Instance control block
1068 * @param[in] rbCb RB control block
1069 * @param[in] mBuf Sdu to be queued
1070 * @param[in] datReq Ptr to the datReq sent from PDCP
1075 void rlcAmmQSdu(RlcCb *gCb, RlcDlRbCb *rbCb, Buffer *mBuf, KwuDatReqInfo *datReq)
1087 RLC_ALLOC_WC(gCb,sdu, sizeof(RlcSdu));
1089 #if (ERRCLASS & ERRCLS_ADD_RES)
1092 DU_LOG("\n RLC : rlcAmmQSdu : Memory allocation failed UEID:%d CELLID:%d",\
1093 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1096 #endif /* ERRCLASS & ERRCLS_RES */
1098 RLC_UPD_L2_DL_TOT_SDU_STS(gCb,rbCb);
1099 /* Discard new changes starts */
1100 rlcUtlGetCurrTime(&sdu->arrTime);
1101 /* Discard new changes ends */
1102 /* Assign values to sdu */
1103 ODU_GET_MSG_LEN(mBuf, &sdu->sduSz);
1106 sdu->actSz = sdu->sduSz;
1107 sdu->mode.am.sduId = datReq->sduId;
1108 /* initialize values for AM mode to 0 */
1109 sdu->mode.am.rcvdSz = 0;
1110 sdu->mode.am.isSegmented = 0;
1111 #ifndef RGL_SPECIFIC_CHANGES
1114 extern uint32_t dlrate_kwu;
1115 dlrate_kwu += sdu->sduSz;
1119 /* Update nxtTx to point to the added sdu if this is the first SDU in the
1121 if (AMDL.nxtTx == NULLP)
1123 DU_LOG("\nRLC : rlcAmmQSdu: Received SDU will be transmitted next \
1124 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1128 /* Add sdu to the sdu list */
1129 cmLListAdd2Tail(&AMDL.sduQ, &sdu->lstEnt);
1130 sdu->lstEnt.node = (PTR)sdu;
1134 if (rbCb->ueCb->tenbStats)
1136 if (AMDL.sduQ.count > rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxPktsInSduQ)
1138 rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxPktsInSduQ = AMDL.sduQ.count;
1140 rlcWinSz = RLC_AM_TRANS_WIN_SIZE(&AMDL);
1141 if (rlcWinSz > rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxWindowSz)
1143 rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxWindowSz = rlcWinSz;
1149 /* Update BO and estimate header size for the current BO */
1150 AMDL.bo = AMDL.bo + sdu->sduSz;
1151 if(AMDL.snLen == RLC_AM_CFG_12BIT_SN_LEN)
1159 #ifdef LTE_L2_MEAS_RLC
1160 /* Update numActUe if it is not active */
1161 if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_ACT_UE) &&
1162 (rbCb->ueCb->numActRb[rbCb->qci] == 0))
1164 rbCb->ueCb->numActRb[rbCb->qci]++;
1165 gCb.rlcL2Cb.numActUe[rbCb->qci]++;
1169 if(!rlcDlUtlIsReestInProgress(rbCb))
1171 rlcAmmSendDedLcBoStatus(gCb, rbCb, &AMDL);
1179 * @brief Private handler to construct control PDU
1182 * This function sets the pduSz correctly after eliminating the fixed
1183 * header sizes and the MAC header size. It copies the already prepared
1184 * STATUS PDU to the data to be sent to MAC.
1186 * @param[in] gCb RLC instance control block
1187 * @param[in] rbCb Downlink RB control block
1188 * @param[in] kwdatReq DatReq to be sent to MAC
1193 void rlcAmmDlAssembleCntrlInfo(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
1195 RlcUdxDlSapCb *sapCb;
1198 macHdrEstmt = (rbCb->m.amDl.cntrlBo < 256) ?
1199 RLC_MAC_HDR_SZ2 : RLC_MAC_HDR_SZ3;
1200 /* Eliminate fixed hdr size (14bits including ACK_SN) */
1201 if (rlcDatReq->pduSz >= (RLC_CNTRL_PDU_FIXED_HDRSZ + macHdrEstmt))
1203 /* Check the TB size whether it is sufficcient enough to fit the
1204 status Pdu into it otherwise make arrangement such that it can fit
1205 into in a way of possible NACks*/
1206 /* ccpu00135743 : fix for MAC Hdr size calc */
1207 rlcDatReq->pduSz -= macHdrEstmt;
1209 /* Create the status Pdu with the required NACKs */
1210 rlcAmmCreateStatusPdu(gCb,rbCb,rlcDatReq);
1212 sapCb = RLC_GET_DL_SAPCB(gCb, rbCb);
1213 rlcDlUdxStaProhTmrStart(&(gCb->u.dlCb->udxDlSap->pst),
1214 sapCb->suId, &(rbCb->rlcId));
1216 /* Update number of pdus in pduInfo */
1217 rlcDatReq->pduInfo.mBuf[rlcDatReq->pduInfo.numPdu] = AMDL.mBuf;
1218 rlcDatReq->pduInfo.numPdu++;
1219 gRlcStats.amRlcStats.numDLStaPduSent++;
1221 RLC_FREE_SHRABL_BUF(gCb->u.dlCb->udxDlSap->pst.region,
1222 gCb->u.dlCb->udxDlSap->pst.pool,
1224 sizeof(RlcUdxDlStaPdu));
1226 AMDL.pStaPdu = NULLP;
1228 gRlcStats.amRlcStats.numDLStaPduSent++;
1235 * @brief Handler to form the PDUs with the size indicated by MAC
1238 * This function is invoked by UTL with the PDU size indicated by
1239 * MAC (after eliminating MAC header size). It assembles control
1240 * Info / data (New SDUs / Retx PDUs), check if polling needs to be
1241 * set for the data PDU and returns PDU(s) and updated BO with
1242 * estimated header size to be sent to MAC.
1244 * - Check if the control BO is available and call rlcAssembleCntrlInfo
1245 * to assemble control Information
1246 * - Check if the pdu size is available to form PDUs from retransmission
1247 * buffer and call rlcResegRetxPdus
1248 * - Check if the pdu size is available and assemble SDUs from sduQ
1249 * if exist, using rlcAssembleSdus
1250 * - PDU Info and bo are filled in and then sent to MAC from the
1253 * @param[in] gCb RLC instance control block
1254 * @param[in] rbCb RB control block
1255 * @param[in] kwdatReq DatReq to be sent to MAC
1256 * @param[in] fillCtrlPdu Indicates whether cntrl PDU to be filled or not
1261 void rlcAmmProcessSdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq, bool fillCtrlPdu)
1263 /* Assemble control information. fillCtrlPdu parameter check is added for CA
1264 * It is used to force cntrl Pdu scheduling on PCell. for Non CA case this
1265 * flag will always be TRUE. In CA case, for PCELL it is TRUE and for SCEll
1268 if ((AMDL.cntrlBo != 0)
1274 rlcDatReq->boRep.staPduPrsnt = TRUE;
1275 rlcDatReq->boRep.staPduBo = AMDL.cntrlBo;
1277 if (AMDL.pStaPdu != NULLP)
1279 rlcAmmDlAssembleCntrlInfo (gCb, rbCb, rlcDatReq);
1283 DU_LOG("\nRLC: rlcAmmProcessSdus: Miscomputation of control Bo. \
1284 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1289 /* Retransmit PDUs /portions of PDUs available in retxLst */
1290 if ((rlcDatReq->pduSz > 0) && (AMDL.nxtRetx != NULLP))
1292 rlcResegRetxPdus (gCb,rbCb, rlcDatReq);
1295 /* Assemble SDUs to form new PDUs */
1296 if ((rlcDatReq->pduSz > 0) && (AMDL.nxtTx != 0))
1298 rlcAssembleSdus(gCb,rbCb, rlcDatReq);
1301 if (AMDL.nxtRetx != NULLP)
1303 rlcDatReq->boRep.oldestSduArrTime = AMDL.nxtRetx->sduMap.sdu->arrTime;
1305 else if (AMDL.nxtTx != NULLP)
1307 rlcDatReq->boRep.oldestSduArrTime = AMDL.nxtTx->arrTime;
1310 rlcDatReq->boRep.bo = rlcAmmCalculateBo(&AMDL);
1311 rlcDatReq->boRep.staPduBo = AMDL.cntrlBo;
1313 /* Hdr estimation is moved to kwAmmCreatePDu */
1314 rlcDatReq->boRep.estHdrSz = AMDL.estHdrSz;
1316 if(rlcDatReq->pduSz > 0)
1318 gRlcStats.amRlcStats.numDLBytesUnused += rlcDatReq->pduSz;
1324 * @brief Private handler split a PDU/segment into two
1327 * Its a private function called by kwResegRetxPdu to split a segment
1328 * or a retransmit PDU into two segments splitting at the passed size.
1329 * This function is called only for those PDUs that dont have any LIs.
1331 * @param[in] gCb RLC instance control block
1332 * @param[in] rbCb RB control block
1333 * @param[in,out] crnt The PDU to be split, first part of split pdu remians
1335 * @param[out] next The second part of the split pdu
1336 * @param[in] size The size witin crnt, at which to split
1341 void rlcSplitPdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcRetx *crnt, RlcRetx *next, uint16_t size)
1344 RlcAmDl *amDl = &AMDL;
1346 /* Set the SN for the new segment */
1347 next->amHdr.sn = crnt->amHdr.sn;
1349 /* Set the protocol specific fields appropriately */
1350 si = crnt->amHdr.si;
1351 crnt->amHdr.si = si | RLC_SI_FIRST_SEG;
1352 next->amHdr.si = si | RLC_SI_LAST_SEG;
1356 /* Update seg size */
1357 next->segSz = crnt->segSz - size;
1360 /* Set the SO fields appropriately */
1361 /* MS_FIX for DL stall */
1362 next->soEnd = crnt->soEnd;
1364 /* Set the SO fields appropriately */
1365 /* SO of next will be after the end of current */
1366 next->amHdr.so = crnt->amHdr.so + crnt->segSz;
1367 /* SO End of current will be one less than the start of next */
1368 crnt->soEnd = next->amHdr.so - 1;
1370 /* intialize the other fields in the amHdr of next to 0 */
1374 /* This macro is called for No LI case - one SDU */
1375 /* Update the size of SDU in each node's sduMap */
1376 next->sduMap.sdu = crnt->sduMap.sdu;
1377 crnt->sduMap.sduSz = crnt->segSz;
1378 next->sduMap.sduSz = next->segSz;
1380 /* Segment the payload into two parts based on the size passed */
1381 ODU_SEGMENT_MSG(crnt->seg, size, &next->seg);
1382 next->retxCnt = crnt->retxCnt;
1383 next->yetToConst = TRUE;
1384 next->pendingReTrans = crnt->pendingReTrans;
1386 /* Compute the header size and update the BO appropriately */
1387 if(amDl->snLen == RLC_AM_CFG_12BIT_SN_LEN)
1389 next->hdrSz = RLC_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1390 if(crnt->amHdr.si == RLC_SI_FIRST_SEG)
1392 crnt->hdrSz = RLC_AM_SEG_12BIT_SN_WITHOUT_SO_HDRSZ;
1396 crnt->hdrSz = RLC_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1401 next->hdrSz = RLC_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1402 if(crnt->amHdr.si == RLC_SI_FIRST_SEG)
1404 crnt->hdrSz = RLC_AM_SEG_18BIT_SN_WITHOUT_SO_HDRSZ;
1408 crnt->hdrSz = RLC_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1412 /* Add the next to the retx list */
1413 AMDL.retxLst.crnt = &crnt->lstEnt;
1414 CM_LLIST_INS_AFT_CRNT(AMDL.retxLst, next);
1415 AMDL.nxtRetx = next;
1416 amDl->estHdrSz += next->hdrSz;
1422 * @brief Private handler to retransmit PDUs or PDU segments
1425 * Its a private function called by kwProcessSdus, to create the
1426 * PDUs / its segments from the retransmission buffer available in RbCb.
1428 * - Eliminate the fixed header size and MAC header size while
1429 * forming PDUs/segments
1430 * - While pdusize is available and retxBuf has data (pdu or portion
1431 * of pdu) to be sent, form the pdu as it is if it matches with the
1432 * pdusize else segment the PDUs/portion of PDUs
1433 * - Call rlcAmmDlCheckAndSetPoll function to check and set the poll bit as
1435 * - Concatenate data and header info and fill pduInfo
1436 * - Update retxCnt and send indication to PDCP if it reaches maxRetx
1439 * @param[in] gCb RLC instance control block
1440 * @param[in] rbCb RB control block
1441 * @param[in] kwdatReq DatReq to be sent to MAC
1446 void rlcResegRetxPdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
1450 uint8_t hdr[RLC_MAX_HDRSZ];
1456 RlcL2MeasTb *l2MeasTb;
1457 RlclchInfo *lchInfo;
1463 /* TODO : This shoould be taken care in new Trasmissions */
1464 /* This lchInfo should be retrieved there */
1465 l2MeasTb = rlcUtlGetCurMeasTb(gCb, rbCb);
1466 if (l2MeasTb == NULLP)
1470 /* TODO : This lcid needs to be searched in case of normal Tx */
1471 /* In retx here, its fine as this will be higher priority */
1472 lchInfo = &l2MeasTb->lchInfo[l2MeasTb->numLchInfo];
1473 if (l2MeasTb->numLchInfo >= RLC_MAX_ACTV_DRB)
1477 l2MeasTb->numLchInfo++;
1478 lchInfo->lcId = rbCb->lch.lChId;
1479 lchInfo->numSdus = 0;
1482 while ((rlcDatReq->pduSz > 0) && (amDl->nxtRetx != NULLP)&&
1483 (rlcDatReq->pduInfo.numPdu < RLC_MAX_PDU))
1487 retx = amDl->nxtRetx;
1488 /* kw003.201 : Add header size to seg size to determine if the */
1489 /* the segment can be completed within the allocation */
1490 /* kw003.201 - Eliminate MAC Header Size based on bites needed */
1491 tmpSz = RLC_MIN((retx->segSz + retx->hdrSz), rlcDatReq->pduSz);
1492 pduSz = (retx->segSz + retx->hdrSz);
1493 /* 5GNR_RLC: length field in 5GNR MAC Hdr is 8/16 btis*/
1494 rlcDatReq->pduSz -= (tmpSz < 255) ? RLC_MAC_HDR_SZ2 : RLC_MAC_HDR_SZ3;
1496 /* kw003.201 - We should have at least one more than basic header */
1497 if (rlcDatReq->pduSz <= retx->hdrSz)
1501 rlcGetNxtRetx(gCb, &(amDl->nxtRetx));
1503 /* Send retx buf without segmentation */
1504 if (rlcDatReq->pduSz >= pduSz)
1508 DU_LOG("\nRLC: rlcResegRetxPdus: Send retx buf without segmentation "
1509 "UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1511 if (retx->yetToConst)
1513 /* Construct hdr with the available hdr values */
1514 rlcConstructAmHdr(&retx->amHdr, hdr, amDl->snLen, &idx);
1515 /* Add header to the pdu/segment */
1516 ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx + 1, retx->seg);
1517 retx->yetToConst = FALSE;
1520 /* kw003.201 - Check if poll bit needs to be set. Retx size does */
1521 /* not affect the poll bit so it is being passed as zero */
1522 pollBit = rlcAmmDlCheckAndSetPoll(gCb,rbCb, FALSE, 0);
1523 RLC_UPD_POLL_BIT(gCb, retx, pollBit);
1525 rlcDatReq->pduSz -= pduSz;
1526 AMDL.estHdrSz -= retx->hdrSz;
1529 if (rbCb->rlcId.rbType == CM_LTE_DRB)
1532 for (sduIdx = lchInfo->numSdus ;
1533 ((numSdus < retx->numSdu) && (sduIdx < RLC_L2MEAS_SDUIDX)) ;
1534 sduIdx++, numSdus++)
1536 lchInfo->sduInfo[sduIdx].arvlTime = retx->sduMap[numSdus].sdu->arrTime;
1537 lchInfo->sduInfo[sduIdx].isRetxPdu = TRUE; /* TODO : for later use */
1539 lchInfo->numSdus += numSdus;
1547 /* Segment this pdu / portion of pdu. Insert this segment into */
1548 /* retxLst and update offset */
1549 DU_LOG("\nRLC: rlcResegRetxPdus: Segment retx buf UEID:%d CELLID:%d",
1550 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1552 /* Eliminate fixed header size if the pdu is segmented for the */
1554 if(amDl->snLen == RLC_AM_CFG_12BIT_SN_LEN)
1556 if(retx->amHdr.si < RLC_SI_LAST_SEG)
1558 rlcDatReq->pduSz -= RLC_AM_SEG_12BIT_SN_WITHOUT_SO_HDRSZ;
1562 rlcDatReq->pduSz -= RLC_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1567 if(retx->amHdr.si < RLC_SI_LAST_SEG)
1569 rlcDatReq->pduSz -= RLC_AM_SEG_18BIT_SN_WITHOUT_SO_HDRSZ;
1573 rlcDatReq->pduSz -= RLC_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1576 if (rlcDatReq->pduSz <= 0)
1581 /* Allocate memory for tracking a new segment */
1582 RLC_ALLOC_WC(gCb,tNode, sizeof(RlcRetx));
1583 #if (ERRCLASS & ERRCLS_ADD_RES)
1586 DU_LOG("\nRLC: rlcResegRetxPdus: Memory allocation failed UEID:%d CELLID:%d",
1587 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1590 #endif /* ERRCLASS & ERRCLS_RES */
1592 /* initialize the list pointer to 0 instead of memset */
1593 tNode->lstEnt.next = 0;
1594 tNode->lstEnt.prev = 0;
1596 /* Segment header and data */
1597 RLC_AM_RMV_HDR(gCb, rbCb, retx);
1599 /* kw003.201 - Split the payload and update other fields */
1600 rlcSplitPdu(gCb,rbCb, retx, tNode, rlcDatReq->pduSz);
1605 sduIdx = lchInfo->numSdus;
1606 for (numSdus = 0, sduIdx = lchInfo->numSdus;
1607 ((numSdus < retx->numSdu) && (sduIdx < RLC_L2MEAS_SDUIDX));
1608 numSdus++, sduIdx++)
1610 lchInfo->sduInfo[sduIdx].arvlTime =
1611 retx->sduMap[numSdus].sdu->arrTime;
1612 lchInfo->sduInfo[sduIdx].isRetxPdu = TRUE;
1614 lchInfo->numSdus = sduIdx;
1615 if ((retx->amHdr.lsf == 0) && (lchInfo->numSdus > 0))
1620 /* Construct hdr with the available hdr values */
1621 rlcConstructAmHdr(&retx->amHdr, hdr, amDl->snLen, &idx);
1622 ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx + 1, retx->seg);
1624 retx->hdrSz = idx + 1;
1626 /* Poll bit need not be set for this seg, since its second */
1627 /* half remains in retxLst */
1628 RLC_UPD_POLL_BIT(gCb, retx, FALSE);
1629 retx->yetToConst = FALSE;
1630 rlcDatReq->pduSz = 0;
1633 rlcCpyMsg(gCb,retx->seg, &pdu);
1635 /* Update pduInfo */
1636 rlcDatReq->pduInfo.mBuf[rlcDatReq->pduInfo.numPdu] = pdu;
1637 rlcDatReq->pduInfo.numPdu++;
1638 /* kw005.201 ccpu00117318, updating the statistics */
1639 gCb->genSts.pdusRetx += 1;
1640 gRlcStats.amRlcStats.numRlcAmCellRetxPdu++;
1641 retx->soEnd = retx->amHdr.so + retx->segSz - 1;
1642 retx->pendingReTrans = FALSE;
1643 amDl->retxBo -= retx->segSz;
1646 DU_LOG("\nRLC: rlcResegRetxPdus: retxBo after resegmentation = %ld"
1647 "UEID:%d CELLID:%d", amDl->retxBo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1649 DU_LOG("\nRLC: rlcResegRetxPdus: retxBo after resegmentation = %d "
1650 "UEID:%d CELLID:%d", amDl->retxBo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1658 * @brief Private handler to assemble SDUs to form new data PDU(s)
1661 * Its a private function called by kwProcessSdus, to create the new data
1662 * PDUs from the SDU queue of RbCb.
1664 * - While pdusize is available, segment/concatenate SDUs or else if it
1665 * matches the pdu size form PDUs accordingly.
1666 * - RLC header and MAC header size are eliminated while forming the PDUs
1667 * - Call rlcAmmDlCheckAndSetPoll function to check and set the poll bit
1669 * - Concatenate data and header info and fill pduInfo
1671 * @param[in] rbCb RB control block
1672 * @param[in] kwdatReq DatReq to be sent to MAC
1677 void rlcAssembleSdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
1679 Buffer *pdu = NULLP;
1680 MsgLen macGrntSz = rlcDatReq->pduSz;
1681 RlcAmDl *amDl = &AMDL;
1682 RlcSdu *sdu = amDl->nxtTx;
1684 bool nxtTxUpd = FALSE;
1685 KwuDiscSduInfo *discSduInfo = NULLP;
1686 RlcKwuSapCb* rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
1688 RlcContSduLst contSduLst; /*Contained sduLst */
1689 int32_t dataVol = amDl->bo;
1690 uint32_t *totMacGrant = &rlcDatReq->totMacGrant;
1691 RlcL2MeasDlIpTh *dlIpThPut = &rbCb->l2MeasIpThruput.dlIpTh;
1692 uint8_t *sduIdx = &dlIpThPut->lastSduIdx;
1694 bool isSduSegmented;
1697 RlclchInfo *dstLchInfo;
1698 uint32_t segSduCnt = 0;
1700 uint32_t numSdus = 0;
1701 uint32_t currSduIdx = 0;
1702 RlcL2MeasTb *l2MeasTb;
1704 /* Discard new changes starts */
1707 uint8_t numNewPdu = 0;
1708 RlcTx *txBuf = NULLP;
1709 /* Discard new changes ends */
1710 VOLATILE uint32_t startTime = 0;
1712 uint32_t fixedHdrSz;
1714 RlcAmHdr *amHdr = NULLP;
1715 RlcDlPduInfo *pduInfo = NULLP;
1718 contSduLst.numSdus = 0;
1719 contSduLst.lcId = rbCb->lch.lChId;
1721 lchInfo.lcId = rbCb->lch.lChId;
1722 lchInfo.numSdus = 0;
1724 /* Discard new changes starts */
1725 /* Allocate memory for discSdu Info */
1726 RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region,
1727 rlckwuSap->pst.pool,
1729 sizeof(KwuDiscSduInfo));
1731 #if (ERRCLASS & ERRCLS_ADD_RES)
1732 if (discSduInfo == NULLP)
1734 DU_LOG("\nRLC: rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1735 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1738 #endif /* ERRCLASS & ERRCLS_RES */
1740 discSduInfo->numSduIds = 0;
1741 discSduInfo->rlcId = rbCb->rlcId;
1743 rlcUtlGetCurrTime(&curTime);
1744 amDl->sduQ.crnt = &sdu->lstEnt;
1745 /* Eliminate fixed header size */
1746 /*5GNR: value of RLC_AM_PDU_FIXED_HDRSZ will be 2 or 3 depending on SN Size*/
1747 if(amDl->snLen == RLC_AM_CFG_12BIT_SN_LEN)
1749 fixedHdrSz = RLC_AM_PDU_12BIT_SN_HDRSZ;
1753 fixedHdrSz = RLC_AM_PDU_18BIT_SN_HDRSZ;
1756 while ((macGrntSz > fixedHdrSz) && (sdu != NULLP) &&
1757 (rlcDatReq->pduInfo.numPdu < RLC_MAX_PDU) &&
1758 (numNewPdu < RLC_MAX_NEW_DL_PDU))
1761 isSduSegmented = sdu->mode.am.isSegmented;
1763 /* Discard new changes starts */
1764 if ((sdu->mode.am.isSegmented == FALSE) && (rbCb->discTmrInt > 0) && \
1765 (rbCb->rlcId.rbType == CM_LTE_DRB))
1767 //leftAmSdus[rbCb->qci]--;
1768 timeDiff = RLC_TIME_DIFF(curTime,sdu->arrTime);
1769 if (timeDiff > rbCb->discTmrInt)
1773 SStartTask(&startTime, PID_RLC_AMM_DISC_SDUS);
1775 RLC_UPD_L2_DL_DISC_SDU_STS(gCb,rbCb);
1776 /* TODO need to send disc cfm to pdcp */
1778 /* Update bo for boReport */
1779 amDl->bo -= sdu->sduSz;
1781 /* Get next sdu for assembly */
1782 nxtNode = sdu->lstEnt.next;
1784 /* store the info for sending it to PDCP */
1785 if(discSduInfo->numSduIds > 500)
1787 DU_LOG("\nRLC: rlcAssembleSdus: This is a big error, we shouldn't be here"
1788 "UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1792 discSduInfo->sduIds[discSduInfo->numSduIds] = sdu->mode.am.sduId;
1793 discSduInfo->numSduIds++;
1795 cmLListDelFrm(&amDl->sduQ, &sdu->lstEnt);
1797 rlcUtlAddSduToBeFreedQueue(gCb, sdu);
1798 rlcUtlRaiseDlCleanupEvent(gCb);
1800 /* We need to restore the crnt in the linked list which
1801 * would have become NULL in the DelFrm above */
1802 amDl->sduQ.crnt = nxtNode;
1805 sdu = (RlcSdu*)nxtNode->node;
1810 ODU_STOP_TASK(startTime, PID_RLC_AMM_DISC_SDUS);
1819 /** kw003.201 - Check for window stall when you are
1820 * creating a new PDU
1822 if (RLC_AM_IS_TRANS_WIN_STALLED(amDl))
1825 printf("\n Window stalled \n");
1826 gRlcStats.amRlcStats.numRlcAmCellWinStall++;
1831 hdrEstmt = fixedHdrSz;
1833 if (sdu->mode.am.isSegmented)
1835 /* Adding two byte for SO */
1838 /* Eliminate MAC header */
1839 /* ccpu00135743 : Fix for MAC Hdr size calculation */
1840 /*5GNR: value of mac hdr length field changed to 8/16bits */
1841 pduSz = RLC_MIN(macGrntSz, (sdu->sduSz + hdrEstmt));
1842 hdrEstmt += (pduSz < 255) ? RLC_MAC_HDR_SZ2 : RLC_MAC_HDR_SZ3;
1844 macGrntSz -= hdrEstmt;
1845 /* kw005.201 Check for PDU Size is large enough.
1846 * Fix for ccpu00118973
1853 /* Dont create new txBuf for segmented SDU */
1854 if (!sdu->mode.am.isSegmented)
1857 RLC_ALLOC_WC(gCb,txBuf, sizeof(RlcTx));
1859 cmLListInit(&txBuf->pduLst);
1861 #if (ERRCLASS & ERRCLS_ADD_RES)
1864 uint32_t avblMem = 0;
1865 SRegInfoShow(gCb->init.region, &avblMem);
1866 DU_LOG("\nRLC: rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1867 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1870 #endif /* ERRCLASS & ERRCLS_RES */
1872 rlcUtlStoreTxBuf(amDl->txBufLst, txBuf, amDl->txNext);
1876 txBuf = rlcUtlGetTxBuf(amDl->txBufLst, amDl->txNext);
1879 RLC_ALLOC_WC(gCb,pduInfo, sizeof(RlcDlPduInfo));
1880 #if (ERRCLASS & ERRCLS_ADD_RES)
1881 if (pduInfo == NULLP)
1883 uint32_t avblMem = 0;
1884 SRegInfoShow(gCb->init.region, &avblMem);
1885 DU_LOG("\nRLC: rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1886 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1889 #endif /* ERRCLASS & ERRCLS_RES */
1891 /*Initialize DL segment structure */
1892 pduInfo->lstEnt.next = NULLP;
1893 pduInfo->lstEnt.prev = NULLP;
1894 pduInfo->lstEnt.node = NULLP;
1896 pduInfo->pdu = NULLP;
1897 pduInfo->amHdr.dc = 0;
1898 pduInfo->amHdr.p = 0;
1899 pduInfo->amHdr.si = 0;
1900 pduInfo->amHdr.so = 0;
1902 pduInfo->amHdr.sn = amDl->txNext;
1904 if (macGrntSz >= sdu->sduSz)
1908 /* Update Framing Info */
1909 if (sdu->mode.am.isSegmented)
1911 /*5GNR RLC: SN should be same for all segment of a SDU*/
1912 pduInfo->amHdr.sn = sdu->mode.am.sn;
1913 pduInfo->amHdr.si = RLC_SI_LAST_SEG; /* binary 10 */
1914 pduInfo->amHdr.so = sdu->actSz - sdu->sduSz;
1915 sdu->mode.am.isSegmented = FALSE;
1918 gRlcStats.amRlcStats.numRlcAmCellSduTx++;
1919 //printf("\n 5GNRLOG: last segment of lcId %d SduId %u So %u macGrntSz %u sduActSz %u sdu->sduSz %u\n",
1920 // rbCb->lch.lChId, sdu->mode.am.sduId, pduInfo->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
1924 gRlcStats.amRlcStats.numRlcAmCellSduTx++;
1926 amHdr = &pduInfo->amHdr;
1927 /* Create PDU with hdr and data */
1928 rlcAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
1930 //printf("\n Segmentation not required case: numPdu %d pdu %p \n",rlcDatReq->pduInfo.numPdu, pdu);
1932 #ifdef LTE_L2_MEAS_RLC
1933 rlcUtlUpdSduSnMap(rbCb, sdu, rlcDatReq, TRUE);
1934 #endif /* LTE_L2_MEAS */
1936 /* kw005.201 ccpu00117318, updating the statistics */
1937 rlcUtlIncrementKwuStsSduTx(gCb->u.dlCb->rlcKwuDlSap + rbCb->k1wuSapId);
1939 if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb))
1943 *sduIdx = dlIpThPut->lastSduIdx;
1947 RLC_GETSDUIDX(*sduIdx);
1950 rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
1951 rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
1952 sdu->mode.am.sduId, newIdx);
1953 /* Update the arrival time for each SDU */
1955 if ( lchInfo.numSdus < RLC_L2MEAS_SDUIDX)
1957 lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime;
1962 sduMap.sduSz = sdu->sduSz;
1967 * Allocate buffer for next PDU
1968 * Remove the segmented portion from SDUQ
1969 * Calculate the hdr with LI for SDU */
1971 Buffer *remSeg = NULLP;
1973 //printf("\n SDU segmentation case: numPdu %d pdu %p \n", rlcDatReq->pduInfo.numPdu, pdu);
1975 if(RLC_MEAS_IS_DL_IP_MEAS_ON_FOR_RB(gCb,rbCb) ||
1976 RLC_MEAS_IS_DL_DELAY_MEAS_ON_FOR_RB(gCb,rbCb) ||
1977 RLC_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb) )
1979 /* If actual size of the sdu is equal to msgLen
1980 * then it is first segment of the SDU */
1981 if(sdu->actSz == sdu->sduSz)
1983 RLC_GETSDUIDX(*sduIdx);
1988 *sduIdx = dlIpThPut->lastSduIdx;
1990 rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
1991 rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
1992 sdu->mode.am.sduId, newIdx);
1993 if(RLC_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb))
1995 /* If actual size of the sdu is equal to msgLen
1996 * then it is first segment of the SDU */
1997 if(sdu->actSz == sdu->sduSz)
2005 /* Segment the SDU to the size of the PDU and update header Info */
2006 ODU_SEGMENT_MSG(sdu->mBuf, macGrntSz, &remSeg);
2010 /* Update SI and SN */
2011 if (sdu->mode.am.isSegmented)
2013 /*5GNR RLC: SN should be same for all segment of a SDU.
2014 * Sdu was already segmented and segmenting again*/
2015 pduInfo->amHdr.sn = sdu->mode.am.sn;
2016 pduInfo->amHdr.si = RLC_SI_MID_SEG; /* binary 11 */
2017 pduInfo->amHdr.so = sdu->actSz - sdu->sduSz;
2019 //printf("\n 5GNRLOG: mid segment of lcId %d SduId %u So %u macGrntSz %u sduActSz %u sdu->sduSz %u\n",
2020 // rbCb->lch.lChId, sdu->mode.am.sduId, txBuf->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
2024 /*5GNR RLC: This means it is the first*/
2025 pduInfo->amHdr.si = RLC_SI_FIRST_SEG; /* binary 01 */
2026 /*5GNR_RLC: Store SN so that in sub-seqent SDU segments will use this SN*/
2027 sdu->mode.am.sn = pduInfo->amHdr.sn;
2028 pduInfo->amHdr.so = 0;
2030 //printf("\n 5GNRLOG: First segment of lcId %d SduId %u So %u macGrntSz %u sduActSz %u sdu->sduSz %u\n",
2031 // rbCb->lch.lChId, sdu->mode.am.sduId, txBuf->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
2034 amHdr = &pduInfo->amHdr;
2035 /* Create PDU with hdr and data */
2036 rlcAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
2038 sdu->mode.am.isSegmented = TRUE;
2039 sdu->sduSz -= macGrntSz;
2040 sduMap.sduSz = macGrntSz;
2042 #ifdef LTE_L2_MEAS_RLC
2043 rlcUtlUpdSduSnMap(rbCb, sdu, rlcDatReq, FALSE);
2044 #endif /* LTE_L2_MEAS */
2050 /* Update bo for boReport */
2051 amDl->bo -= sduMap.sduSz;
2055 /* Update pduInfo */
2056 rlcDatReq->pduInfo.mBuf[rlcDatReq->pduInfo.numPdu] = pdu;
2057 rlcDatReq->pduInfo.numPdu++;
2059 /* kw005.201 ccpu00117318, updating the statistics */
2060 gCb->genSts.pdusSent++;
2061 gRlcStats.amRlcStats.numRlcAmCellSduBytesTx = gRlcStats.amRlcStats.numRlcAmCellSduBytesTx + sduMap.sduSz;
2062 /* Update the RLC Tx buffer with the new PDU info */
2063 RLC_MEM_CPY(&pduInfo->sduMap, &sduMap, sizeof(RlcSduMap));
2066 macGrntSz -= sduMap.sduSz;
2067 /* Get next sdu for assembly */
2068 RLC_LLIST_NEXT_SDU(amDl->sduQ, sdu);
2070 } /*End of pduSz loop */
2072 rlcDatReq->pduSz = macGrntSz;
2073 /* Updating nxtTx to sdu in the Q */
2078 if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) &&
2079 (rbCb->rlcId.rbType == CM_LTE_DRB))
2083 l2MeasTb = rlcUtlGetCurMeasTb(gCb, rbCb);
2084 rlcUtlUpdateBurstSdus(gCb, rbCb, &contSduLst, dataVol, *totMacGrant);
2085 if ((lchInfo.numSdus != 0) && (l2MeasTb != NULLP))
2087 for (lchIdx = 0; ((lchIdx < l2MeasTb->numLchInfo)
2088 && (lchIdx < RLC_MAX_ACTV_DRB )); lchIdx++)
2090 if (l2MeasTb->lchInfo[lchIdx].lcId == rbCb->lch.lChId)
2092 /* Lch Info already added in Retx procedure */
2096 if (lchIdx < RLC_MAX_ACTV_DRB)
2098 if (lchIdx == l2MeasTb->numLchInfo)
2100 l2MeasTb->lchInfo[lchIdx].lcId = rbCb->lch.lChId;
2101 l2MeasTb->lchInfo[lchIdx].numSdus = 0;
2102 l2MeasTb->numLchInfo++;
2104 dstLchInfo = &l2MeasTb->lchInfo[lchIdx];
2105 currSduIdx = l2MeasTb->lchInfo[lchIdx].numSdus;
2106 while ((numSdus < lchInfo.numSdus) && (currSduIdx < RLC_L2MEAS_SDUIDX))
2108 dstLchInfo->sduInfo[currSduIdx].arvlTime = lchInfo.sduInfo[numSdus].arvlTime;
2109 dstLchInfo->sduInfo[currSduIdx].isRetxPdu = FALSE;
2113 l2MeasTb->lchInfo[lchIdx].numSdus += numSdus;
2116 /* Fix Klock warning */
2117 if(l2MeasTb != NULLP)
2119 l2MeasTb->txSegSduCnt += segSduCnt;
2122 *totMacGrant -= (oldBo - amDl->bo);
2125 if(discSduInfo->numSduIds != 0)
2127 /* Sap control block */
2128 RlcUiKwuDiscSduCfm(&rlckwuSap->pst, rlckwuSap->suId, discSduInfo);
2132 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, discSduInfo, sizeof(KwuDiscSduInfo));
2136 DU_LOG("\nRLC: rlcAssembleSdus: BO after assembly = %d UEID:%d CELLID:%d",
2137 amDl->bo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
2143 * @brief Private handler to check if the poll bit needs to be set for data PDU
2146 * Its a private function called by kwProcessSdus, to checks if the
2147 * polling bit needs to be set for any RLC data PDU and updates the
2149 * - For the new PDUs, if the counters exceed the configured
2150 * pduWoPoll/byteWoPoll values, return poll bit.
2151 * - For the PDUs/portion of PDUs, if the SDU list / retxBuf is
2152 * empty, return poll bit.
2153 * - Update the pollPdu, pollByte counters and Poll_SN; start staProhTmr
2155 * @param[in] rCb RLC instance control block
2156 * @param[in] rbCb RB control block
2157 * @param[in] newPdu Flag to indicate if its a new AMD PDU.
2158 * @param[in] bufSz Length of the PDU
2161 * -# 1 - To set the poll bit
2162 * -# 0 - Poll bit is not set
2165 bool rlcAmmDlCheckAndSetPoll(RlcCb *gCb, RlcDlRbCb *rbCb, bool newPdu, MsgLen bufSz)
2167 bool pollBit = FALSE;
2168 RlcAmDl *amDl = &(rbCb->m.amDl);
2170 /* If it's a new PDU increment PDU without poll and bytes without poll
2171 and check if they cross the configured number of poll pdu and poll bytes*/
2175 /* Patch kw004.201 */
2176 amDl->byteWoPoll += bufSz;
2178 if (((amDl->pollPdu != -1) && (amDl->pduWoPoll >= amDl->pollPdu)) ||
2179 ((amDl->pollByte != -1) && (amDl->byteWoPoll >= amDl->pollByte)))
2185 /* Check if both tx/retx buffer are empty or if tx window is stalled */
2186 if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) ||
2187 RLC_AM_IS_TRANS_WIN_STALLED(amDl))
2194 amDl->pduWoPoll = 0;
2195 amDl->byteWoPoll = 0;
2197 amDl->pollSn = (amDl->txNext - 1) & amDl->snModMask;
2199 DU_LOG("\nRLC: rlcAmmDlCheckAndSetPoll: Poll SN = %d UEID:%d CELLID:%d",
2200 amDl->pollSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
2202 /* kw005.201: Fix for poll retransmission timer.
2203 * Timer is stopped if it is already running and
2204 * then starting the timer. Fixes crs
2205 * ccpu00117216 and ccpu00118284 .
2207 if( TRUE == rlcChkTmr(gCb,(PTR)rbCb,RLC_EVT_AMDL_POLL_RETX_TMR) )
2209 rlcStopTmr(gCb,(PTR)rbCb, RLC_EVT_AMDL_POLL_RETX_TMR);
2212 rlcStartTmr(gCb,(PTR)rbCb, RLC_EVT_AMDL_POLL_RETX_TMR);
2219 * @brief Private handler to create AMD PDU
2222 * This function constructs header and concatenate it with the data for
2223 * the PDU. It also updates the txBuf with the created PDU.
2225 * @param[in] gCB RLC instance control block
2226 * @param[in] rbCb Downlink RB control block
2227 * @param[in] amHdr AM header
2228 * @param[in] RlcDlPduInfo Pointer to PduInfo
2229 * @param[in] pdu PDU buffer
2234 void rlcAmmCreatePdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcAmHdr *amHdr,
2235 RlcDlPduInfo *pduInfo, Buffer *pdu)
2237 uint8_t hdr[RLC_MAX_HDRSZ];
2241 RlcAmDl *amDl = &(rbCb->m.amDl);
2244 amHdr->sn = amDl->txNext;
2246 /*5GNR RLC: Increment txNext only if no segmentation of it is a last segment */
2247 if((!amHdr->si) || (amHdr->si == RLC_SI_LAST_SEG))
2249 //printf("\n 5GNRLOG: no segment/last seg SDU with lcId %d Sn %u txNext %u So %u\n",
2250 // rbCb->lch.lChId, amHdr->sn, amDl->txNext, amHdr->so);
2251 amDl->txNext = (amDl->txNext + 1) & amDl->snModMask;
2254 /* Update hdr Info */
2255 ODU_GET_MSG_LEN(pdu, &pduSz);
2257 /* passing newPDU = TRUE*/
2258 amHdr->p = rlcAmmDlCheckAndSetPoll(gCb,rbCb, TRUE, pduSz);
2260 /* Construct header with the available hdr Info, set isSegment to FALSE */
2261 rlcConstructAmHdr(amHdr, hdr, amDl->snLen, &idx);
2263 /* Concatenate hdr and data */
2264 ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx+1, pdu);
2266 txBuf = rlcUtlGetTxBuf(amDl->txBufLst, amHdr->sn);
2267 rlcCpyMsg(gCb,pdu,&(pduInfo->pdu));
2268 pduInfo->pduSz = pduSz;
2269 pduInfo->hdrSz = idx+1;
2271 /*Update estHdrSz. deduct current hdrSz */
2272 amDl->estHdrSz -= pduInfo->hdrSz;
2273 /* Reestimate estHdrSz for mid and last seg */
2276 amDl->estHdrSz += ((amHdr->si == RLC_SI_MID_SEG)? pduInfo->hdrSz : (pduInfo->hdrSz + 2));
2279 cmLListAdd2Tail(&txBuf->pduLst, &pduInfo->lstEnt);
2280 pduInfo->lstEnt.node = (PTR)pduInfo;
2282 gCb->genSts.bytesSent += pduSz;
2288 * @brief Private handler to remove the retx PDU from the rbCb
2291 * This function releases a retx PDU stored on DL portion of rbCb.
2292 * It also updates the BO if wtForAck flag is not set which implies
2293 * that it is not sent out yet.
2295 * @param[in] gCb RLC instance control block
2296 * @param[in] retx retransmit PDU to be removed
2297 * @param[in] rbCb Radio Bearer Control Block
2303 PRIVATE Void rlcRemRetxPdu
2310 PRIVATE Void rlcRemRetxPdu(gCb, rbCb, retx)
2318 cmLListDelFrm(&AMDL.retxLst, &retx->lstEnt);
2320 if( AMDL.retxLst.count == 0)
2322 AMDL.nxtRetx = NULLP;
2325 if(retx->pendingReTrans == TRUE)
2327 AMDL.retxBo -= retx->segSz;
2328 AMDL.estHdrSz -= retx->hdrSz;
2331 rlcUtlAddReTxPduToBeFreedQueue(gCb, retx);
2332 rlcUtlRaiseDlCleanupEvent(gCb);
2338 * @brief Private handler to mark a retx PDU for further retransmission
2341 * This function sets a retx PDU that has not been ACKed in the
2342 * received Status PDU for futher retransmission. If the retransmission
2343 * limit is reached, it releases the retx PDU and informs the higher
2344 * layers about the same.
2346 * @param[in] gCb RLC instance control block
2347 * @param[in] retx retransmit PDU to be removed
2348 * @param[in] rbCb Radio Bearer Control Block
2354 PRIVATE Void rlcAmmDlMarkPduForReTx
2361 PRIVATE Void rlcAmmDlMarkPduForReTx(*gCb, rbCb, retx)
2367 TRC2(rlcAmmDlMarkPduForReTx)
2368 if (AMDL.maxReTxReached == TRUE)
2373 if(retx->pendingReTrans == FALSE)
2375 retx->pendingReTrans = TRUE;
2378 AMDL.retxBo += retx->segSz;
2379 AMDL.estHdrSz += retx->hdrSz;
2381 if (retx->retxCnt > AMDL.maxRetx)
2383 /* RLC_DL_MAX_RETX fix */
2384 /* Marking the RB stalled for DL scheduling. This is to avoid unnecessary */
2385 /* preparation of RLC PDUs and adding the same to Tx Buffer */
2386 /* This condition is to avoid sending StaIndication more than once */
2387 if (TRUE != rbCb->m.amDl.maxReTxReached)
2389 rbCb->m.amDl.maxReTxReached = TRUE;
2390 rbCb->m.amDl.bo = 0;
2391 rbCb->m.amDl.cntrlBo = 0;
2392 rbCb->m.amDl.retxBo = 0;
2393 /* Sending BO update to SCH */
2394 rlcUtlSendDedLcBoStatus(gCb, rbCb, 0,0,0,0);
2395 rlcAmmSndStaInd(gCb, rbCb, retx);
2396 gRlcStats.amRlcStats.numDLMaxRetx++;
2399 rlcRemRetxPdu(gCb,rbCb, retx);
2405 if (AMDL.nxtRetx == NULLP)
2407 AMDL.nxtRetx = retx;
2410 gRlcStats.amRlcStats.numDLRetransPdus++;
2418 * @brief Private handler to check if SDU is completely deliverd and
2419 * send higher layers data confirmation
2422 * This function sends higher layers data confirmation for SDUs which
2423 * have been successfully delivered to the peer RLC entity.
2425 * @param[in] gCb RLC instance control block
2426 * @param[in] rbCb Radio Bearer Control Block
2427 * @param[in] sduLst List of SDUs that were part of the PDU
2428 * @param[in] numSdu Number of SDUs in the list
2434 PRIVATE Void rlcAmmDlCheckIsSDUDelivered
2439 KwuDatCfmInfo **datCfm
2442 PRIVATE Void rlcAmmDlCheckIsSDUDelivered(gCb, rbCb, sduMap, datCfm)
2446 KwuDatCfmInfo **datCfm;
2451 TRC2(rlcAmmDlCheckIsSDUDelivered)
2455 sdu->mode.am.rcvdSz += sduMap->sduSz;
2457 /* send a dat cfm if all the bytes of the sdu have been received */
2458 if (sdu->mode.am.rcvdSz == sdu->actSz)
2460 /* Send DatCfm for this sdu */
2461 if((*datCfm)->numSduIds < KWU_MAX_DAT_CFM)
2463 (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2467 /* This is an error that should never happen, we should resize
2468 * the #define to a larger value or check why we need to
2469 * send so many confirms in one go
2470 * Confrims to PDCP are being dropped in this case
2472 RlcKwuSapCb *rlckwuSap;
2473 rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
2474 RlcUiKwuDatCfm(&rlckwuSap->pst, rlckwuSap->suId, *datCfm);
2476 RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, *datCfm, sizeof(KwuDatCfmInfo));
2478 #if (ERRCLASS & ERRCLS_ADD_RES)
2479 if (*datCfm == NULLP)
2481 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
2482 "Memory allocation failed UEID:%d CELLID:%d",
2484 rbCb->rlcId.cellId);
2487 #endif /* ERRCLASS & ERRCLS_RES */
2489 (*datCfm)->numSduIds = 0;
2490 (*datCfm)->rlcId = rbCb->rlcId;
2491 /* ccpu00135618: say total 1026 sduIds to copy the 1025 sduId after
2492 * new allocation of datCfm */
2493 (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2496 /* Remove SDU from the sduQ */
2497 cmLListDelFrm(&AMDL.sduQ, &sdu->lstEnt);
2498 rlcUtlAddSduToBeFreedQueue(gCb, sdu);
2499 rlcUtlRaiseDlCleanupEvent(gCb);
2506 * @brief Private handler to mark a PDU successful.
2509 * This function is called when we receive a STATUS pdu that marks
2510 * a PDU as successful. It releases the PDU from RLC entity and
2511 * informs PDCP of successful SDUs delivered as a result of this PDU.
2513 * @param[in] gCb RLC instance control block
2514 * @param[in] rbCb Radio Bearer Control Block
2515 * @param[in] sn SN that is successfully delivered to the peer
2521 PRIVATE Void rlcAmmDlProcessSuccessfulTxPdu
2526 KwuDatCfmInfo **datCfm
2529 PRIVATE Void rlcAmmDlProcessSuccessfulTxPdu(gCb, rbCb, sn, datCfm)
2533 KwuDatCfmInfo **datCfm;
2536 TRC2(rlcAmmDlProcessSuccessfulTxPdu)
2539 RlcTx *txBuf = rlcUtlGetTxBuf(AMDL.txBufLst, sn);
2545 pduNode = txBuf->pduLst.first;
2548 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(pduNode->node);
2549 rlcAmmDlCheckIsSDUDelivered(gCb,
2553 pduNode = pduNode->next;
2556 rlcUtlAddTxPduToBeFreedQueue(gCb, txBuf);
2557 rlcUtlRaiseDlCleanupEvent(gCb);
2558 /* so that it is not processed again */
2559 rlcUtlRemovTxBuf(AMDL.txBufLst, txBuf, gCb);
2565 * @brief Handler to send Status Indication to PDCP
2568 * This function is used to send status indication to PDCP when the
2569 * maximum retransmission threshold value is reached for a PDU.
2571 * @param[in] gCb RLC instance control block
2572 * @param[in] rbCb RB control block
2573 * @param[in] retx The PDU/segment that failed max re-transmissions
2579 PRIVATE Void rlcAmmSndStaInd
2586 PRIVATE Void rlcAmmSndStaInd(gCb, rbCb, retx)
2592 KwuStaIndInfo *staInd;
2593 RlcKwuSapCb *rlckwuSap;
2595 TRC2(rlcAmmSndStaInd);
2598 /* Sap control block */
2599 rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
2601 /* Allocate memory for staInd Info */
2602 RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, staInd, sizeof(KwuStaIndInfo));
2604 #if (ERRCLASS & ERRCLS_ADD_RES)
2605 if (staInd == NULLP)
2607 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
2608 "Memory allocation failed UEID:%d CELLID:%d",
2610 rbCb->rlcId.cellId);
2613 #endif /* ERRCLASS & ERRCLS_RES */
2615 /* Fill staInd Info */
2616 RLC_MEM_CPY(&staInd->rlcId, &rbCb->rlcId, sizeof(CmLteRlcId));
2619 staInd->sduId[0] = retx->sduMap.sdu->mode.am.sduId;
2623 RlcUiKwuStaInd(&rlckwuSap->pst, rlckwuSap->suId, staInd);
2624 #endif /* KW_PDCP */
2630 * @brief Handler to get the next node to be retransmitted from retxLst
2633 * This function is used to get the next node to be retransmitted
2636 * @param[in] gCb RLC instance control block
2637 * @param[in] retx The PDU/segment after which to find a node to be
2643 void rlcGetNxtRetx(RlcCb *gCb, RlcRetx **retx)
2649 tNode = &((*retx)->lstEnt);
2650 tNode = tNode->next;
2654 *retx = (RlcRetx *)tNode->node;
2661 }while((*retx)->pendingReTrans == FALSE);
2667 * @brief Handler to process the re-establishment request received from UIM
2669 * @param[in] gCb RLC instance control block
2670 * @param[in] rlcId Identity of the RB in the UE/Cell for which
2671 * re-establishment is to be done
2672 * @param[in] rbCb Downlink RB control block (rbCb is freed in this
2679 Void rlcAmmDlReEstablish
2686 Void rlcAmmDlReEstablish(gCb, rlcId, rbCb)
2692 /* create a new AM DL RB, reset it and replace in the UeCb*/
2697 RLC_ALLOC(gCb, resetRb, sizeof(RlcDlRbCb));
2699 /* ccpu00135170 Removing KLOCK warning */
2700 if(resetRb == NULLP)
2705 RLC_MEM_CPY(resetRb, rbCb, sizeof(RlcDlRbCb));
2706 RLC_MEM_SET(&resetRb->m.amDl, 0 , sizeof(RlcAmDl));
2708 /* AGHOSH changes start */
2709 /* restore the old AM values */
2710 newAmDl = &resetRb->m.amDl;
2711 oldAmDl = &rbCb->m.amDl;
2713 newAmDl->pollPdu = oldAmDl->pollPdu;
2714 newAmDl->pollByte = oldAmDl->pollByte;
2715 newAmDl->maxRetx = oldAmDl->maxRetx;
2716 newAmDl->snLen = oldAmDl->snLen;
2717 newAmDl->snModMask = oldAmDl->snModMask;
2718 newAmDl->pollRetxTmrInt = oldAmDl->pollRetxTmrInt;
2719 rbCb->boUnRprtdCnt = (U32)0;
2720 rbCb->lastRprtdBoToMac = (U32)0;
2721 cmInitTimers(&(resetRb->m.amDl.pollRetxTmr), 1);
2722 /* AGHOSH changes end */
2724 if (ROK != rlcDbmFetchDlUeCb(gCb,rlcId.ueId, rlcId.cellId, &ueCb))
2726 RLOG_ARG2(L_ERROR,DBG_CELLID, rlcId.cellId,
2727 "UeId [%d]: UeCb not found RBID;%d",
2733 if(rlcId.rbType == CM_LTE_SRB)
2735 ueCb->srbCb[rlcId.rbId] = resetRb;
2739 ueCb->drbCb[rlcId.rbId] = resetRb;
2741 /* update into the logical channel array also */
2742 ueCb->lCh[rbCb->lch.lChId - 1].dlRbCb = resetRb;
2744 if((resetRb->rlcId.rbType == CM_LTE_SRB)
2745 &&(resetRb->rlcId.rbId == 1))
2747 /* To stop the traffic on SRB2 and other DRBs*/
2748 rlcDlUtlSetReestInProgressForAllRBs(gCb, ueCb);
2752 rlcDlUtlSetReestInProgressForRB(gCb, resetRb);
2755 /* allocate the TX array again */
2759 resetRb->m.amDl.txBufLst,
2760 (RLC_TX_BUF_BIN_SIZE * sizeof(CmLListCp)));
2761 for(hashIndex = 0; hashIndex < RLC_TX_BUF_BIN_SIZE; hashIndex++)
2763 cmLListInit(&(resetRb->m.amDl.txBufLst[hashIndex]));
2766 /* send the old rb of deletion */
2767 rlcAmmFreeDlRbCb(gCb,rbCb);
2770 /* TODO: for now we are re-settting the re-establishment flag here
2771 this needs to be fixed
2772 There should be a proper intreface to resume the RBs */
2773 if(rlcId.rbType == CM_LTE_SRB)
2775 rlcDlUtlResetReestInProgress(ueCb->srbCb[rlcId.rbId]);
2779 rlcDlUtlResetReestInProgress(ueCb->drbCb[rlcId.rbId]);
2786 * @brief Handler to discard a SDU.
2789 * This function is used to discard a SDU after receiving
2790 * the Discard Request from UIM. The SDU is discarded if its
2791 * available and is not mapped to any PDU yet.
2793 * @param[in] gCb RLC instance control block
2794 * @param[in] rbCb RB control block
2795 * @param[in] sduId Sdu ID of the SDU to be discarded
2798 * -# ROK In case of successful discard
2799 * -# RFAILED In case the SDU is not found or already mapped
2809 S16 rlcAmmDiscSdu(gCb, rbCb, sduId)
2815 TRC2(rlcAmmDiscSdu);
2820 * @brief Handler for Poll retransmit timer expiry
2823 * This function is used to handle events upon expiry of Poll
2826 * @param[in] gCb RLC instance control block
2827 * @param[in] rbCb Downlink RB control block
2832 Void rlcAmmPollRetxTmrExp
2838 Void rlcAmmPollRetxTmrExp(gCb, rbCb)
2844 RlcAmDl *amDl = &(rbCb->m.amDl);
2847 TRC2(rlcAmmPollRetxTmrExp);
2850 /* kw003.201 - Correcting the logic for determmining whether to do */
2851 /* any transmission of PDU. As per the spec section */
2852 /* 5.2.2.3, if there is any to transmit or retransmit, */
2853 /* do nothing. Else, pick up the VT(S) -1 for retx */
2854 /* We have nothing to transmit if window is stalled or */
2855 /* there are no SDUs to be transmitted or if there are */
2856 /* PDUs to be retransmitted. */
2857 if(CM_LTE_SRB == rbCb->rlcId.rbType)
2859 gRlcStats.amRlcStats.numDLPollTimerExpiresSrb++;
2863 gRlcStats.amRlcStats.numDLPollTimerExpiresDrb++;
2866 if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) ||
2867 RLC_AM_IS_TRANS_WIN_STALLED(amDl))
2869 sn = (amDl->txNext - 1) & amDl->snModMask;
2870 txBuf = rlcUtlGetTxBuf(amDl->txBufLst, sn);
2874 rlcAmmDlMoveFrmTxtoRetxBuffer(gCb,amDl, &retx, sn);
2876 if (AMDL.nxtRetx == NULLP)
2878 AMDL.nxtRetx = retx;
2881 rlcAmmSendDedLcBoStatus(gCb, rbCb, &AMDL);
2884 /* Get the last node in retxLst */
2885 RLC_LLIST_LAST_RETX(amDl->retxLst, retx);
2887 /* Unset wtForAck flag for the NACK PDUs */
2890 rlcAmmDlMarkPduForReTx(gCb, rbCb, retx);
2891 rlcAmmSendDedLcBoStatus(gCb, rbCb, &AMDL);
2899 * @brief Handler to update Acks for the remaining PDUs after the last accessed
2903 * This function is used to handle ACKs for the PDUs remaining after the
2904 * last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and
2905 * sends DatCfm to PDCP for the same.
2907 * @param[in] gCb RLC instance control block
2908 * @param[in] rbCb Downlink Radio Bearer control block
2909 * @param[in] mAckSn The ACK SN after doing the base modulus
2910 * @param[in] rextNode Next node in the re-transmission buffer
2917 PRIVATE Void rlcAmmDlUpdateTxAndReTxBufForAckSn
2923 KwuDatCfmInfo **datCfm
2926 PRIVATE Void rlcAmmDlUpdateTxAndReTxBufForAckSn(gCb, rbCb, mAckSn, retxNode, datCfm)
2931 KwuDatCfmInfo **datCfm;
2939 TRC2(rlcAmmDlUpdateTxAndReTxBufForAckSn);
2941 /* Remove pdus/segs from retxLst */
2944 retx = (RlcRetx *)(retxNode->node);
2945 retxNode = retxNode->next;
2946 MODAMT(retx->amHdr.sn, mSn, AMDL.txNextAck,AMDL.snModMask);
2949 rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
2953 /* For the remaining; pdus not acknowldeged by the NACK_SN but being
2954 acknowledged by the ACK_SN*/
2955 /* start from the starting of the transmission window and remove till just
2957 mSn = 0; /* same as MODAMT(AMDL.txNextAck, mSn, AMDL.txNextAck);*/
2958 sn = AMDL.txNextAck;
2961 txBuf = rlcUtlGetTxBuf(AMDL.txBufLst, sn);
2964 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
2965 "rlcAmmDlUpdateTxAndReTxBufForAckSn: ACK for PDU "
2966 "with sn = %ld UEID:%ld CELLID:%ld",
2969 rbCb->rlcId.cellId);
2971 rlcAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
2974 sn = (sn + 1) & AMDL.snModMask;
2975 MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
2982 * @brief Handler to update Acks for the remaining PDUs after the last accessed
2986 * This function is used to handle ACKs for the PDUs remaining after the
2987 * last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and
2988 * sends DatCfm to PDCP for the same.
2990 * @param[in] gCb RLC instance control block
2991 * @param[in] rbCb Downlink Radio Bearer control block
2992 * @param[in] mAckSn The ACK SN after doing the base modulus
2993 * @param[in] rextNode Next node in the re-transmission buffer
2999 PRIVATE Void rlcAmmDlUpdTxAndReTxBufForLessThanNackSn
3006 KwuDatCfmInfo **datCfm
3009 PRIVATE Void rlcAmmDlUpdTxAndReTxBufForLessThanNackSn(gCb, rbCb, sn, mNackSn, retxNode, datCfm)
3015 KwuDatCfmInfo **datCfm;
3022 TRC2(rlcAmmDlUpdTxAndReTxBufForLessThanNackSn);
3026 retx = (RlcRetx *)((*retxNode)->node);
3027 MODAMT(retx->amHdr.sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3030 (*retxNode) = (*retxNode)->next;
3031 rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
3039 /* Remove all pdus with SN < NACK_SN from the transmission buffer */
3040 MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3041 while (mSn < mNackSn)
3043 /* this if check seems redundant,why should mSn ever be mTxSn
3044 (which actually is VT(A) */
3045 txBuf = rlcUtlGetTxBuf(AMDL.txBufLst, sn);
3046 if ((txBuf != NULLP))
3048 RLOG_ARG3(L_DEBUG,DBG_RBID, rbCb->rlcId.rbId,
3049 "rlcHndlStaRsp: Handle ACK (sn = %d) UEID:%d CELLID:%d",
3052 rbCb->rlcId.cellId);
3054 /* Remove pdus from txBuf */
3055 rlcAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
3058 sn = (sn + 1) & AMDL.snModMask;
3059 MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3067 * @brief Handler to form construct AM header
3070 * This function is used to construct am header with the available header
3073 * @param[in] gCb RLC instance control block
3074 * @param[in] amHdr AM Header
3075 * @param[in] isSeg Check for Segmentation of PDU
3076 * @param[in] hdr Header field
3077 * @param[in] idx Index
3082 void rlcConstructAmHdr(RlcAmHdr *amHdr, uint8_t *hdr, uint8_t snLen, uint16_t *idx)
3085 hdr[0] = RLC_DATA_BITMASK;
3087 hdr[0] = hdr[0] | (amHdr->p << 6);
3088 hdr[0] = hdr[0] | ((amHdr->si & 0x3) << 4);
3089 if(snLen == RLC_AM_CFG_12BIT_SN_LEN)
3091 hdr[0] = hdr[0] | (U8)((amHdr->sn & 0xF00) >> 8);
3092 hdr[1] = (U8)(amHdr->sn & 0x0FF);
3097 hdr[0] = hdr[0] | (U8)((amHdr->sn & 0x30000) >> 16);
3098 hdr[1] = (U8)((amHdr->sn & 0xFF00) >> 8);
3100 hdr[2] = (U8)(amHdr->sn & 0xFF);
3104 if ((amHdr->si == RLC_SI_MID_SEG) || (amHdr->si == RLC_SI_LAST_SEG))
3107 hdr[(*idx)] = (U8)((amHdr->so & 0xFF00)>> 8);
3109 hdr[(*idx)] = (U8)(amHdr->so & 0xFF);
3116 * @brief This function adds a retx PDU to list of retx PDUs
3119 * kw003.201 - Poll expiry may cause an SN to be added to retx
3120 * out of sequence and hence all additions to retx
3121 * must validate that they are added in sequence
3123 * @param[in] amDl AM Downlink Control Block
3124 * @param[in] retx Retransmit PDU
3130 PRIVATE Void rlcAmmAddPduToRetxLst
3136 PRIVATE Void rlcAmmAddPduToRetxLst(amDl, retx)
3146 TRC2(rlcAmmAddPduToRetxLst);
3148 node = amDl->retxLst.last;
3149 MODAMT(retx->amHdr.sn, retxMSn, amDl->txNextAck,amDl->snModMask);
3150 while(node != NULLP)
3152 tRetx = (RlcRetx *)(node->node);
3153 MODAMT(tRetx->amHdr.sn, tMSn, amDl->txNextAck,amDl->snModMask);
3165 amDl->retxLst.crnt = node;
3166 cmLListInsAfterCrnt(&amDl->retxLst, &retx->lstEnt);
3167 retx->lstEnt.node = (PTR)retx;
3171 amDl->retxLst.crnt = amDl->retxLst.first;
3172 cmLListInsCrnt(&amDl->retxLst, &retx->lstEnt);
3173 retx->lstEnt.node = (PTR)retx;
3176 if (amDl->nxtRetx == NULLP)
3178 amDl->nxtRetx = retx;
3185 * @brief Handler to Move the PDU from txBuf to re-transmission buffer
3188 * This function is used to move the PDU from the txBuf to re-transmit buffer
3190 * @param[in] gCb RLC instance control block
3191 * @param[in] amDl AM Downlink Control Block
3192 * @param[in] retx node in the reTx buffer to be moved to, allocated by
3194 * @param[in] sn SN in the tx buffer which needs to be moved
3201 PRIVATE Void rlcAmmDlMoveFrmTxtoRetxBuffer
3209 PRIVATE Void rlcAmmDlMoveFrmTxtoRetxBuffer(gCb, amDl, retx, sn)
3216 RlcTx* txBuf = rlcUtlGetTxBuf(amDl->txBufLst, sn);
3217 TRC2(rlcAmmDlMoveFrmTxtoRetxBuffer);
3223 while(txBuf->pduLst.first)
3225 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(txBuf->pduLst.first->node);
3226 RLC_ALLOC_WC(gCb,*retx, sizeof(RlcRetx));
3228 #if (ERRCLASS & ERRCLS_ADD_RES)
3231 RLOG0(L_FATAL, "Memory allocation failed");
3234 #endif /* ERRCLASS & ERRCLS_RES */
3236 /* Move Sdu byte segment from TX buf to retx buf*/
3237 rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb,
3242 /* Delete node from the txBuf Pdu lst */
3243 cmLListDelFrm(&txBuf->pduLst, txBuf->pduLst.first);
3244 RLC_FREE_WC(gCb, pduInfo, sizeof(RlcDlPduInfo));
3246 /* Remove PDU from txBuf */
3247 rlcUtlDelTxBuf(amDl->txBufLst, txBuf,gCb);
3256 * function to free/release the Acknowledged mode RBCB buffers
3259 * This primitive Frees the Acknowledged Mode RbCb transmission Buffer,
3260 * retransmission Buffer and reciption Buffers
3262 * @param [in] gCb - RLC instance control block
3263 * @param [in] rbCb - Downlink RB Control Block
3268 Void rlcAmmFreeDlRbCb
3274 Void rlcAmmFreeDlRbCb(gCb,rbCb)
3279 /* stop the re-transmission timer */
3280 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,RLC_EVT_AMDL_POLL_RETX_TMR))
3282 rlcStopTmr(gCb,(PTR)rbCb, RLC_EVT_AMDL_POLL_RETX_TMR);
3285 /* store the entire Rb pointer */
3286 rbCb->rlsLnk.node = (PTR)rbCb;
3287 cmLListAdd2Tail(&gCb->u.dlCb->toBeFreed.rbLst, &rbCb->rlsLnk);
3290 cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.amDl.sduQ));
3292 rlcUtlRaiseDlCleanupEvent(gCb);
3298 * @brief Handler to create STATUS Pdu
3301 * This function is used to create status pdu
3303 * @param[in] gCb RLC instance control block
3304 * @param[in] rbCb Downlink RB control block
3305 * @param[in] rlcDatReq The data to be passed to MAC
3310 void rlcAmmCreateStatusPdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
3312 RlcSn sn; /* sequence number */
3313 RlcSn ack_sn; /* Ack sequence number */
3314 Buffer *mBuf; /* control pdu buffer */
3315 MsgLen cntrlPduSz; /* control pdu size */
3316 uint8_t cntrlPdu[RLC_MAX_CNTRL_FIELDS]; /* control pdu to be added to mBuf */
3317 RlcUdxDlStaPdu *pStaPdu;
3318 uint16_t bytesToEncode = 0; /* bytes required to encode the STATUS PDU */
3319 uint16_t encIdx = 0;
3320 uint16_t prevEncIdx = 0;
3321 RlcNackInfo *rlcNackInfo;
3324 pStaPdu = AMDL.pStaPdu;
3333 /* ACK SN Field will be set in the end based on available Grant */
3335 encIdx = bytesToEncode = 3; /* Num Octets before NACK SN info encoding*/
3337 ack_sn = pStaPdu->ackSn;
3339 if (rbCb->m.amDl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
3342 /* If alteast one NACK SN Info then set the E1 field */
3343 if (pStaPdu->nackCount)
3353 for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3355 sn = pStaPdu->nackInfo[nkCnt].sn;
3357 rlcNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3359 bytesToEncode += 2; /* 2 Octets for NACK SN */
3361 /* Check if E2 : isSegment is set */
3362 if (rlcNackInfo->isSegment)
3364 bytesToEncode += 4; /* 4 Octets: SOstart, SOend */
3367 /* Check if E3 : nackRange is set */
3368 if (rlcNackInfo->nackRange)
3370 bytesToEncode += 1; /* 1 Octet: NACK range */
3373 /* Check if this NACK info can be accomodated in the Grant */
3374 if( rlcDatReq->pduSz >= bytesToEncode)
3376 /* If there is a NACK SN before this then set its
3380 /* NACKSN E1 E2 E3 R */
3381 cntrlPdu[prevEncIdx + 1] |= 0x8;
3384 /* 12 BIT Nack SN encode */
3385 cntrlPdu[encIdx] = (sn & 0xFF0) >> 4;
3388 cntrlPdu[encIdx + 1] = (sn & 0xF) << 4;
3390 if (rlcNackInfo->isSegment)
3393 cntrlPdu[encIdx + 1] |= 0x4;
3396 /* Add soStart and soEnd */
3398 cntrlPdu[encIdx + 2] = (rlcNackInfo->soStart) >> 8;
3399 cntrlPdu[encIdx + 3] = rlcNackInfo->soStart & 0xFF;
3402 cntrlPdu[encIdx + 4] = (rlcNackInfo->soEnd) >> 8;
3403 cntrlPdu[encIdx + 5] = rlcNackInfo->soEnd & 0xFF;
3406 if (rlcNackInfo->nackRange)
3409 cntrlPdu[encIdx + 1] |= 0x2;
3410 if(rlcNackInfo->isSegment)
3412 cntrlPdu[encIdx + 6] = rlcNackInfo->nackRange;
3416 cntrlPdu[encIdx + 2] = rlcNackInfo->nackRange;
3420 gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3422 /* Set ACK SN now */
3425 ack_sn = rlcNackInfo->sn;
3427 /* Not even one nack can be accomodated */
3436 prevEncIdx = encIdx;
3437 encIdx = bytesToEncode;
3439 }/* Loop is done for the NackCount */
3444 DU_LOG("\nRLC: rlcAssembleCntrlInfo: ACK PDU's SN = %d"\
3445 "UEID:%d CELLID:%d", ack_sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
3447 cntrlPdu[0] |= (ack_sn & 0xF00)>> 8;
3448 cntrlPdu[1] = (U8)ack_sn;
3452 else if (rbCb->m.amDl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
3454 /* If alteast one NACK SN Info then set the E1 field */
3455 if (pStaPdu->nackCount)
3465 for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3467 sn = pStaPdu->nackInfo[nkCnt].sn;
3469 rlcNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3471 bytesToEncode += 3; /* 3 Octets for NACK SN */
3473 /* Check if E2 : isSegment is set */
3474 if (rlcNackInfo->isSegment)
3476 bytesToEncode += 4; /* 4 Octets: SOstart, SOend */
3479 /* Check if E3 : nackRange is set */
3480 if (rlcNackInfo->nackRange)
3482 bytesToEncode += 1; /* 1 Octet: NACK range */
3485 /* Check if this NACK info can be accomodated in the Grant */
3486 if( rlcDatReq->pduSz >= bytesToEncode)
3488 /* If there is a NACK SN before this then set its
3492 /* NACKSN E1 E2 E3 R R R */
3493 cntrlPdu[prevEncIdx + 2] |= 0x20;
3496 /* 18 BIT Nack SN encode */
3497 cntrlPdu[encIdx] = (U8)((sn & 0x3FC00) >> 10);
3500 cntrlPdu[encIdx + 1] = (U8)((sn & 0x3FC) >> 2);
3503 cntrlPdu[encIdx + 2] = (U8)((sn & 0x3)<< 6);
3505 if (rlcNackInfo->isSegment)
3507 /* NACKSN E1 E2 E3 R R R */
3509 cntrlPdu[encIdx + 2] |= 0x10;
3512 /* Add soStart and soEnd */
3514 cntrlPdu[encIdx + 3] = (rlcNackInfo->soStart) >> 8;
3515 cntrlPdu[encIdx + 4] = (U8)rlcNackInfo->soStart;
3518 cntrlPdu[encIdx + 5] = (rlcNackInfo->soEnd) >> 8;
3519 cntrlPdu[encIdx + 6] = (U8)(rlcNackInfo->soEnd);
3522 if (rlcNackInfo->nackRange)
3524 /* NACKSN E1 E2 E3 R R R */
3526 cntrlPdu[encIdx + 2] |= 0x08;
3528 if (rlcNackInfo->isSegment)
3530 cntrlPdu[encIdx + 7] = rlcNackInfo->nackRange;
3534 cntrlPdu[encIdx + 3] = rlcNackInfo->nackRange;
3538 gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3540 /* Set ACK SN now */
3543 ack_sn = rlcNackInfo->sn;
3545 /* Not even one nack can be accomodated */
3548 cntrlPdu[2] &= 0xFD;
3554 prevEncIdx = encIdx;
3555 encIdx = bytesToEncode;
3557 }/* Loop is done for the NackCount */
3562 DU_LOG("\nRLC: rlcAssembleCntrlInfo: ACK PDU's SN = %d"
3563 "UEID:%d CELLID:%d", ack_sn, rbCb->rlcId.ueId,rbCb->rlcId.cellId);
3565 cntrlPdu[0] |= (ack_sn & 0x3C000) >> 14;
3566 cntrlPdu[1] = (ack_sn & 0x3FC0) >> 6;
3567 cntrlPdu[2] |= (ack_sn & 0x3F)<< 2;
3574 DU_LOG("\nRLC: rlcAssembleCntrlInfo:Conf SN LEN %d is INVALID !!!! \
3575 UEID:%d CELLID:%d", rbCb->m.amDl.snLen, rbCb->rlcId.ueId,
3576 rbCb->rlcId.cellId);
3581 SGetMsg(RLC_GET_MEM_REGION(gCb), RLC_GET_MEM_POOL(gCb),&mBuf);
3583 mBuf = (Buffer *)rlcAmmStaPduList[rlcAmmStaPduListCnt++];
3585 if(rlcAmmStaPduListCnt > 511)
3586 rlcAmmStaPduListCnt = 0;
3589 cntrlPduSz = encIdx;
3590 ODU_ADD_POST_MSG_MULT(cntrlPdu, cntrlPduSz, mBuf);
3592 rlcDatReq->pduSz -= cntrlPduSz;
3593 /* Add mBuf to AMDL.mBuf */
3599 #ifdef RLC_STA_PROC_IN_MAC/* RLC Status PDU Processing */
3601 S16 rlcProcDlStatusPdu(Pst *udxPst,SuId suId,
3602 CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu);
3605 PRIVATE Void rgAmmExtractElmnt
3612 PRIVATE Void rgAmmExtractElmnt(gCb, pdu, hdrInfo)
3619 U8 pLen = hdrInfo->pLen;
3620 U8 len = (U8)hdrInfo->len;
3628 TRC2(rlcAmmExtractElmnt);
3634 SRemPreMsg(&hdr, pdu);
3640 val = tHdr >> (RLC_BYTE_LEN - (len));
3644 else /*if (len > 8) */
3648 val = val >> (RLC_BYTE_LEN - fLen);
3649 val = val << (len - fLen);
3651 SRemPreMsg(&hdr, pdu);
3655 hdr = hdr >> (RLC_BYTE_LEN - rLen);
3658 pLen = (RLC_BYTE_LEN - rLen);
3662 rLen = rLen - RLC_BYTE_LEN;
3664 tVal = tVal << rLen;
3667 SRemPreMsg(&hdr, pdu);
3669 hdr = hdr >> (RLC_BYTE_LEN - rLen);
3672 pLen = (RLC_BYTE_LEN - rLen);
3676 hdrInfo->pLen = pLen;
3687 PRIVATE Void rgAmmUlHndlStatusPdu
3697 PRIVATE Void rgAmmUlHndlStatusPdu(udxPst,suId,gCb, rbCb, cntrlPdu, fByte)
3708 RlcUdxStaPdu *pStaPdu;
3709 U8 e3; /* NACK RANGE : 5GNR */
3712 U32 resrvdBitsAckSn;
3713 U32 resrvdBitsNackSn;
3716 TRC2(rgAmmUlHndlStatusPdu)
3718 RLCDBGP_BRIEF(gCb, "rgAmmUlHndlStatusPdu(rbCb, cntrlPdu, fByte) \n");
3720 RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
3722 /* Extract the Control PDU */
3723 hdrInfo.hdr = (*fByte << 1);
3726 /* D/C has been shifted in the calling function */
3727 if (hdrInfo.hdr & 0xE0)
3729 RLCDBGP_ERROR(gCb, "rgAmmUlHndlStatusPdu: Reserved value for CPT received \n");
3733 RLC_ALLOC_SHRABL_BUF(udxPst->region,
3736 sizeof(RlcUdxStaPdu));
3738 #if (ERRCLASS & ERRCLS_ADD_RES)
3739 /* Memory allocation failure can not be expected */
3746 if (rbCb->m.amDl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
3749 resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_12BITS;
3750 resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_12BITS;
3752 else if (rbCb->m.amDl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
3755 resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_18BITS;
3756 resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_18BITS;
3761 resrvdBitsAckSn = 0;
3762 resrvdBitsAckSn = 0;
3765 pStaPdu->nackCnt = 0;
3767 hdrInfo.hdr = hdrInfo.hdr << RLC_CPT_LEN;
3770 hdrInfo.len = RLC_SN_LEN;
3771 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3772 pStaPdu->ackSn = hdrInfo.val;
3774 /* Check if NACK Exists */
3775 hdrInfo.len = RLC_E1_LEN;
3776 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3777 e1 = (U8)hdrInfo.val;
3778 RLCDBGP_DETAIL(gCb, "rgAmmUlHndlStatusPdu: ACK SN = %d \n", pStaPdu->ackSn);
3780 /* Extract the Reserved Bits after ACK SN field */
3781 hdrInfo.len = resrvdBitsAckSn;
3782 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3785 /* If NACK exists in control PDU */
3786 /* For ACKs and NACKs */
3787 while (e1 && (pStaPdu->nackCnt < RLC_MAX_NACK_CNT))
3789 hdrInfo.len = snLen;
3790 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3791 pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
3793 hdrInfo.len = RLC_E1_LEN;
3794 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3795 e1 = (U8)hdrInfo.val;
3798 /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
3800 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3801 /* e2 = (U8) hdrInfo.val;*/
3803 /* Store e2 value */
3804 pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (U8) hdrInfo.val;
3806 /* Extract e3 : 5GNR */
3807 /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
3809 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3810 e3 = (U8) hdrInfo.val;
3812 /* Extract Reserved Bits after NACK SN */
3813 hdrInfo.len = resrvdBitsNackSn;
3814 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3816 /* Test for resegmentation */
3817 if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
3819 hdrInfo.len = RLC_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
3820 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3821 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
3823 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3824 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = hdrInfo.val;
3827 "rgAmmUlHndlStatusPdu: soStart and soEnd = %d %d \n",
3828 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
3829 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd);
3834 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
3835 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = 0;
3838 /* NACK RANGE Field is SET */
3841 /* Extract NACK range field */
3842 hdrInfo.len = RLC_NACK_RANGE_LEN;
3843 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3844 snRange = (U8)hdrInfo.val;
3846 pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
3852 gRlcStats.amRlcStats.numULStaPduRcvd++;
3853 gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
3855 /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
3856 to the last NACK SN + 1 and discard the original ACK_SN*/
3857 if(pStaPdu->nackCnt == RLC_MAX_NACK_CNT)
3859 pStaPdu->ackSn = (pStaPdu->nackInfo[RLC_MAX_NACK_CNT-1].sn + 1) & amDl->snModMask;
3863 /* Parse & send Status PDU to RLC-DL */
3864 //rlcUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
3865 rlcUlUdxStaUpdReq(udxPst, suId, &rbCb->rlcId, pStaPdu);
3870 S16 rlcProcDlStatusPdu(Pst *udxPst,SuId suId,
3871 CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu)
3873 RlcDlRbCb *rbCb = NULLP;
3874 RlcDlUeCb *ueCb = NULLP;
3877 S16 retVal = RFAILED;
3879 Pst dlRlcPst = *udxPst;
3881 gCb = RLC_GET_RLCCB(1); /* DL RLC instance */
3883 if( ROK != rlcDbmFetchDlUeCb(gCb,rnti,cellId,&(ueCb)))
3885 printf("\n RLC UECb Not found...\n");
3890 rbCb = ueCb->lCh[lcId - 1].dlRbCb;
3892 /* Skip if mode is not AM */
3893 if((rbCb == NULLP) || (rbCb->mode != CM_LTE_MODE_AM))
3898 if(ROK != SExamMsg((Data *)(&fByte),
3901 printf("\n Failure in Rlc Hdr SExamMsg\n");
3905 if(RLC_CNTRL_PDU == ((fByte & RLC_DC_POS) >> RLC_DC_SHT))
3907 SRemPreMsg(&temp, rlcSdu);
3908 dlRlcPst.selector = 1;/* LWLC*/
3909 rgAmmUlHndlStatusPdu(&dlRlcPst,suId,gCb, rbCb, rlcSdu, &fByte);
3923 /********************************************************************30**
3926 **********************************************************************/