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 /* header include files (.h) */
39 #include "common_def.h"
40 #include "lkw.h" /* LKW defines */
41 #include "ckw.h" /* CKW defines */
42 #include "kwu.h" /* KWU defines */
43 #include "rgu.h" /* RGU defines */
44 #include "kw_err.h" /* Err defines */
45 #include "kw_env.h" /* RLC environment options */
47 #include "kw.h" /* RLC defines */
52 /* extern (.x) include files */
53 #include "lkw.x" /* LKW */
54 #include "ckw.x" /* CKW */
55 #include "kwu.x" /* KWU */
56 #include "rgu.x" /* RGU */
64 uint32_t rlcAmmStaPduList[512];
65 uint32_t rlcAmmStaPduListCnt = 0;
70 @brief RLC Acknowledged Mode Downlink Module
72 #define RLC_MODULE (RLC_DBGMASK_AM | RLC_DBGMASK_DL)
74 uint32_t rlcStatusPduCnt, rlcStatusAckCnt, rlcStatusNcnt, rlcSduSndCnt;
80 /* forward references */
81 Void rlcAmmDlHndlStatusPdu ARGS ((RlcCb *gCb,
83 RlcUdxStaPdu *pStaPdu));
85 /* public variable declarations */
87 /* This structure holds all the global structs we need. */
89 /* private variable declarations */
91 #define RLC_AM_RMV_HDR(_gCb, _rbCb, _retx) do { \
92 if ((_retx)->yetToConst == FALSE) \
95 SSegMsg((_retx)->seg, (_retx)->hdrSz, &_pduInfo); \
96 ODU_PUT_MSG_BUF((_retx)->seg); \
97 (_retx)->seg = _pduInfo; \
99 (_rbCb)->m.amDl.estHdrSz -= retx->hdrSz;\
102 /* private function declarations */
104 static Void rlcResegRetxPdus ARGS ((RlcCb *gCb,
106 RlcDatReq *rlcDatReq));
108 static Void rlcRemRetxPdu ARGS ((RlcCb *gCb,
112 static Void rlcAmmCreateStatusPdu ARGS ((RlcCb *gCb,
114 RlcDatReq *rlcDatReq));
116 static Void rlcAmmDlMarkPduForReTx ARGS ((RlcCb *gCb,
120 static Void rlcAmmDlProcessSuccessfulTxPdu ARGS((RlcCb *gCb,
123 KwuDatCfmInfo **datCfm));
125 static Void rlcAmmDlSetTxNextAck ARGS((RlcAmDl *amDl, RlcSn sn));
127 static Void rlcAmmDlCheckAndStopPollTmr ARGS((RlcCb *gCb,
131 static Void rlcAssembleSdus ARGS ((RlcCb *gCb,
133 RlcDatReq *rlcDatReq));
135 static bool rlcAmmDlCheckAndSetPoll ARGS ((RlcCb *gCb,
140 static Void rlcAmmCreatePdu ARGS ((RlcCb *gCb,
143 RlcDlPduInfo *pduInfo,
146 static Void rlcAmmSndStaInd ARGS ((RlcCb *gCb,RlcDlRbCb *rbCb, RlcRetx *retx));
148 static Void rlcGetNxtRetx ARGS ((RlcCb *gCb, RlcRetx **retx));
150 static Void rlcConstructAmHdr ARGS ((RlcAmHdr *amHdr,
155 static Void rlcAmmDlUpdateTxAndReTxBufForAckSn ARGS ((RlcCb *gCb,
159 KwuDatCfmInfo **datCfm));
161 static Void rlcAmmDlMoveFrmTxtoRetxBuffer ARGS ((RlcCb *gCb,
166 static Void rlcAmmDlCheckIsSDUDelivered ARGS((RlcCb *gCb,
169 KwuDatCfmInfo **datCfm));
171 static Void rlcAmmAddPduToRetxLst ARGS((RlcAmDl *amDl,
174 static Void rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer ARGS(
179 RlcDlPduInfo *pduInfo
182 static Void rlcAmmDlHndlStatus4SduByteSegInTxBuf ARGS(
186 RlcNackInfo *nackSnInfo,
188 KwuDatCfmInfo **datCfm
191 static Void rlcAmmDlUpdateTxAndReTxBufForNackSn ARGS(
195 RlcNackInfo *nackSnInfo,
197 KwuDatCfmInfo **datCfm
200 static Void RlcDlAmmGetNackSnInfoFrmNackRangeIdx ARGS(
203 RlcNackInfo *nackInfo,
205 RlcNackInfo *nackSnInfo,
209 static Void rlcAmmDlUpdTxAndReTxBufForLessThanNackSn ARGS(
216 KwuDatCfmInfo **datCfm
218 /*****************************************************************************
220 AM Module contains the following funcitons:
224 - rlcAmmDlAssembleCntrlInfo
227 - rlcAmmDlCheckAndSetPoll
233 *******************************************************************************/
234 /** @addtogroup ammode */
238 * @brief Function to send a Status Response to MAC for a dedicated logical
242 * Function calculates the current bo and send a Status response for the
243 * dedicated logical channel if the bo is non zero
245 * @param[in] gCb RLC instance control block
246 * @param[in] rbCb Radio Bearer control block
247 * @param[in] amDl AM downlink control block
251 void rlcAmmSendDedLcBoStatus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcAmDl *amDl)
253 int32_t bo = rlcAmmCalculateBo(amDl);
257 rlcUtlSendDedLcBoStatus(gCb, rbCb, bo, amDl->estHdrSz, \
258 amDl->cntrlBo ?TRUE:FALSE,amDl->cntrlBo);
265 * @brief Function to check if the pollSn is acked and stop the poll timer
267 * @param[in] gCb RLC instance control block
268 * @param[in] rbCb Radio Bearer control block
269 * @param[in] mAckSn The last received ACKSN. The base modulus value should
274 static Void rlcAmmDlCheckAndStopPollTmr(RlcCb *gCb,RlcDlRbCb *rbCb,RlcSn mAckSn)
278 MODAMT(rbCb->m.amDl.pollSn, mPollSn, rbCb->m.amDl.txNextAck,rbCb->m.amDl.snModMask);
280 if (mPollSn <= mAckSn)
282 if (rlcChkTmr(gCb, (PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR))
284 rlcStopTmr(gCb, (PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR);
292 * @brief Function to set VT(A) and VT(MS). Calculates the VT(MS) from VT(A)
294 * @param[in,out] amDl AM downlink control block
295 * @param[in]sn Sequence number to be set as VT(A)
299 static Void rlcAmmDlSetTxNextAck(RlcAmDl *amDl,RlcSn sn)
301 amDl->txNextAck = sn;
307 * @brief Function to process a successfully re-transmitted PDU/segment
310 * Checks if the SDU has been completely delivered or not. Removes the PDU
311 * from the re-transmission buffer
313 * @param[in] gCb RLC instance control block
314 * @param[in] rbCb Downlink Radio Bearer control block
315 * @param[in] retx The PDU/segment which was successfully re-transmitted
319 static Void rlcAmmDlProcessSuccessfulReTx
324 KwuDatCfmInfo **datCfm
327 rlcAmmDlCheckIsSDUDelivered(gCb, rbCb, &(retx->sduMap), datCfm);
329 rlcRemRetxPdu(gCb, rbCb, retx);
335 * @brief Handler to Move the PDU from txBuf to re-transmission buffer
338 * This function is used to move the PDU from the txBuf to re-transmit buffer
340 * @param[in]RlcCb *gCb RLC instance control block
341 * @param[in]RlcAmDl *amDl AM Downlink Control Block
342 * @param[in]RlcRetx **retx node in the reTx buffer to be moved to, allocated by
344 * @param[in]RlcDlPduInfo *pduInfo TX PDU which needs to be moved
350 static Void rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer
355 RlcDlPduInfo *pduInfo
359 RLC_ALLOC_WC(gCb,*retx, sizeof(RlcRetx));
361 #if (ERRCLASS & ERRCLS_ADD_RES)
364 DU_LOG("\nERROR --> RLC_DL : Memory allocation failed");
367 #endif /* ERRCLASS & ERRCLS_RES */
369 (*retx)->seg = pduInfo->pdu;
370 (*retx)->segSz = pduInfo->pduSz;
371 /* MS_FIX for DL stall */
372 (*retx)->soEnd = (pduInfo->amHdr.so + pduInfo->pduSz - 1);
374 (*retx)->hdrSz = pduInfo->hdrSz;
375 (*retx)->retxCnt = 1;
376 (*retx)->yetToConst = 0;
377 (*retx)->pendingReTrans = TRUE;
379 /* initialize the list pointer to 0 instead of memset */
380 (*retx)->lstEnt.next = 0;
381 (*retx)->lstEnt.prev = 0;
382 /* copy the sdu maps */
383 RLC_MEM_CPY(&((*retx)->sduMap),
387 RLC_MEM_CPY(&((*retx)->amHdr), &pduInfo->amHdr, sizeof(RlcAmHdr));
388 rlcAmmAddPduToRetxLst(amDl, (*retx));
390 /* Update the BO appropriately */
391 amDl->retxBo += (*retx)->segSz;
392 amDl->estHdrSz += (*retx)->hdrSz;
394 gRlcStats.amRlcStats.numDLRetransPdus++;
397 } /*rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer */
400 * @brief Function to handle Status of Sdu byte segment for a nackSn
403 * This function is used to move the PDU from the txBuf to re-transmit buffer
405 * @param[in]RlcCb *gCb RLC instance control block
406 * @param[in]RlcDlRbCb *rbCb AM Downlink Control Block
407 * @param[in]RlcNackInfo *nackSnInfo Nack Information of a NACK_SN
408 * @param[in]RlcRetx **retx node in the reTx buffer to be moved to, allocated by
410 * @param[in]KwuDatCfmInfo **datCfm Ptr to datCfm
416 static Void rlcAmmDlHndlStatus4SduByteSegInTxBuf
420 RlcNackInfo *nackSnInfo,
422 KwuDatCfmInfo ** datCfm
429 txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, nackSnInfo->sn);
434 lnk = txBuf->pduLst.first;
437 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(lnk->node);
438 RlcSn pduSoEnd = (pduInfo->amHdr.so + pduInfo->sduMap.sduSz - 1);
440 /* If So of Sdu byte segment(pduInfo/seg) is < status pdu
441 soStart that means it's ACKED*/
442 if(pduSoEnd < nackSnInfo->soStart)
444 rlcAmmDlCheckIsSDUDelivered(gCb,
450 else if (pduSoEnd <= nackSnInfo->soEnd)
452 /* Move Sdu byte segment from TX buf to retx buf*/
453 rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb,
464 /* Delete node from the txBuf Pdu lst */
465 cmLListDelFrm(&txBuf->pduLst, lnk);
466 RLC_FREE(gCb, pduInfo, sizeof(RlcDlPduInfo));
469 if(!txBuf->pduLst.count)
471 /*No more Sdu byte segment are left. Hence delete txBuf*/
472 rlcUtlDelTxBuf(RLC_AMDL.txBufLst, txBuf,gCb);
479 * @brief Function to handle Status of Sdu byte segment for a nackSn
482 * This function is used to move the PDU from the txBuf to re-transmit buffer
484 * @param[in]RlcCb *gCb RLC instance control block
485 * @param[in]RlcDlRbCb *rbCb AM Downlink Control Block
486 * @param[in]RlcNackInfo *nackSnInfo Nack Information of a NACK_SN
487 * @param[in]RlcRetx **retx node in the reTx buffer to be moved to, allocated by
489 * @param[in]KwuDatCfmInfo **datCfm Ptr to datCfm
494 static Void rlcAmmDlUpdateTxAndReTxBufForNackSn
498 RlcNackInfo *nackSnInfo,
500 KwuDatCfmInfo **datCfm
506 /* Now process the NACK_SN received. Now the NACK_SN is */
507 /* either the first element of RETX or is in TX array */
508 /* To remove the remaining acks from the pdu byte segments */
510 /* if the NACK_SN is in the transmit buffer, move it to the re-
512 txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, nackSnInfo->sn);
515 if(nackSnInfo->isSegment)
517 /* Go through all the AMD PDUs of a particular SN
518 and check if segment is ACKED if yes then mark succesfully sent,
519 if segment is NACKed then move it to to retx lst */
520 rlcAmmDlHndlStatus4SduByteSegInTxBuf(gCb, rbCb, nackSnInfo, &retx, datCfm);
524 /*e2= 0 and e3= 0: Move complete PDU from TX buf to retx buf*/
525 rlcAmmDlMoveFrmTxtoRetxBuffer(gCb,
531 #if (ERRCLASS & ERRCLS_ADD_RES)
535 (*retxNode) = retx->lstEnt.next;
541 /* process the pdus/segments in the re-transmit buffer with
545 retx = (RlcRetx *)((*retxNode)->node);
546 if (retx->amHdr.sn != nackSnInfo->sn)
550 if ((nackSnInfo->isSegment) &&
551 ((retx->soEnd < nackSnInfo->soStart) /*|| (retx->amHdr.so > soEnd)*/))
553 DU_LOG( "\nDEBUG --> RLC_DL : rlcHndlStaRsp: Handle ACK for byte segment, Its "
554 "sn = %d UEID:%d CELLID:%d",
558 DU_LOG("\nDEBUG --> RLC_DL : soStart and soEnd = %d, %d, UEID:%d CELLID:%d",
559 retx->amHdr.so, retx->soEnd,
563 (*retxNode) = (*retxNode)->next;
564 rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
566 else if((!nackSnInfo->isSegment) || (retx->soEnd <= nackSnInfo->soEnd))
568 /* This case covers the NACKED segments and also the case */
569 /* when there are segments and the entire SN is nacked. */
570 /* This case also covers the case of nonsegmented retx PDU*/
572 (*retxNode) = (*retxNode)->next;
573 /* Mark the retx PDU we found for further retransmission */
574 rlcAmmDlMarkPduForReTx(gCb, rbCb, retx);
578 /* If we are here that means this segment and segments after this are ACKed*/
581 } /* end of retxNode while loop*/
586 * @brief Function to get nack Sn information from nackRange index
589 * This function is used to get nack Sn information from nackRange index
591 * @param[in]RlcAmDl *amDl,
592 * @param[in]RlcUdxStaPdu *StaPdu,
593 * @param[in]RlcNackInfo *nackSnInfo,
594 * @param[in]RlcRetx *retx;
595 * @param[in]RlcSn sn,
596 * @param[in]uint8_t idx
601 static Void RlcDlAmmGetNackSnInfoFrmNackRangeIdx
604 RlcNackInfo *nackInfo,
606 RlcNackInfo *nackSnInfo,
614 nackSnInfo->isSegment = FALSE;
616 if((!nackInfo->isSegment) || (!idx && nackSnInfo->nackRange && (!nackInfo->soStart)))
618 nackSnInfo->soStart = 0;
619 nackSnInfo->soEnd = 0;
622 txBuf = rlcUtlGetTxBuf(amDl->txBufLst, nackSnInfo->sn);
625 node = txBuf->pduLst.first;
628 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(node->node);
629 uint16_t pduSoEnd = pduInfo->amHdr.so + pduInfo->sduMap.sduSz - 1;
630 if((!idx) && (pduInfo->amHdr.so == nackInfo->soStart))
632 nackSnInfo->isSegment = TRUE;
633 nackSnInfo->soStart = pduInfo->amHdr.so;
634 nackSnInfo->soEnd = pduSoEnd;
637 else if((idx == nackSnInfo->nackRange - 1) && \
638 (pduSoEnd == nackInfo->soEnd))
640 nackSnInfo->isSegment = TRUE;
641 nackSnInfo->soStart = pduInfo->amHdr.so;
642 nackSnInfo->soEnd = pduSoEnd;
648 if(!nackSnInfo->isSegment)
652 retx = (RlcRetx *)(retxNode->node);
653 if(retx->amHdr.sn != nackSnInfo->sn)
657 if((!idx) && (retx->amHdr.so == nackInfo->soStart))
659 nackSnInfo->isSegment = TRUE;
660 nackSnInfo->soStart = retx->amHdr.so;
661 nackSnInfo->soEnd = retx->soEnd;
664 else if((idx == nackSnInfo->nackRange - 1) && \
665 (retx->soEnd == nackInfo->soEnd))
667 nackSnInfo->isSegment = TRUE;
668 nackSnInfo->soStart = retx->amHdr.so;
669 nackSnInfo->soEnd = retx->soEnd;
672 retxNode = retxNode->next;
678 * @brief Function to update transmission buffers and send confimations to
679 * PDCP on the reception of Status PDU
682 * First processes the NACKs received
683 * -# Removes the pdus which are acked by each of the NACK SN from the
684 * transmission and re-transmission buffer
685 * -# If NACKed SN in in the transmisson buffer, moves it to re-transmission
687 * -# Removes PDU segments of the NACKed SN which have been successfully
688 * received by the other end. For the un-successful ones, marks them for
690 * -# When PDUs/segments are removed from the buffer, indicates to upper
691 * layer if the SDU is completely delivered
692 * -# Removes the PDUs/segments which are acked by the ACK_SN but not by the
695 * @param[in] gCb RLC Instance control block
696 * @param[in] rbCb Downlink Radio Bearer control block
697 * @param[in] pStaPdu The decoded Status Pdu
701 Void rlcAmmDlHndlStatusPdu(RlcCb *gCb,RlcDlRbCb *rbCb,RlcUdxStaPdu *pStaPdu)
706 KwuDatCfmInfo* datCfm;
707 RlcKwuSapCb *rlckwuSap;
712 rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
713 /* store the re-transmission bo, to check if it changes due to the
714 processing of the status pdu */
715 oldRetxBo = RLC_AMDL.retxBo;
717 /* Allocate memory for datCfm Info */
718 RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
720 #if (ERRCLASS & ERRCLS_ADD_RES)
723 DU_LOG("\nERROR --> RLC_DL : Memory allocation failed UEID:%d CELLID:%d",
726 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
729 #endif /* ERRCLASS & ERRCLS_RES */
731 datCfm->numSduIds = 0;
732 datCfm->rlcId = rbCb->rlcId;
734 MODAMT(pStaPdu->ackSn, mAckSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
735 MODAMT(RLC_AMDL.txNext,mTxNext, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
739 DU_LOG("\nERROR --> RLC_DL : Invalid ACK SN = %d received. Current Vta =%d"
745 /* RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo)); */
746 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
750 /* Venki - stopping the poll retx timer */
751 /*Stop PollRetx Tmr */
752 rlcAmmDlCheckAndStopPollTmr(gCb, rbCb, mAckSn);
754 /* Set the first node in retx list to retxNode */
755 retxNode = RLC_AMDL.retxLst.first;
757 /* If NACK exists in control PDU */
758 if (pStaPdu->nackCnt)
761 RlcNackInfo nackSnInfo;
764 RlcSn transWinStartSn = RLC_AMDL.txNextAck; /*used to track the SN from which
765 to start processing the transmission
769 /* if any NACKs then txNextAck should be equal to the first NACK_SN*/
770 txNextAck = pStaPdu->nackInfo[0].sn;
772 rlcStatusNcnt += pStaPdu->nackCnt;
775 while (idx < pStaPdu->nackCnt)
777 nackSnInfo.isSegment = pStaPdu->nackInfo[idx].isSegment;
778 nackSnInfo.nackRange = pStaPdu->nackInfo[idx].nackRange;
779 nackSnInfo.sn = pStaPdu->nackInfo[idx].sn;
781 DU_LOG("\nDEBUG --> RLC_DL : rlcHndlStaRsp: NACK SN = %d UEID:%d CELLID:%d",
786 nackSnInfo.soStart = pStaPdu->nackInfo[idx].soStart;
787 nackSnInfo.soEnd = pStaPdu->nackInfo[idx].soEnd;
789 /* e2 is used as a boolean indicating presence of SOStart or SOEnd */
791 sn = transWinStartSn;
793 /* move transWinStartSn to nackSnInfo.sn + 1, as the pdu's before that
794 will be removed from the buffer */
795 transWinStartSn = (nackSnInfo.sn + (nackSnInfo.nackRange ?\
796 (nackSnInfo.nackRange - 1) : 0) + 1) & RLC_AMDL.snModMask;
798 /* Clear the acked SNs from the retx list */
799 MODAMT(nackSnInfo.sn, mNackSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
801 if ((mNackSn > mAckSn) || (mNackSn >= mTxNext))
803 /* Erroneous NACK_SN, we should raise an error towards L3 */
804 DU_LOG("\nERROR --> RLC_DL : Status Pdu is not correct UEID:%d CELLID:%d",
807 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
811 /* clear all the SNs < NACK_SN from re-transmission list */
812 rlcAmmDlUpdTxAndReTxBufForLessThanNackSn(gCb, rbCb, sn, mNackSn,
815 if(!nackSnInfo.nackRange)
817 rlcAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, &nackSnInfo, &retxNode, &datCfm);
818 gRlcStats.amRlcStats.numRlcAmCellNackRx++;
823 /* Update issegment, soStart, soEnd ,sn in nackSnInfo and handle
827 RlcDlAmmGetNackSnInfoFrmNackRangeIdx(&RLC_AMDL, &pStaPdu->nackInfo[idx],
828 retxNode, &nackSnInfo, idx1);
830 rlcAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, &nackSnInfo,
832 nackSnInfo.sn = ((nackSnInfo.sn + 1) & (RLC_AMDL.snModMask));
833 gRlcStats.amRlcStats.numRlcAmCellNackRx++;
835 }while((++idx1) < (nackSnInfo.nackRange));
839 } /* End of nackCnt while loop */
841 /* Remove the PDUs with are further acked by the ACK_SN after taking
842 care of all the NACK_SN related acknowledgments*/
843 rlcAmmDlUpdateTxAndReTxBufForAckSn(gCb,rbCb, mAckSn, retxNode, &datCfm);
845 /* Update txNextAck */
846 rlcAmmDlSetTxNextAck(&RLC_AMDL,txNextAck);
852 DU_LOG("\nDEBUG --> RLC_DL : rlcHndlStaRsp: Received All ACKS UEID:%d CELLID:%d",
856 /* For the remaining ACKs after last nackSn */
857 rlcAmmDlUpdateTxAndReTxBufForAckSn(gCb,rbCb, mAckSn, retxNode, &datCfm);
859 /* update txNextAck */
860 rlcAmmDlSetTxNextAck(&RLC_AMDL, pStaPdu->ackSn);
863 if(datCfm->numSduIds != 0)
865 if(datCfm->numSduIds > 1024)
867 DU_LOG("\nDEBUG --> RLC_DL : Sending [%u] SDU Cfms to PDCP & [%u] lost for"
870 datCfm->numSduIds-1024,
873 datCfm->numSduIds = 1024;
875 rlcSduSndCnt += datCfm->numSduIds;
876 /* Sap control block */
877 RlcUiKwuDatCfm(&rlckwuSap->pst, rlckwuSap->suId, datCfm);
881 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
884 /* Fix for memory corruption */
885 RLC_LLIST_FIRST_RETX(RLC_AMDL.retxLst, RLC_AMDL.nxtRetx);
886 /* BO update, if retransmission BO has changed. RLC_AMDL.retxBo would have
887 canged inside the above called functions */
888 if (oldRetxBo != RLC_AMDL.retxBo)
890 rlcAmmSendDedLcBoStatus(gCb, rbCb, &RLC_AMDL);
897 * @brief Function to calculate the current buffer occupancy
900 * Function to calculate the current bo depending on the control,
901 * re-transmit, transmit bo's and the state of the transmit window.
902 * If the transmit window is stalled, then the transmit bo is not
905 * @param[in] amDl AM mode donwlink control block
910 S32 rlcAmmCalculateBo(RlcAmDl *amDl)
914 /* Make sure non of the bo's are negative */
920 if (amDl->cntrlBo < 0)
925 if (amDl->retxBo < 0)
930 bo = amDl->cntrlBo + amDl->retxBo;
932 /* if window is not stalled then add the transmit bo also */
933 if (! RLC_AM_IS_TRANS_WIN_STALLED(amDl))
943 * @brief Handler to queue the SDUs received from PDCP
946 * This function is invoked by UIM to queue the SDU received from PDCP in the
947 * SDU queue of the corresponding RbCb. It also updates the BO and report the
949 * - Allocate memory for and assign received buffer to the SDU
950 * - Add SDU in the sduQ of RlcAmDl
951 * - Calculate bo with the buffer received
952 * - Accumulate bo with retransmission bo and control pdu's bo if available
953 * - Estimate the header size for the bo; Fill in StaRspInfo and send it
956 * @param[in] gCb RLC Instance control block
957 * @param[in] rbCb RB control block
958 * @param[in] mBuf Sdu to be queued
959 * @param[in] datReq Ptr to the datReq sent from PDCP
964 void rlcAmmQSdu(RlcCb *gCb, RlcDlRbCb *rbCb, Buffer *mBuf, KwuDatReqInfo *datReq)
976 RLC_ALLOC_WC(gCb,sdu, sizeof(RlcSdu));
978 #if (ERRCLASS & ERRCLS_ADD_RES)
981 DU_LOG("\nERROR --> RLC_DL : rlcAmmQSdu : Memory allocation failed UEID:%d CELLID:%d",\
982 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
985 #endif /* ERRCLASS & ERRCLS_RES */
987 RLC_UPD_L2_DL_TOT_SDU_STS(gCb,rbCb);
988 /* Discard new changes starts */
989 rlcUtlGetCurrTime(&sdu->arrTime);
990 /* Discard new changes ends */
991 /* Assign values to sdu */
992 ODU_GET_MSG_LEN(mBuf, &sdu->sduSz);
995 sdu->actSz = sdu->sduSz;
996 sdu->mode.am.sduId = datReq->sduId;
997 /* initialize values for AM mode to 0 */
998 sdu->mode.am.rcvdSz = 0;
999 sdu->mode.am.isSegmented = 0;
1000 #ifndef RGL_SPECIFIC_CHANGES
1003 uint32_t dlrate_kwu;
1004 dlrate_kwu += sdu->sduSz;
1008 /* Update nxtTx to point to the added sdu if this is the first SDU in the
1010 if (RLC_AMDL.nxtTx == NULLP)
1012 DU_LOG("\nDEBUG --> RLC_DL : rlcAmmQSdu: Received SDU will be transmitted next \
1013 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1014 RLC_AMDL.nxtTx = sdu;
1017 /* Add sdu to the sdu list */
1018 cmLListAdd2Tail(&RLC_AMDL.sduQ, &sdu->lstEnt);
1019 sdu->lstEnt.node = (PTR)sdu;
1023 if (rbCb->ueCb->tenbStats)
1025 if (RLC_AMDL.sduQ.count > rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxPktsInSduQ)
1027 rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxPktsInSduQ = RLC_AMDL.sduQ.count;
1029 rlcWinSz = RLC_AM_TRANS_WIN_SIZE(&RLC_AMDL);
1030 if (rlcWinSz > rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxWindowSz)
1032 rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxWindowSz = rlcWinSz;
1038 /* Update BO and estimate header size for the current BO */
1039 RLC_AMDL.bo = RLC_AMDL.bo + sdu->sduSz;
1040 if(RLC_AMDL.snLen == RLC_AM_CFG_12BIT_SN_LEN)
1042 RLC_AMDL.estHdrSz += 2;
1046 RLC_AMDL.estHdrSz += 3;
1048 #ifdef LTE_L2_MEAS_RLC
1049 /* Update numActUe if it is not active */
1050 if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_ACT_UE) &&
1051 (rbCb->ueCb->numActRb[rbCb->qci] == 0))
1053 rbCb->ueCb->numActRb[rbCb->qci]++;
1054 gCb.rlcL2Cb.numActUe[rbCb->qci]++;
1058 if(!rlcDlUtlIsReestInProgress(rbCb))
1060 rlcAmmSendDedLcBoStatus(gCb, rbCb, &RLC_AMDL);
1068 * @brief Private handler to construct control PDU
1071 * This function sets the pduSz correctly after eliminating the fixed
1072 * header sizes and the MAC header size. It copies the already prepared
1073 * STATUS PDU to the data to be sent to MAC.
1075 * @param[in] gCb RLC instance control block
1076 * @param[in] rbCb Downlink RB control block
1077 * @param[in] kwdatReq DatReq to be sent to MAC
1082 static void rlcAmmDlAssembleCntrlInfo(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
1084 RlcUdxDlSapCb *sapCb;
1087 macHdrEstmt = (rbCb->m.amDl.cntrlBo < 256) ?
1088 RLC_MAC_HDR_SZ2 : RLC_MAC_HDR_SZ3;
1089 /* Eliminate fixed hdr size (14bits including ACK_SN) */
1090 if (rlcDatReq->pduSz >= (RLC_CNTRL_PDU_FIXED_HDRSZ + macHdrEstmt))
1092 /* Check the TB size whether it is sufficcient enough to fit the
1093 status Pdu into it otherwise make arrangement such that it can fit
1094 into in a way of possible NACks*/
1095 /* ccpu00135743 : fix for MAC Hdr size calc */
1096 rlcDatReq->pduSz -= macHdrEstmt;
1098 /* Create the status Pdu with the required NACKs */
1099 rlcAmmCreateStatusPdu(gCb,rbCb,rlcDatReq);
1101 sapCb = RLC_GET_DL_SAPCB(gCb, rbCb);
1102 rlcDlUdxStaProhTmrStart(&(gCb->u.dlCb->udxDlSap->pst),
1103 sapCb->suId, &(rbCb->rlcId));
1105 /* Update number of pdus in pduInfo */
1106 rlcDatReq->pduInfo.mBuf[rlcDatReq->pduInfo.numPdu] = RLC_AMDL.mBuf;
1107 rlcDatReq->pduInfo.numPdu++;
1108 gRlcStats.amRlcStats.numDLStaPduSent++;
1110 RLC_FREE_SHRABL_BUF(gCb->u.dlCb->udxDlSap->pst.region,
1111 gCb->u.dlCb->udxDlSap->pst.pool,
1113 sizeof(RlcUdxDlStaPdu));
1115 RLC_AMDL.pStaPdu = NULLP;
1116 RLC_AMDL.mBuf = NULLP;
1117 gRlcStats.amRlcStats.numDLStaPduSent++;
1124 * @brief Handler to form the PDUs with the size indicated by MAC
1127 * This function is invoked by UTL with the PDU size indicated by
1128 * MAC (after eliminating MAC header size). It assembles control
1129 * Info / data (New SDUs / Retx PDUs), check if polling needs to be
1130 * set for the data PDU and returns PDU(s) and updated BO with
1131 * estimated header size to be sent to MAC.
1133 * - Check if the control BO is available and call rlcAssembleCntrlInfo
1134 * to assemble control Information
1135 * - Check if the pdu size is available to form PDUs from retransmission
1136 * buffer and call rlcResegRetxPdus
1137 * - Check if the pdu size is available and assemble SDUs from sduQ
1138 * if exist, using rlcAssembleSdus
1139 * - PDU Info and bo are filled in and then sent to MAC from the
1142 * @param[in] gCb RLC instance control block
1143 * @param[in] rbCb RB control block
1144 * @param[in] kwdatReq DatReq to be sent to MAC
1145 * @param[in] fillCtrlPdu Indicates whether cntrl PDU to be filled or not
1150 void rlcAmmProcessSdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq, bool fillCtrlPdu)
1152 /* Assemble control information. fillCtrlPdu parameter check is added for CA
1153 * It is used to force cntrl Pdu scheduling on PCell. for Non CA case this
1154 * flag will always be TRUE. In CA case, for PCELL it is TRUE and for SCEll
1157 if ((RLC_AMDL.cntrlBo != 0)
1163 rlcDatReq->boRep.staPduPrsnt = TRUE;
1164 rlcDatReq->boRep.staPduBo = RLC_AMDL.cntrlBo;
1166 if (RLC_AMDL.pStaPdu != NULLP)
1168 rlcAmmDlAssembleCntrlInfo (gCb, rbCb, rlcDatReq);
1172 DU_LOG("\nERROR --> RLC_DL : rlcAmmProcessSdus: Miscomputation of control Bo. \
1173 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1175 RLC_AMDL.cntrlBo = 0;
1178 /* Retransmit PDUs /portions of PDUs available in retxLst */
1179 if ((rlcDatReq->pduSz > 0) && (RLC_AMDL.nxtRetx != NULLP))
1181 rlcResegRetxPdus (gCb,rbCb, rlcDatReq);
1184 /* Assemble SDUs to form new PDUs */
1185 if ((rlcDatReq->pduSz > 0) && (RLC_AMDL.nxtTx != 0))
1187 rlcAssembleSdus(gCb,rbCb, rlcDatReq);
1190 if (RLC_AMDL.nxtRetx != NULLP)
1192 rlcDatReq->boRep.oldestSduArrTime = RLC_AMDL.nxtRetx->sduMap.sdu->arrTime;
1194 else if (RLC_AMDL.nxtTx != NULLP)
1196 rlcDatReq->boRep.oldestSduArrTime = RLC_AMDL.nxtTx->arrTime;
1199 rlcDatReq->boRep.bo = rlcAmmCalculateBo(&RLC_AMDL);
1200 rlcDatReq->boRep.staPduBo = RLC_AMDL.cntrlBo;
1202 /* Hdr estimation is moved to kwAmmCreatePDu */
1203 rlcDatReq->boRep.estHdrSz = RLC_AMDL.estHdrSz;
1205 if(rlcDatReq->pduSz > 0)
1207 gRlcStats.amRlcStats.numDLBytesUnused += rlcDatReq->pduSz;
1213 * @brief Private handler split a PDU/segment into two
1216 * Its a private function called by kwResegRetxPdu to split a segment
1217 * or a retransmit PDU into two segments splitting at the passed size.
1218 * This function is called only for those PDUs that dont have any LIs.
1220 * @param[in] gCb RLC instance control block
1221 * @param[in] rbCb RB control block
1222 * @param[in,out] crnt The PDU to be split, first part of split pdu remians
1224 * @param[out] next The second part of the split pdu
1225 * @param[in] size The size witin crnt, at which to split
1230 static void rlcSplitPdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcRetx *crnt, RlcRetx *next, uint16_t size)
1233 RlcAmDl *amDl = &RLC_AMDL;
1235 /* Set the SN for the new segment */
1236 next->amHdr.sn = crnt->amHdr.sn;
1238 /* Set the protocol specific fields appropriately */
1239 si = crnt->amHdr.si;
1240 crnt->amHdr.si = si | RLC_SI_FIRST_SEG;
1241 next->amHdr.si = si | RLC_SI_LAST_SEG;
1245 /* Update seg size */
1246 next->segSz = crnt->segSz - size;
1249 /* Set the SO fields appropriately */
1250 /* MS_FIX for DL stall */
1251 next->soEnd = crnt->soEnd;
1253 /* Set the SO fields appropriately */
1254 /* SO of next will be after the end of current */
1255 next->amHdr.so = crnt->amHdr.so + crnt->segSz;
1256 /* SO End of current will be one less than the start of next */
1257 crnt->soEnd = next->amHdr.so - 1;
1259 /* intialize the other fields in the amHdr of next to 0 */
1263 /* This macro is called for No LI case - one SDU */
1264 /* Update the size of SDU in each node's sduMap */
1265 next->sduMap.sdu = crnt->sduMap.sdu;
1266 crnt->sduMap.sduSz = crnt->segSz;
1267 next->sduMap.sduSz = next->segSz;
1269 /* Segment the payload into two parts based on the size passed */
1270 ODU_SEGMENT_MSG(crnt->seg, size, &next->seg);
1271 next->retxCnt = crnt->retxCnt;
1272 next->yetToConst = TRUE;
1273 next->pendingReTrans = crnt->pendingReTrans;
1275 /* Compute the header size and update the BO appropriately */
1276 if(amDl->snLen == RLC_AM_CFG_12BIT_SN_LEN)
1278 next->hdrSz = RLC_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1279 if(crnt->amHdr.si == RLC_SI_FIRST_SEG)
1281 crnt->hdrSz = RLC_AM_SEG_12BIT_SN_WITHOUT_SO_HDRSZ;
1285 crnt->hdrSz = RLC_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1290 next->hdrSz = RLC_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1291 if(crnt->amHdr.si == RLC_SI_FIRST_SEG)
1293 crnt->hdrSz = RLC_AM_SEG_18BIT_SN_WITHOUT_SO_HDRSZ;
1297 crnt->hdrSz = RLC_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1301 /* Add the next to the retx list */
1302 RLC_AMDL.retxLst.crnt = &crnt->lstEnt;
1303 CM_LLIST_INS_AFT_CRNT(RLC_AMDL.retxLst, next);
1304 RLC_AMDL.nxtRetx = next;
1305 amDl->estHdrSz += next->hdrSz;
1311 * @brief Private handler to retransmit PDUs or PDU segments
1314 * Its a private function called by kwProcessSdus, to create the
1315 * PDUs / its segments from the retransmission buffer available in RbCb.
1317 * - Eliminate the fixed header size and MAC header size while
1318 * forming PDUs/segments
1319 * - While pdusize is available and retxBuf has data (pdu or portion
1320 * of pdu) to be sent, form the pdu as it is if it matches with the
1321 * pdusize else segment the PDUs/portion of PDUs
1322 * - Call rlcAmmDlCheckAndSetPoll function to check and set the poll bit as
1324 * - Concatenate data and header info and fill pduInfo
1325 * - Update retxCnt and send indication to PDCP if it reaches maxRetx
1328 * @param[in] gCb RLC instance control block
1329 * @param[in] rbCb RB control block
1330 * @param[in] kwdatReq DatReq to be sent to MAC
1335 static void rlcResegRetxPdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
1339 uint8_t hdr[RLC_MAX_HDRSZ];
1345 RlcL2MeasTb *l2MeasTb;
1346 RlclchInfo *lchInfo;
1352 /* TODO : This shoould be taken care in new Trasmissions */
1353 /* This lchInfo should be retrieved there */
1354 l2MeasTb = rlcUtlGetCurMeasTb(gCb, rbCb);
1355 if (l2MeasTb == NULLP)
1359 /* TODO : This lcid needs to be searched in case of normal Tx */
1360 /* In retx here, its fine as this will be higher priority */
1361 lchInfo = &l2MeasTb->lchInfo[l2MeasTb->numLchInfo];
1362 if (l2MeasTb->numLchInfo >= RLC_MAX_ACTV_DRB)
1366 l2MeasTb->numLchInfo++;
1367 lchInfo->lcId = rbCb->lch.lChId;
1368 lchInfo->numSdus = 0;
1371 while ((rlcDatReq->pduSz > 0) && (amDl->nxtRetx != NULLP)&&
1372 (rlcDatReq->pduInfo.numPdu < RLC_MAX_PDU))
1376 retx = amDl->nxtRetx;
1377 /* kw003.201 : Add header size to seg size to determine if the */
1378 /* the segment can be completed within the allocation */
1379 /* kw003.201 - Eliminate MAC Header Size based on bites needed */
1380 tmpSz = RLC_MIN((retx->segSz + retx->hdrSz), rlcDatReq->pduSz);
1381 pduSz = (retx->segSz + retx->hdrSz);
1382 /* 5GNR_RLC_DL : length field in 5GNR MAC Hdr is 8/16 btis*/
1383 rlcDatReq->pduSz -= (tmpSz < 255) ? RLC_MAC_HDR_SZ2 : RLC_MAC_HDR_SZ3;
1385 /* kw003.201 - We should have at least one more than basic header */
1386 if (rlcDatReq->pduSz <= retx->hdrSz)
1390 rlcGetNxtRetx(gCb, &(amDl->nxtRetx));
1392 /* Send retx buf without segmentation */
1393 if (rlcDatReq->pduSz >= pduSz)
1397 DU_LOG("\nINFO --> RLC_DL : rlcResegRetxPdus: Send retx buf without segmentation "
1398 "UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1400 if (retx->yetToConst)
1402 /* Construct hdr with the available hdr values */
1403 rlcConstructAmHdr(&retx->amHdr, hdr, amDl->snLen, &idx);
1404 /* Add header to the pdu/segment */
1405 ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx + 1, retx->seg);
1406 retx->yetToConst = FALSE;
1409 /* kw003.201 - Check if poll bit needs to be set. Retx size does */
1410 /* not affect the poll bit so it is being passed as zero */
1411 pollBit = rlcAmmDlCheckAndSetPoll(gCb,rbCb, FALSE, 0);
1412 RLC_UPD_POLL_BIT(gCb, retx, pollBit);
1414 rlcDatReq->pduSz -= pduSz;
1415 RLC_AMDL.estHdrSz -= retx->hdrSz;
1418 if (rbCb->rlcId.rbType == CM_LTE_DRB)
1421 for (sduIdx = lchInfo->numSdus ;
1422 ((numSdus < retx->numSdu) && (sduIdx < RLC_L2MEAS_SDUIDX)) ;
1423 sduIdx++, numSdus++)
1425 lchInfo->sduInfo[sduIdx].arvlTime = retx->sduMap[numSdus].sdu->arrTime;
1426 lchInfo->sduInfo[sduIdx].isRetxPdu = TRUE; /* TODO : for later use */
1428 lchInfo->numSdus += numSdus;
1436 /* Segment this pdu / portion of pdu. Insert this segment into */
1437 /* retxLst and update offset */
1438 DU_LOG("\nINFO --> RLC_DL : rlcResegRetxPdus: Segment retx buf UEID:%d CELLID:%d",
1439 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1441 /* Eliminate fixed header size if the pdu is segmented for the */
1443 if(amDl->snLen == RLC_AM_CFG_12BIT_SN_LEN)
1445 if(retx->amHdr.si < RLC_SI_LAST_SEG)
1447 rlcDatReq->pduSz -= RLC_AM_SEG_12BIT_SN_WITHOUT_SO_HDRSZ;
1451 rlcDatReq->pduSz -= RLC_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1456 if(retx->amHdr.si < RLC_SI_LAST_SEG)
1458 rlcDatReq->pduSz -= RLC_AM_SEG_18BIT_SN_WITHOUT_SO_HDRSZ;
1462 rlcDatReq->pduSz -= RLC_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1465 if (rlcDatReq->pduSz <= 0)
1470 /* Allocate memory for tracking a new segment */
1471 RLC_ALLOC_WC(gCb,tNode, sizeof(RlcRetx));
1472 #if (ERRCLASS & ERRCLS_ADD_RES)
1475 DU_LOG("\nERROR --> RLC_DL : rlcResegRetxPdus: Memory allocation failed UEID:%d CELLID:%d",
1476 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1479 #endif /* ERRCLASS & ERRCLS_RES */
1481 /* initialize the list pointer to 0 instead of memset */
1482 tNode->lstEnt.next = 0;
1483 tNode->lstEnt.prev = 0;
1485 /* Segment header and data */
1486 RLC_AM_RMV_HDR(gCb, rbCb, retx);
1488 /* kw003.201 - Split the payload and update other fields */
1489 rlcSplitPdu(gCb,rbCb, retx, tNode, rlcDatReq->pduSz);
1494 sduIdx = lchInfo->numSdus;
1495 for (numSdus = 0, sduIdx = lchInfo->numSdus;
1496 ((numSdus < retx->numSdu) && (sduIdx < RLC_L2MEAS_SDUIDX));
1497 numSdus++, sduIdx++)
1499 lchInfo->sduInfo[sduIdx].arvlTime =
1500 retx->sduMap[numSdus].sdu->arrTime;
1501 lchInfo->sduInfo[sduIdx].isRetxPdu = TRUE;
1503 lchInfo->numSdus = sduIdx;
1504 if ((retx->amHdr.lsf == 0) && (lchInfo->numSdus > 0))
1509 /* Construct hdr with the available hdr values */
1510 rlcConstructAmHdr(&retx->amHdr, hdr, amDl->snLen, &idx);
1511 ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx + 1, retx->seg);
1513 retx->hdrSz = idx + 1;
1515 /* Poll bit need not be set for this seg, since its second */
1516 /* half remains in retxLst */
1517 RLC_UPD_POLL_BIT(gCb, retx, FALSE);
1518 retx->yetToConst = FALSE;
1519 rlcDatReq->pduSz = 0;
1522 rlcCpyMsg(gCb,retx->seg, &pdu);
1524 /* Update pduInfo */
1525 rlcDatReq->pduInfo.mBuf[rlcDatReq->pduInfo.numPdu] = pdu;
1526 rlcDatReq->pduInfo.numPdu++;
1527 /* kw005.201 ccpu00117318, updating the statistics */
1528 gCb->genSts.pdusRetx += 1;
1529 gRlcStats.amRlcStats.numRlcAmCellRetxPdu++;
1530 retx->soEnd = retx->amHdr.so + retx->segSz - 1;
1531 retx->pendingReTrans = FALSE;
1532 amDl->retxBo -= retx->segSz;
1535 DU_LOG("\nINFO --> RLC_DL : rlcResegRetxPdus: retxBo after resegmentation = %ld"
1536 "UEID:%d CELLID:%d", amDl->retxBo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1538 DU_LOG("\nINFO --> RLC_DL : rlcResegRetxPdus: retxBo after resegmentation = %d "
1539 "UEID:%d CELLID:%d", amDl->retxBo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1547 * @brief Private handler to assemble SDUs to form new data PDU(s)
1550 * Its a private function called by kwProcessSdus, to create the new data
1551 * PDUs from the SDU queue of RbCb.
1553 * - While pdusize is available, segment/concatenate SDUs or else if it
1554 * matches the pdu size form PDUs accordingly.
1555 * - RLC header and MAC header size are eliminated while forming the PDUs
1556 * - Call rlcAmmDlCheckAndSetPoll function to check and set the poll bit
1558 * - Concatenate data and header info and fill pduInfo
1560 * @param[in] rbCb RB control block
1561 * @param[in] kwdatReq DatReq to be sent to MAC
1566 static void rlcAssembleSdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
1568 Buffer *pdu = NULLP;
1569 MsgLen macGrntSz = rlcDatReq->pduSz;
1570 RlcAmDl *amDl = &RLC_AMDL;
1571 RlcSdu *sdu = amDl->nxtTx;
1573 bool nxtTxUpd = FALSE;
1574 KwuDiscSduInfo *discSduInfo = NULLP;
1575 RlcKwuSapCb* rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
1577 RlcContSduLst contSduLst; /*Contained sduLst */
1578 int32_t dataVol = amDl->bo;
1579 uint32_t *totMacGrant = &rlcDatReq->totMacGrant;
1580 RlcL2MeasDlIpTh *dlIpThPut = &rbCb->l2MeasIpThruput.dlIpTh;
1581 uint8_t *sduIdx = &dlIpThPut->lastSduIdx;
1583 bool isSduSegmented;
1586 RlclchInfo *dstLchInfo;
1587 uint32_t segSduCnt = 0;
1589 uint32_t numSdus = 0;
1590 uint32_t currSduIdx = 0;
1591 RlcL2MeasTb *l2MeasTb;
1593 /* Discard new changes starts */
1596 uint8_t numNewPdu = 0;
1597 RlcTx *txBuf = NULLP;
1598 /* Discard new changes ends */
1599 volatile uint32_t startTime = 0;
1601 uint32_t fixedHdrSz;
1603 RlcAmHdr *amHdr = NULLP;
1604 RlcDlPduInfo *pduInfo = NULLP;
1607 contSduLst.numSdus = 0;
1608 contSduLst.lcId = rbCb->lch.lChId;
1610 lchInfo.lcId = rbCb->lch.lChId;
1611 lchInfo.numSdus = 0;
1613 /* Discard new changes starts */
1614 /* Allocate memory for discSdu Info */
1615 RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region,
1616 rlckwuSap->pst.pool,
1618 sizeof(KwuDiscSduInfo));
1620 #if (ERRCLASS & ERRCLS_ADD_RES)
1621 if (discSduInfo == NULLP)
1623 DU_LOG("\nERROR --> RLC_DL : rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1624 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1627 #endif /* ERRCLASS & ERRCLS_RES */
1629 discSduInfo->numSduIds = 0;
1630 discSduInfo->rlcId = rbCb->rlcId;
1632 rlcUtlGetCurrTime(&curTime);
1633 amDl->sduQ.crnt = &sdu->lstEnt;
1634 /* Eliminate fixed header size */
1635 /*5GNR: value of RLC_AM_PDU_FIXED_HDRSZ will be 2 or 3 depending on SN Size*/
1636 if(amDl->snLen == RLC_AM_CFG_12BIT_SN_LEN)
1638 fixedHdrSz = RLC_AM_PDU_12BIT_SN_HDRSZ;
1642 fixedHdrSz = RLC_AM_PDU_18BIT_SN_HDRSZ;
1645 while ((macGrntSz > fixedHdrSz) && (sdu != NULLP) &&
1646 (rlcDatReq->pduInfo.numPdu < RLC_MAX_PDU) &&
1647 (numNewPdu < RLC_MAX_NEW_DL_PDU))
1650 isSduSegmented = sdu->mode.am.isSegmented;
1652 /* Discard new changes starts */
1653 if ((sdu->mode.am.isSegmented == FALSE) && (rbCb->discTmrInt > 0) && \
1654 (rbCb->rlcId.rbType == CM_LTE_DRB))
1656 //leftAmSdus[rbCb->qci]--;
1657 timeDiff = RLC_TIME_DIFF(curTime,sdu->arrTime);
1658 if (timeDiff > rbCb->discTmrInt)
1662 SStartTask(&startTime, PID_RLC_AMM_DISC_SDUS);
1664 RLC_UPD_L2_DL_DISC_SDU_STS(gCb,rbCb);
1665 /* TODO need to send disc cfm to pdcp */
1667 /* Update bo for boReport */
1668 amDl->bo -= sdu->sduSz;
1670 /* Get next sdu for assembly */
1671 nxtNode = sdu->lstEnt.next;
1673 /* store the info for sending it to PDCP */
1674 if(discSduInfo->numSduIds > 500)
1676 DU_LOG("\nERROR --> RLC_DL : rlcAssembleSdus: This is a big error, we shouldn't be here"
1677 "UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1681 discSduInfo->sduIds[discSduInfo->numSduIds] = sdu->mode.am.sduId;
1682 discSduInfo->numSduIds++;
1684 cmLListDelFrm(&amDl->sduQ, &sdu->lstEnt);
1686 rlcUtlAddSduToBeFreedQueue(gCb, sdu);
1687 rlcUtlRaiseDlCleanupEvent(gCb);
1689 /* We need to restore the crnt in the linked list which
1690 * would have become NULL in the DelFrm above */
1691 amDl->sduQ.crnt = nxtNode;
1694 sdu = (RlcSdu*)nxtNode->node;
1699 ODU_STOP_TASK(startTime, PID_RLC_AMM_DISC_SDUS);
1708 /** kw003.201 - Check for window stall when you are
1709 * creating a new PDU
1711 if (RLC_AM_IS_TRANS_WIN_STALLED(amDl))
1714 DU_LOG("\nINFO --> RLC_DL : Window stalled \n");
1715 gRlcStats.amRlcStats.numRlcAmCellWinStall++;
1720 hdrEstmt = fixedHdrSz;
1722 if (sdu->mode.am.isSegmented)
1724 /* Adding two byte for SO */
1727 /* Eliminate MAC header */
1728 /* ccpu00135743 : Fix for MAC Hdr size calculation */
1729 /*5GNR: value of mac hdr length field changed to 8/16bits */
1730 pduSz = RLC_MIN(macGrntSz, (sdu->sduSz + hdrEstmt));
1731 hdrEstmt += (pduSz < 255) ? RLC_MAC_HDR_SZ2 : RLC_MAC_HDR_SZ3;
1733 macGrntSz -= hdrEstmt;
1734 /* kw005.201 Check for PDU Size is large enough.
1735 * Fix for ccpu00118973
1742 /* Dont create new txBuf for segmented SDU */
1743 if (!sdu->mode.am.isSegmented)
1746 RLC_ALLOC_WC(gCb,txBuf, sizeof(RlcTx));
1748 cmLListInit(&txBuf->pduLst);
1750 #if (ERRCLASS & ERRCLS_ADD_RES)
1753 uint32_t avblMem = 0;
1754 SRegInfoShow(gCb->init.region, &avblMem);
1755 DU_LOG("\nERROR --> RLC_DL : rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1756 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1759 #endif /* ERRCLASS & ERRCLS_RES */
1761 rlcUtlStoreTxBuf(amDl->txBufLst, txBuf, amDl->txNext);
1765 txBuf = rlcUtlGetTxBuf(amDl->txBufLst, amDl->txNext);
1768 RLC_ALLOC_WC(gCb,pduInfo, sizeof(RlcDlPduInfo));
1769 #if (ERRCLASS & ERRCLS_ADD_RES)
1770 if (pduInfo == NULLP)
1772 uint32_t avblMem = 0;
1773 SRegInfoShow(gCb->init.region, &avblMem);
1774 DU_LOG("\nERROR --> RLC_DL : rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1775 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1778 #endif /* ERRCLASS & ERRCLS_RES */
1780 /*Initialize DL segment structure */
1781 pduInfo->lstEnt.next = NULLP;
1782 pduInfo->lstEnt.prev = NULLP;
1783 pduInfo->lstEnt.node = NULLP;
1785 pduInfo->pdu = NULLP;
1786 pduInfo->amHdr.dc = 0;
1787 pduInfo->amHdr.p = 0;
1788 pduInfo->amHdr.si = 0;
1789 pduInfo->amHdr.so = 0;
1791 pduInfo->amHdr.sn = amDl->txNext;
1793 if (macGrntSz >= sdu->sduSz)
1797 /* Update Framing Info */
1798 if (sdu->mode.am.isSegmented)
1800 /*5GNR RLC_DL : SN should be same for all segment of a SDU*/
1801 pduInfo->amHdr.sn = sdu->mode.am.sn;
1802 pduInfo->amHdr.si = RLC_SI_LAST_SEG; /* binary 10 */
1803 pduInfo->amHdr.so = sdu->actSz - sdu->sduSz;
1804 sdu->mode.am.isSegmented = FALSE;
1807 gRlcStats.amRlcStats.numRlcAmCellSduTx++;
1808 //DU_LOG("\nINFO --> RLC_DL : 5GNRLOG: last segment of lcId %d SduId %u So %u macGrntSz\
1809 %u sduActSz %u sdu->sduSz %u\n",
1810 // rbCb->lch.lChId, sdu->mode.am.sduId, pduInfo->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
1814 gRlcStats.amRlcStats.numRlcAmCellSduTx++;
1816 amHdr = &pduInfo->amHdr;
1817 /* Create PDU with hdr and data */
1818 rlcAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
1820 //DU_LOG("\nINFO --> Segmentation not required case: numPdu %d pdu %p \n",rlcDatReq->pduInfo.numPdu, pdu);
1822 #ifdef LTE_L2_MEAS_RLC
1823 rlcUtlUpdSduSnMap(rbCb, sdu, rlcDatReq, TRUE);
1824 #endif /* LTE_L2_MEAS */
1826 /* kw005.201 ccpu00117318, updating the statistics */
1827 rlcUtlIncrementKwuStsSduTx(gCb->u.dlCb->rlcKwuDlSap + rbCb->k1wuSapId);
1829 if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb))
1833 *sduIdx = dlIpThPut->lastSduIdx;
1837 RLC_GETSDUIDX(*sduIdx);
1840 rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
1841 rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
1842 sdu->mode.am.sduId, newIdx);
1843 /* Update the arrival time for each SDU */
1845 if ( lchInfo.numSdus < RLC_L2MEAS_SDUIDX)
1847 lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime;
1852 sduMap.sduSz = sdu->sduSz;
1857 * Allocate buffer for next PDU
1858 * Remove the segmented portion from SDUQ
1859 * Calculate the hdr with LI for SDU */
1861 Buffer *remSeg = NULLP;
1863 //DU_LOG("\nINFO --> SDU segmentation case: numPdu %d pdu %p \n", rlcDatReq->pduInfo.numPdu, pdu);
1865 if(RLC_MEAS_IS_DL_IP_MEAS_ON_FOR_RB(gCb,rbCb) ||
1866 RLC_MEAS_IS_DL_DELAY_MEAS_ON_FOR_RB(gCb,rbCb) ||
1867 RLC_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb) )
1869 /* If actual size of the sdu is equal to msgLen
1870 * then it is first segment of the SDU */
1871 if(sdu->actSz == sdu->sduSz)
1873 RLC_GETSDUIDX(*sduIdx);
1878 *sduIdx = dlIpThPut->lastSduIdx;
1880 rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
1881 rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
1882 sdu->mode.am.sduId, newIdx);
1883 if(RLC_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb))
1885 /* If actual size of the sdu is equal to msgLen
1886 * then it is first segment of the SDU */
1887 if(sdu->actSz == sdu->sduSz)
1895 /* Segment the SDU to the size of the PDU and update header Info */
1896 ODU_SEGMENT_MSG(sdu->mBuf, macGrntSz, &remSeg);
1900 /* Update SI and SN */
1901 if (sdu->mode.am.isSegmented)
1903 /*5GNR RLC_DL : SN should be same for all segment of a SDU.
1904 * Sdu was already segmented and segmenting again*/
1905 pduInfo->amHdr.sn = sdu->mode.am.sn;
1906 pduInfo->amHdr.si = RLC_SI_MID_SEG; /* binary 11 */
1907 pduInfo->amHdr.so = sdu->actSz - sdu->sduSz;
1909 //DU_LOG("\nINFO --> RLC_DL : 5GNRLOG: mid segment of lcId %d SduId %u So %u macGrntSz %u sduActSz\
1910 %u sdu->sduSz %u\n",
1911 // rbCb->lch.lChId, sdu->mode.am.sduId, txBuf->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
1915 /*5GNR RLC_DL : This means it is the first*/
1916 pduInfo->amHdr.si = RLC_SI_FIRST_SEG; /* binary 01 */
1917 /*5GNR_RLC_DL : Store SN so that in sub-seqent SDU segments will use this SN*/
1918 sdu->mode.am.sn = pduInfo->amHdr.sn;
1919 pduInfo->amHdr.so = 0;
1921 //DU_LOG("\nINFO --> RLC_DL : 5GNRLOG: First segment of lcId %d SduId %u So\
1922 %u macGrntSz %u sduActSz %u sdu->sduSz %u\n",
1923 // rbCb->lch.lChId, sdu->mode.am.sduId, txBuf->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
1926 amHdr = &pduInfo->amHdr;
1927 /* Create PDU with hdr and data */
1928 rlcAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
1930 sdu->mode.am.isSegmented = TRUE;
1931 sdu->sduSz -= macGrntSz;
1932 sduMap.sduSz = macGrntSz;
1934 #ifdef LTE_L2_MEAS_RLC
1935 rlcUtlUpdSduSnMap(rbCb, sdu, rlcDatReq, FALSE);
1936 #endif /* LTE_L2_MEAS */
1942 /* Update bo for boReport */
1943 amDl->bo -= sduMap.sduSz;
1947 /* Update pduInfo */
1948 rlcDatReq->pduInfo.mBuf[rlcDatReq->pduInfo.numPdu] = pdu;
1949 rlcDatReq->pduInfo.numPdu++;
1951 /* kw005.201 ccpu00117318, updating the statistics */
1952 gCb->genSts.pdusSent++;
1953 gRlcStats.amRlcStats.numRlcAmCellSduBytesTx = gRlcStats.amRlcStats.numRlcAmCellSduBytesTx + sduMap.sduSz;
1954 /* Update the RLC Tx buffer with the new PDU info */
1955 RLC_MEM_CPY(&pduInfo->sduMap, &sduMap, sizeof(RlcSduMap));
1958 macGrntSz -= sduMap.sduSz;
1959 /* Get next sdu for assembly */
1960 RLC_LLIST_NEXT_SDU(amDl->sduQ, sdu);
1962 } /*End of pduSz loop */
1964 rlcDatReq->pduSz = macGrntSz;
1965 /* Updating nxtTx to sdu in the Q */
1970 if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) &&
1971 (rbCb->rlcId.rbType == CM_LTE_DRB))
1975 l2MeasTb = rlcUtlGetCurMeasTb(gCb, rbCb);
1976 rlcUtlUpdateBurstSdus(gCb, rbCb, &contSduLst, dataVol, *totMacGrant);
1977 if ((lchInfo.numSdus != 0) && (l2MeasTb != NULLP))
1979 for (lchIdx = 0; ((lchIdx < l2MeasTb->numLchInfo)
1980 && (lchIdx < RLC_MAX_ACTV_DRB )); lchIdx++)
1982 if (l2MeasTb->lchInfo[lchIdx].lcId == rbCb->lch.lChId)
1984 /* Lch Info already added in Retx procedure */
1988 if (lchIdx < RLC_MAX_ACTV_DRB)
1990 if (lchIdx == l2MeasTb->numLchInfo)
1992 l2MeasTb->lchInfo[lchIdx].lcId = rbCb->lch.lChId;
1993 l2MeasTb->lchInfo[lchIdx].numSdus = 0;
1994 l2MeasTb->numLchInfo++;
1996 dstLchInfo = &l2MeasTb->lchInfo[lchIdx];
1997 currSduIdx = l2MeasTb->lchInfo[lchIdx].numSdus;
1998 while ((numSdus < lchInfo.numSdus) && (currSduIdx < RLC_L2MEAS_SDUIDX))
2000 dstLchInfo->sduInfo[currSduIdx].arvlTime = lchInfo.sduInfo[numSdus].arvlTime;
2001 dstLchInfo->sduInfo[currSduIdx].isRetxPdu = FALSE;
2005 l2MeasTb->lchInfo[lchIdx].numSdus += numSdus;
2008 /* Fix Klock warning */
2009 if(l2MeasTb != NULLP)
2011 l2MeasTb->txSegSduCnt += segSduCnt;
2014 *totMacGrant -= (oldBo - amDl->bo);
2017 if(discSduInfo->numSduIds != 0)
2019 /* Sap control block */
2020 RlcUiKwuDiscSduCfm(&rlckwuSap->pst, rlckwuSap->suId, discSduInfo);
2024 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, discSduInfo, sizeof(KwuDiscSduInfo));
2027 DU_LOG("\nDEBUG --> RLC_DL : rlcAssembleSdus: BO after assembly = %d UEID:%d CELLID:%d",
2028 amDl->bo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
2033 * @brief Private handler to check if the poll bit needs to be set for data PDU
2036 * Its a private function called by kwProcessSdus, to checks if the
2037 * polling bit needs to be set for any RLC data PDU and updates the
2039 * - For the new PDUs, if the counters exceed the configured
2040 * pduWoPoll/byteWoPoll values, return poll bit.
2041 * - For the PDUs/portion of PDUs, if the SDU list / retxBuf is
2042 * empty, return poll bit.
2043 * - Update the pollPdu, pollByte counters and Poll_SN; start staProhTmr
2045 * @param[in] rCb RLC instance control block
2046 * @param[in] rbCb RB control block
2047 * @param[in] newPdu Flag to indicate if its a new AMD PDU.
2048 * @param[in] bufSz Length of the PDU
2051 * -# 1 - To set the poll bit
2052 * -# 0 - Poll bit is not set
2055 static bool rlcAmmDlCheckAndSetPoll(RlcCb *gCb, RlcDlRbCb *rbCb, bool newPdu, MsgLen bufSz)
2057 bool pollBit = FALSE;
2058 RlcAmDl *amDl = &(rbCb->m.amDl);
2060 /* If it's a new PDU increment PDU without poll and bytes without poll
2061 and check if they cross the configured number of poll pdu and poll bytes*/
2065 /* Patch kw004.201 */
2066 amDl->byteWoPoll += bufSz;
2068 if (((amDl->pollPdu != -1) && (amDl->pduWoPoll >= amDl->pollPdu)) ||
2069 ((amDl->pollByte != -1) && (amDl->byteWoPoll >= amDl->pollByte)))
2075 /* Check if both tx/retx buffer are empty or if tx window is stalled */
2076 if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) ||
2077 RLC_AM_IS_TRANS_WIN_STALLED(amDl))
2084 amDl->pduWoPoll = 0;
2085 amDl->byteWoPoll = 0;
2087 amDl->pollSn = (amDl->txNext - 1) & amDl->snModMask;
2089 DU_LOG("\nINFO --> RLC_DL : rlcAmmDlCheckAndSetPoll: Poll SN = %d UEID:%d CELLID:%d",
2090 amDl->pollSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
2092 /* kw005.201: Fix for poll retransmission timer.
2093 * Timer is stopped if it is already running and
2094 * then starting the timer. Fixes crs
2095 * ccpu00117216 and ccpu00118284 .
2097 if( TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMDL_POLL_RETX_TMR) )
2099 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR);
2102 rlcStartTmr(gCb,(PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR);
2109 * @brief Private handler to create AMD PDU
2112 * This function constructs header and concatenate it with the data for
2113 * the PDU. It also updates the txBuf with the created PDU.
2115 * @param[in] gCB RLC instance control block
2116 * @param[in] rbCb Downlink RB control block
2117 * @param[in] amHdr AM header
2118 * @param[in] RlcDlPduInfo Pointer to PduInfo
2119 * @param[in] pdu PDU buffer
2124 static void rlcAmmCreatePdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcAmHdr *amHdr,
2125 RlcDlPduInfo *pduInfo, Buffer *pdu)
2127 uint8_t hdr[RLC_MAX_HDRSZ];
2131 RlcAmDl *amDl = &(rbCb->m.amDl);
2134 amHdr->sn = amDl->txNext;
2136 /*5GNR RLC_DL : Increment txNext only if no segmentation of it is a last segment */
2137 if((!amHdr->si) || (amHdr->si == RLC_SI_LAST_SEG))
2139 //DU_LOG("\nINFO --> RLC_DL : 5GNRLOG: no segment/last seg SDU with lcId %d Sn %u txNext %u So %u\n",
2140 // rbCb->lch.lChId, amHdr->sn, amDl->txNext, amHdr->so);
2141 amDl->txNext = (amDl->txNext + 1) & amDl->snModMask;
2144 /* Update hdr Info */
2145 ODU_GET_MSG_LEN(pdu, &pduSz);
2147 /* passing newPDU = TRUE*/
2148 amHdr->p = rlcAmmDlCheckAndSetPoll(gCb,rbCb, TRUE, pduSz);
2150 /* Construct header with the available hdr Info, set isSegment to FALSE */
2151 rlcConstructAmHdr(amHdr, hdr, amDl->snLen, &idx);
2153 /* Concatenate hdr and data */
2154 ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx+1, pdu);
2156 txBuf = rlcUtlGetTxBuf(amDl->txBufLst, amHdr->sn);
2157 rlcCpyMsg(gCb,pdu,&(pduInfo->pdu));
2158 pduInfo->pduSz = pduSz;
2159 pduInfo->hdrSz = idx+1;
2161 /*Update estHdrSz. deduct current hdrSz */
2162 amDl->estHdrSz -= pduInfo->hdrSz;
2163 /* Reestimate estHdrSz for mid and last seg */
2166 amDl->estHdrSz += ((amHdr->si == RLC_SI_MID_SEG)? pduInfo->hdrSz : (pduInfo->hdrSz + 2));
2169 cmLListAdd2Tail(&txBuf->pduLst, &pduInfo->lstEnt);
2170 pduInfo->lstEnt.node = (PTR)pduInfo;
2172 gCb->genSts.bytesSent += pduSz;
2178 * @brief Private handler to remove the retx PDU from the rbCb
2181 * This function releases a retx PDU stored on DL portion of rbCb.
2182 * It also updates the BO if wtForAck flag is not set which implies
2183 * that it is not sent out yet.
2185 * @param[in] gCb RLC instance control block
2186 * @param[in] retx retransmit PDU to be removed
2187 * @param[in] rbCb Radio Bearer Control Block
2192 static Void rlcRemRetxPdu(RlcCb *gCb,RlcDlRbCb *rbCb,RlcRetx *retx)
2194 cmLListDelFrm(&RLC_AMDL.retxLst, &retx->lstEnt);
2196 if( RLC_AMDL.retxLst.count == 0)
2198 RLC_AMDL.nxtRetx = NULLP;
2201 if(retx->pendingReTrans == TRUE)
2203 RLC_AMDL.retxBo -= retx->segSz;
2204 RLC_AMDL.estHdrSz -= retx->hdrSz;
2207 rlcUtlAddReTxPduToBeFreedQueue(gCb, retx);
2208 rlcUtlRaiseDlCleanupEvent(gCb);
2214 * @brief Private handler to mark a retx PDU for further retransmission
2217 * This function sets a retx PDU that has not been ACKed in the
2218 * received Status PDU for futher retransmission. If the retransmission
2219 * limit is reached, it releases the retx PDU and informs the higher
2220 * layers about the same.
2222 * @param[in] gCb RLC instance control block
2223 * @param[in] retx retransmit PDU to be removed
2224 * @param[in] rbCb Radio Bearer Control Block
2229 static Void rlcAmmDlMarkPduForReTx(RlcCb *gCb,RlcDlRbCb *rbCb,RlcRetx *retx)
2231 if (RLC_AMDL.maxReTxReached == TRUE)
2236 if(retx->pendingReTrans == FALSE)
2238 retx->pendingReTrans = TRUE;
2241 RLC_AMDL.retxBo += retx->segSz;
2242 RLC_AMDL.estHdrSz += retx->hdrSz;
2244 if (retx->retxCnt > RLC_AMDL.maxRetx)
2246 /* RLC_DL_MAX_RETX fix */
2247 /* Marking the RB stalled for DL scheduling. This is to avoid unnecessary */
2248 /* preparation of RLC PDUs and adding the same to Tx Buffer */
2249 /* This condition is to avoid sending StaIndication more than once */
2250 if (TRUE != rbCb->m.amDl.maxReTxReached)
2252 rbCb->m.amDl.maxReTxReached = TRUE;
2253 rbCb->m.amDl.bo = 0;
2254 rbCb->m.amDl.cntrlBo = 0;
2255 rbCb->m.amDl.retxBo = 0;
2256 /* Sending BO update to SCH */
2257 rlcUtlSendDedLcBoStatus(gCb, rbCb, 0,0,0,0);
2258 rlcAmmSndStaInd(gCb, rbCb, retx);
2259 gRlcStats.amRlcStats.numDLMaxRetx++;
2262 rlcRemRetxPdu(gCb,rbCb, retx);
2268 if (RLC_AMDL.nxtRetx == NULLP)
2270 RLC_AMDL.nxtRetx = retx;
2273 gRlcStats.amRlcStats.numDLRetransPdus++;
2281 * @brief Private handler to check if SDU is completely deliverd and
2282 * send higher layers data confirmation
2285 * This function sends higher layers data confirmation for SDUs which
2286 * have been successfully delivered to the peer RLC entity.
2288 * @param[in] gCb RLC instance control block
2289 * @param[in] rbCb Radio Bearer Control Block
2290 * @param[in] sduLst List of SDUs that were part of the PDU
2291 * @param[in] numSdu Number of SDUs in the list
2296 static Void rlcAmmDlCheckIsSDUDelivered
2301 KwuDatCfmInfo **datCfm
2308 sdu->mode.am.rcvdSz += sduMap->sduSz;
2310 /* send a dat cfm if all the bytes of the sdu have been received */
2311 if (sdu->mode.am.rcvdSz == sdu->actSz)
2313 /* Send DatCfm for this sdu */
2314 if((*datCfm)->numSduIds < KWU_MAX_DAT_CFM)
2316 (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2320 /* This is an error that should never happen, we should resize
2321 * the #define to a larger value or check why we need to
2322 * send so many confirms in one go
2323 * Confrims to PDCP are being dropped in this case
2325 RlcKwuSapCb *rlckwuSap;
2326 rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
2327 RlcUiKwuDatCfm(&rlckwuSap->pst, rlckwuSap->suId, *datCfm);
2329 RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, *datCfm, sizeof(KwuDatCfmInfo));
2331 #if (ERRCLASS & ERRCLS_ADD_RES)
2332 if (*datCfm == NULLP)
2334 DU_LOG("\nERROR --> RLC_DL : Memory allocation failed UEID:%d CELLID:%d",
2336 rbCb->rlcId.cellId);
2339 #endif /* ERRCLASS & ERRCLS_RES */
2341 (*datCfm)->numSduIds = 0;
2342 (*datCfm)->rlcId = rbCb->rlcId;
2343 /* ccpu00135618: say total 1026 sduIds to copy the 1025 sduId after
2344 * new allocation of datCfm */
2345 (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2348 /* Remove SDU from the sduQ */
2349 cmLListDelFrm(&RLC_AMDL.sduQ, &sdu->lstEnt);
2350 rlcUtlAddSduToBeFreedQueue(gCb, sdu);
2351 rlcUtlRaiseDlCleanupEvent(gCb);
2358 * @brief Private handler to mark a PDU successful.
2361 * This function is called when we receive a STATUS pdu that marks
2362 * a PDU as successful. It releases the PDU from RLC entity and
2363 * informs PDCP of successful SDUs delivered as a result of this PDU.
2365 * @param[in] gCb RLC instance control block
2366 * @param[in] rbCb Radio Bearer Control Block
2367 * @param[in] sn SN that is successfully delivered to the peer
2372 static Void rlcAmmDlProcessSuccessfulTxPdu
2377 KwuDatCfmInfo **datCfm
2382 RlcTx *txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, sn);
2388 pduNode = txBuf->pduLst.first;
2391 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(pduNode->node);
2392 rlcAmmDlCheckIsSDUDelivered(gCb,
2396 pduNode = pduNode->next;
2399 rlcUtlAddTxPduToBeFreedQueue(gCb, txBuf);
2400 rlcUtlRaiseDlCleanupEvent(gCb);
2401 /* so that it is not processed again */
2402 rlcUtlRemovTxBuf(RLC_AMDL.txBufLst, txBuf, gCb);
2408 * @brief Handler to send Status Indication to PDCP
2411 * This function is used to send status indication to PDCP when the
2412 * maximum retransmission threshold value is reached for a PDU.
2414 * @param[in] gCb RLC instance control block
2415 * @param[in] rbCb RB control block
2416 * @param[in] retx The PDU/segment that failed max re-transmissions
2421 static Void rlcAmmSndStaInd
2428 KwuStaIndInfo *staInd;
2429 RlcKwuSapCb *rlckwuSap;
2431 /* Sap control block */
2432 rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
2434 /* Allocate memory for staInd Info */
2435 RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, staInd, sizeof(KwuStaIndInfo));
2437 #if (ERRCLASS & ERRCLS_ADD_RES)
2438 if (staInd == NULLP)
2440 DU_LOG("\nERROR --> RLC_DL : Memory allocation failed UEID:%d CELLID:%d",
2442 rbCb->rlcId.cellId);
2445 #endif /* ERRCLASS & ERRCLS_RES */
2447 /* Fill staInd Info */
2448 RLC_MEM_CPY(&staInd->rlcId, &rbCb->rlcId, sizeof(CmLteRlcId));
2451 staInd->sduId[0] = retx->sduMap.sdu->mode.am.sduId;
2455 RlcUiKwuStaInd(&rlckwuSap->pst, rlckwuSap->suId, staInd);
2456 #endif /* KW_PDCP */
2462 * @brief Handler to get the next node to be retransmitted from retxLst
2465 * This function is used to get the next node to be retransmitted
2468 * @param[in] gCb RLC instance control block
2469 * @param[in] retx The PDU/segment after which to find a node to be
2475 static void rlcGetNxtRetx(RlcCb *gCb, RlcRetx **retx)
2481 tNode = &((*retx)->lstEnt);
2482 tNode = tNode->next;
2486 *retx = (RlcRetx *)tNode->node;
2493 }while((*retx)->pendingReTrans == FALSE);
2499 * @brief Handler to process the re-establishment request received from UIM
2501 * @param[in] gCb RLC instance control block
2502 * @param[in] rlcId Identity of the RB in the UE/Cell for which
2503 * re-establishment is to be done
2504 * @param[in] rbCb Downlink RB control block (rbCb is freed in this
2510 Void rlcAmmDlReEstablish
2517 /* create a new AM DL RB, reset it and replace in the UeCb*/
2522 RLC_ALLOC(gCb, resetRb, sizeof(RlcDlRbCb));
2524 /* ccpu00135170 Removing KLOCK warning */
2525 if(resetRb == NULLP)
2530 RLC_MEM_CPY(resetRb, rbCb, sizeof(RlcDlRbCb));
2531 RLC_MEM_SET(&resetRb->m.amDl, 0 , sizeof(RlcAmDl));
2533 /* AGHOSH changes start */
2534 /* restore the old AM values */
2535 newAmDl = &resetRb->m.amDl;
2536 oldAmDl = &rbCb->m.amDl;
2538 newAmDl->pollPdu = oldAmDl->pollPdu;
2539 newAmDl->pollByte = oldAmDl->pollByte;
2540 newAmDl->maxRetx = oldAmDl->maxRetx;
2541 newAmDl->snLen = oldAmDl->snLen;
2542 newAmDl->snModMask = oldAmDl->snModMask;
2543 newAmDl->pollRetxTmrInt = oldAmDl->pollRetxTmrInt;
2544 rbCb->boUnRprtdCnt = (uint32_t)0;
2545 rbCb->lastRprtdBoToMac = (uint32_t)0;
2546 cmInitTimers(&(resetRb->m.amDl.pollRetxTmr), 1);
2547 /* AGHOSH changes end */
2549 if (ROK != rlcDbmFetchDlUeCb(gCb,rlcId.ueId, rlcId.cellId, &ueCb))
2551 DU_LOG("\nERROR --> RLC_DL : UeId [%d]: UeCb not found RBID;%d",
2557 if(rlcId.rbType == CM_LTE_SRB)
2559 ueCb->srbCb[rlcId.rbId] = resetRb;
2563 ueCb->drbCb[rlcId.rbId] = resetRb;
2565 /* update into the logical channel array also */
2566 ueCb->lCh[rbCb->lch.lChId - 1].dlRbCb = resetRb;
2568 if((resetRb->rlcId.rbType == CM_LTE_SRB)
2569 &&(resetRb->rlcId.rbId == 1))
2571 /* To stop the traffic on SRB2 and other DRBs*/
2572 rlcDlUtlSetReestInProgressForAllRBs(gCb, ueCb);
2576 rlcDlUtlSetReestInProgressForRB(gCb, resetRb);
2579 /* allocate the TX array again */
2583 resetRb->m.amDl.txBufLst,
2584 (RLC_TX_BUF_BIN_SIZE * sizeof(CmLListCp)));
2585 for(hashIndex = 0; hashIndex < RLC_TX_BUF_BIN_SIZE; hashIndex++)
2587 cmLListInit(&(resetRb->m.amDl.txBufLst[hashIndex]));
2590 /* send the old rb of deletion */
2591 rlcAmmFreeDlRbCb(gCb,rbCb);
2594 /* TODO: for now we are re-settting the re-establishment flag here
2595 this needs to be fixed
2596 There should be a proper intreface to resume the RBs */
2597 if(rlcId.rbType == CM_LTE_SRB)
2599 rlcDlUtlResetReestInProgress(ueCb->srbCb[rlcId.rbId]);
2603 rlcDlUtlResetReestInProgress(ueCb->drbCb[rlcId.rbId]);
2610 * @brief Handler to discard a SDU.
2613 * This function is used to discard a SDU after receiving
2614 * the Discard Request from UIM. The SDU is discarded if its
2615 * available and is not mapped to any PDU yet.
2617 * @param[in] gCb RLC instance control block
2618 * @param[in] rbCb RB control block
2619 * @param[in] sduId Sdu ID of the SDU to be discarded
2622 * -# ROK In case of successful discard
2623 * -# RFAILED In case the SDU is not found or already mapped
2625 S16 rlcAmmDiscSdu(RlcCb *gCb,RlcDlRbCb *rbCb,uint32_t sduId )
2631 * @brief Handler for Poll retransmit timer expiry
2634 * This function is used to handle events upon expiry of Poll
2637 * @param[in] gCb RLC instance control block
2638 * @param[in] rbCb Downlink RB control block
2642 Void rlcAmmPollRetxTmrExp(RlcCb *gCb,RlcDlRbCb *rbCb)
2645 RlcAmDl *amDl = &(rbCb->m.amDl);
2649 /* kw003.201 - Correcting the logic for determmining whether to do */
2650 /* any transmission of PDU. As per the spec section */
2651 /* 5.2.2.3, if there is any to transmit or retransmit, */
2652 /* do nothing. Else, pick up the VT(S) -1 for retx */
2653 /* We have nothing to transmit if window is stalled or */
2654 /* there are no SDUs to be transmitted or if there are */
2655 /* PDUs to be retransmitted. */
2656 if(CM_LTE_SRB == rbCb->rlcId.rbType)
2658 gRlcStats.amRlcStats.numDLPollTimerExpiresSrb++;
2662 gRlcStats.amRlcStats.numDLPollTimerExpiresDrb++;
2665 if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) ||
2666 RLC_AM_IS_TRANS_WIN_STALLED(amDl))
2668 sn = (amDl->txNext - 1) & amDl->snModMask;
2669 txBuf = rlcUtlGetTxBuf(amDl->txBufLst, sn);
2673 rlcAmmDlMoveFrmTxtoRetxBuffer(gCb,amDl, &retx, sn);
2675 if (RLC_AMDL.nxtRetx == NULLP)
2677 RLC_AMDL.nxtRetx = retx;
2680 rlcAmmSendDedLcBoStatus(gCb, rbCb, &RLC_AMDL);
2683 /* Get the last node in retxLst */
2684 RLC_LLIST_LAST_RETX(amDl->retxLst, retx);
2686 /* Unset wtForAck flag for the NACK PDUs */
2689 rlcAmmDlMarkPduForReTx(gCb, rbCb, retx);
2690 rlcAmmSendDedLcBoStatus(gCb, rbCb, &RLC_AMDL);
2698 * @brief Handler to update Acks for the remaining PDUs after the last accessed
2702 * This function is used to handle ACKs for the PDUs remaining after the
2703 * last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and
2704 * sends DatCfm to PDCP for the same.
2706 * @param[in] gCb RLC instance control block
2707 * @param[in] rbCb Downlink Radio Bearer control block
2708 * @param[in] mAckSn The ACK SN after doing the base modulus
2709 * @param[in] rextNode Next node in the re-transmission buffer
2715 static Void rlcAmmDlUpdateTxAndReTxBufForAckSn
2721 KwuDatCfmInfo **datCfm
2729 /* Remove pdus/segs from retxLst */
2732 retx = (RlcRetx *)(retxNode->node);
2733 retxNode = retxNode->next;
2734 MODAMT(retx->amHdr.sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2737 rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
2741 /* For the remaining; pdus not acknowldeged by the NACK_SN but being
2742 acknowledged by the ACK_SN*/
2743 /* start from the starting of the transmission window and remove till just
2745 mSn = 0; /* same as MODAMT(RLC_AMDL.txNextAck, mSn, RLC_AMDL.txNextAck);*/
2746 sn = RLC_AMDL.txNextAck;
2749 txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, sn);
2753 DU_LOG("\nDEBUG --> RLC_DL : rlcAmmDlUpdateTxAndReTxBufForAckSn: ACK for PDU "
2754 "with sn = %d UEID:%d CELLID:%d",
2757 rbCb->rlcId.cellId);
2759 rlcAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
2762 sn = (sn + 1) & RLC_AMDL.snModMask;
2763 MODAMT(sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2770 * @brief Handler to update Acks for the remaining PDUs after the last accessed
2774 * This function is used to handle ACKs for the PDUs remaining after the
2775 * last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and
2776 * sends DatCfm to PDCP for the same.
2778 * @param[in] gCb RLC instance control block
2779 * @param[in] rbCb Downlink Radio Bearer control block
2780 * @param[in] mAckSn The ACK SN after doing the base modulus
2781 * @param[in] rextNode Next node in the re-transmission buffer
2786 static Void rlcAmmDlUpdTxAndReTxBufForLessThanNackSn
2793 KwuDatCfmInfo **datCfm
2802 retx = (RlcRetx *)((*retxNode)->node);
2803 MODAMT(retx->amHdr.sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2806 (*retxNode) = (*retxNode)->next;
2807 rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
2815 /* Remove all pdus with SN < NACK_SN from the transmission buffer */
2816 MODAMT(sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2817 while (mSn < mNackSn)
2819 /* this if check seems redundant,why should mSn ever be mTxSn
2820 (which actually is VT(A) */
2821 txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, sn);
2822 if ((txBuf != NULLP))
2824 DU_LOG("\nDEBUG --> RLC_DL : rlcHndlStaRsp: Handle ACK (sn = %d) UEID:%d CELLID:%d",
2827 rbCb->rlcId.cellId);
2829 /* Remove pdus from txBuf */
2830 rlcAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
2833 sn = (sn + 1) & RLC_AMDL.snModMask;
2834 MODAMT(sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2842 * @brief Handler to form construct AM header
2845 * This function is used to construct am header with the available header
2848 * @param[in] gCb RLC instance control block
2849 * @param[in] amHdr AM Header
2850 * @param[in] isSeg Check for Segmentation of PDU
2851 * @param[in] hdr Header field
2852 * @param[in] idx Index
2857 static void rlcConstructAmHdr(RlcAmHdr *amHdr, uint8_t *hdr, uint8_t snLen, uint16_t *idx)
2860 hdr[0] = RLC_DATA_BITMASK;
2862 hdr[0] = hdr[0] | (amHdr->p << 6);
2863 hdr[0] = hdr[0] | ((amHdr->si & 0x3) << 4);
2864 if(snLen == RLC_AM_CFG_12BIT_SN_LEN)
2866 hdr[0] = hdr[0] | (uint8_t)((amHdr->sn & 0xF00) >> 8);
2867 hdr[1] = (uint8_t)(amHdr->sn & 0x0FF);
2872 hdr[0] = hdr[0] | (uint8_t)((amHdr->sn & 0x30000) >> 16);
2873 hdr[1] = (uint8_t)((amHdr->sn & 0xFF00) >> 8);
2875 hdr[2] = (uint8_t)(amHdr->sn & 0xFF);
2879 if ((amHdr->si == RLC_SI_MID_SEG) || (amHdr->si == RLC_SI_LAST_SEG))
2882 hdr[(*idx)] = (uint8_t)((amHdr->so & 0xFF00)>> 8);
2884 hdr[(*idx)] = (uint8_t)(amHdr->so & 0xFF);
2891 * @brief This function adds a retx PDU to list of retx PDUs
2894 * kw003.201 - Poll expiry may cause an SN to be added to retx
2895 * out of sequence and hence all additions to retx
2896 * must validate that they are added in sequence
2898 * @param[in] amDl AM Downlink Control Block
2899 * @param[in] retx Retransmit PDU
2904 static Void rlcAmmAddPduToRetxLst(RlcAmDl *amDl,RlcRetx *retx)
2911 node = amDl->retxLst.last;
2912 MODAMT(retx->amHdr.sn, retxMSn, amDl->txNextAck,amDl->snModMask);
2913 while(node != NULLP)
2915 tRetx = (RlcRetx *)(node->node);
2916 MODAMT(tRetx->amHdr.sn, tMSn, amDl->txNextAck,amDl->snModMask);
2928 amDl->retxLst.crnt = node;
2929 cmLListInsAfterCrnt(&amDl->retxLst, &retx->lstEnt);
2930 retx->lstEnt.node = (PTR)retx;
2934 amDl->retxLst.crnt = amDl->retxLst.first;
2935 cmLListInsCrnt(&amDl->retxLst, &retx->lstEnt);
2936 retx->lstEnt.node = (PTR)retx;
2939 if (amDl->nxtRetx == NULLP)
2941 amDl->nxtRetx = retx;
2948 * @brief Handler to Move the PDU from txBuf to re-transmission buffer
2951 * This function is used to move the PDU from the txBuf to re-transmit buffer
2953 * @param[in] gCb RLC instance control block
2954 * @param[in] amDl AM Downlink Control Block
2955 * @param[in] retx node in the reTx buffer to be moved to, allocated by
2957 * @param[in] sn SN in the tx buffer which needs to be moved
2963 static Void rlcAmmDlMoveFrmTxtoRetxBuffer
2971 RlcTx* txBuf = rlcUtlGetTxBuf(amDl->txBufLst, sn);
2977 while(txBuf->pduLst.first)
2979 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(txBuf->pduLst.first->node);
2980 RLC_ALLOC_WC(gCb,*retx, sizeof(RlcRetx));
2982 #if (ERRCLASS & ERRCLS_ADD_RES)
2985 DU_LOG("\nERROR --> RLC_DL : Memory allocation failed");
2988 #endif /* ERRCLASS & ERRCLS_RES */
2990 /* Move Sdu byte segment from TX buf to retx buf*/
2991 rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb,
2996 /* Delete node from the txBuf Pdu lst */
2997 cmLListDelFrm(&txBuf->pduLst, txBuf->pduLst.first);
2998 RLC_FREE(gCb, pduInfo, sizeof(RlcDlPduInfo));
3000 /* Remove PDU from txBuf */
3001 rlcUtlDelTxBuf(amDl->txBufLst, txBuf,gCb);
3010 * function to free/release the Acknowledged mode RBCB buffers
3013 * This primitive Frees the Acknowledged Mode RbCb transmission Buffer,
3014 * retransmission Buffer and reciption Buffers
3016 * @param [in] gCb - RLC instance control block
3017 * @param [in] rbCb - Downlink RB Control Block
3021 Void rlcAmmFreeDlRbCb(RlcCb *gCb,RlcDlRbCb *rbCb)
3023 /* stop the re-transmission timer */
3024 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMDL_POLL_RETX_TMR))
3026 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR);
3029 /* store the entire Rb pointer */
3030 rbCb->rlsLnk.node = (PTR)rbCb;
3031 cmLListAdd2Tail(&gCb->u.dlCb->toBeFreed.rbLst, &rbCb->rlsLnk);
3034 cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.amDl.sduQ));
3036 rlcUtlRaiseDlCleanupEvent(gCb);
3042 * @brief Handler to create STATUS Pdu
3045 * This function is used to create status pdu
3047 * @param[in] gCb RLC instance control block
3048 * @param[in] rbCb Downlink RB control block
3049 * @param[in] rlcDatReq The data to be passed to MAC
3054 static void rlcAmmCreateStatusPdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
3056 RlcSn sn; /* sequence number */
3057 RlcSn ack_sn; /* Ack sequence number */
3058 Buffer *mBuf; /* control pdu buffer */
3059 MsgLen cntrlPduSz; /* control pdu size */
3060 uint8_t cntrlPdu[RLC_MAX_CNTRL_FIELDS]; /* control pdu to be added to mBuf */
3061 RlcUdxDlStaPdu *pStaPdu;
3062 uint16_t bytesToEncode = 0; /* bytes required to encode the STATUS PDU */
3063 uint16_t encIdx = 0;
3064 uint16_t prevEncIdx = 0;
3065 RlcNackInfo *rlcNackInfo;
3068 pStaPdu = RLC_AMDL.pStaPdu;
3077 /* ACK SN Field will be set in the end based on available Grant */
3079 encIdx = bytesToEncode = 3; /* Num Octets before NACK SN info encoding*/
3081 ack_sn = pStaPdu->ackSn;
3083 if (rbCb->m.amDl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
3086 /* If alteast one NACK SN Info then set the E1 field */
3087 if (pStaPdu->nackCount)
3097 for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3099 sn = pStaPdu->nackInfo[nkCnt].sn;
3101 rlcNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3103 bytesToEncode += 2; /* 2 Octets for NACK SN */
3105 /* Check if E2 : isSegment is set */
3106 if (rlcNackInfo->isSegment)
3108 bytesToEncode += 4; /* 4 Octets: SOstart, SOend */
3111 /* Check if E3 : nackRange is set */
3112 if (rlcNackInfo->nackRange)
3114 bytesToEncode += 1; /* 1 Octet: NACK range */
3117 /* Check if this NACK info can be accomodated in the Grant */
3118 if( rlcDatReq->pduSz >= bytesToEncode)
3120 /* If there is a NACK SN before this then set its
3124 /* NACKSN E1 E2 E3 R */
3125 cntrlPdu[prevEncIdx + 1] |= 0x8;
3128 /* 12 BIT Nack SN encode */
3129 cntrlPdu[encIdx] = (sn & 0xFF0) >> 4;
3132 cntrlPdu[encIdx + 1] = (sn & 0xF) << 4;
3134 if (rlcNackInfo->isSegment)
3137 cntrlPdu[encIdx + 1] |= 0x4;
3140 /* Add soStart and soEnd */
3142 cntrlPdu[encIdx + 2] = (rlcNackInfo->soStart) >> 8;
3143 cntrlPdu[encIdx + 3] = rlcNackInfo->soStart & 0xFF;
3146 cntrlPdu[encIdx + 4] = (rlcNackInfo->soEnd) >> 8;
3147 cntrlPdu[encIdx + 5] = rlcNackInfo->soEnd & 0xFF;
3150 if (rlcNackInfo->nackRange)
3153 cntrlPdu[encIdx + 1] |= 0x2;
3154 if(rlcNackInfo->isSegment)
3156 cntrlPdu[encIdx + 6] = rlcNackInfo->nackRange;
3160 cntrlPdu[encIdx + 2] = rlcNackInfo->nackRange;
3164 gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3166 /* Set ACK SN now */
3169 ack_sn = rlcNackInfo->sn;
3171 /* Not even one nack can be accomodated */
3180 prevEncIdx = encIdx;
3181 encIdx = bytesToEncode;
3183 }/* Loop is done for the NackCount */
3188 DU_LOG("\nINFO --> RLC_DL : rlcAssembleCntrlInfo: ACK PDU's SN = %d"\
3189 "UEID:%d CELLID:%d", ack_sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
3191 cntrlPdu[0] |= (ack_sn & 0xF00)>> 8;
3192 cntrlPdu[1] = (uint8_t)ack_sn;
3196 else if (rbCb->m.amDl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
3198 /* If alteast one NACK SN Info then set the E1 field */
3199 if (pStaPdu->nackCount)
3209 for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3211 sn = pStaPdu->nackInfo[nkCnt].sn;
3213 rlcNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3215 bytesToEncode += 3; /* 3 Octets for NACK SN */
3217 /* Check if E2 : isSegment is set */
3218 if (rlcNackInfo->isSegment)
3220 bytesToEncode += 4; /* 4 Octets: SOstart, SOend */
3223 /* Check if E3 : nackRange is set */
3224 if (rlcNackInfo->nackRange)
3226 bytesToEncode += 1; /* 1 Octet: NACK range */
3229 /* Check if this NACK info can be accomodated in the Grant */
3230 if( rlcDatReq->pduSz >= bytesToEncode)
3232 /* If there is a NACK SN before this then set its
3236 /* NACKSN E1 E2 E3 R R R */
3237 cntrlPdu[prevEncIdx + 2] |= 0x20;
3240 /* 18 BIT Nack SN encode */
3241 cntrlPdu[encIdx] = (uint8_t)((sn & 0x3FC00) >> 10);
3244 cntrlPdu[encIdx + 1] = (uint8_t)((sn & 0x3FC) >> 2);
3247 cntrlPdu[encIdx + 2] = (uint8_t)((sn & 0x3)<< 6);
3249 if (rlcNackInfo->isSegment)
3251 /* NACKSN E1 E2 E3 R R R */
3253 cntrlPdu[encIdx + 2] |= 0x10;
3256 /* Add soStart and soEnd */
3258 cntrlPdu[encIdx + 3] = (rlcNackInfo->soStart) >> 8;
3259 cntrlPdu[encIdx + 4] = (uint8_t)rlcNackInfo->soStart;
3262 cntrlPdu[encIdx + 5] = (rlcNackInfo->soEnd) >> 8;
3263 cntrlPdu[encIdx + 6] = (uint8_t)(rlcNackInfo->soEnd);
3266 if (rlcNackInfo->nackRange)
3268 /* NACKSN E1 E2 E3 R R R */
3270 cntrlPdu[encIdx + 2] |= 0x08;
3272 if (rlcNackInfo->isSegment)
3274 cntrlPdu[encIdx + 7] = rlcNackInfo->nackRange;
3278 cntrlPdu[encIdx + 3] = rlcNackInfo->nackRange;
3282 gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3284 /* Set ACK SN now */
3287 ack_sn = rlcNackInfo->sn;
3289 /* Not even one nack can be accomodated */
3292 cntrlPdu[2] &= 0xFD;
3298 prevEncIdx = encIdx;
3299 encIdx = bytesToEncode;
3301 }/* Loop is done for the NackCount */
3306 DU_LOG("\nINFO --> RLC_DL : rlcAssembleCntrlInfo: ACK PDU's SN = %d"
3307 "UEID:%d CELLID:%d", ack_sn, rbCb->rlcId.ueId,rbCb->rlcId.cellId);
3309 cntrlPdu[0] |= (ack_sn & 0x3C000) >> 14;
3310 cntrlPdu[1] = (ack_sn & 0x3FC0) >> 6;
3311 cntrlPdu[2] |= (ack_sn & 0x3F)<< 2;
3318 DU_LOG("\nERROR --> RLC_DL : rlcAssembleCntrlInfo:Conf SN LEN %d is INVALID !!!! \
3319 UEID:%d CELLID:%d", rbCb->m.amDl.snLen, rbCb->rlcId.ueId,
3320 rbCb->rlcId.cellId);
3325 SGetMsg(RLC_GET_MEM_REGION(gCb), RLC_GET_MEM_POOL(gCb),&mBuf);
3327 mBuf = (Buffer *)rlcAmmStaPduList[rlcAmmStaPduListCnt++];
3329 if(rlcAmmStaPduListCnt > 511)
3330 rlcAmmStaPduListCnt = 0;
3333 cntrlPduSz = encIdx;
3334 ODU_ADD_POST_MSG_MULT(cntrlPdu, cntrlPduSz, mBuf);
3336 rlcDatReq->pduSz -= cntrlPduSz;
3337 /* Add mBuf to RLC_AMDL.mBuf */
3338 RLC_AMDL.mBuf = mBuf;
3343 #ifdef RLC_STA_PROC_IN_MAC/* RLC Status PDU Processing */
3345 S16 rlcProcDlStatusPdu(Pst *udxPst,SuId suId,
3346 CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu);
3348 static Void rgAmmExtractElmnt(RlcCb *gCb,Buffer *pdu,RlcExtHdr *hdrInfo)
3351 uint8_t pLen = hdrInfo->pLen;
3352 uint8_t len = (uint8_t)hdrInfo->len;
3357 /* uint8_t rLen1 = 0; */
3364 SRemPreMsg(&hdr, pdu);
3370 val = tHdr >> (RLC_BYTE_LEN - (len));
3374 else /*if (len > 8) */
3378 val = val >> (RLC_BYTE_LEN - fLen);
3379 val = val << (len - fLen);
3381 SRemPreMsg(&hdr, pdu);
3385 hdr = hdr >> (RLC_BYTE_LEN - rLen);
3388 pLen = (RLC_BYTE_LEN - rLen);
3392 rLen = rLen - RLC_BYTE_LEN;
3394 tVal = tVal << rLen;
3397 SRemPreMsg(&hdr, pdu);
3399 hdr = hdr >> (RLC_BYTE_LEN - rLen);
3402 pLen = (RLC_BYTE_LEN - rLen);
3406 hdrInfo->pLen = pLen;
3416 static Void rgAmmUlHndlStatusPdu
3428 RlcUdxStaPdu *pStaPdu;
3429 uint8_t e3; /* NACK RANGE : 5GNR */
3432 uint32_t resrvdBitsAckSn;
3433 uint32_t resrvdBitsNackSn;
3435 RLCDBGP_BRIEF(gCb, "rgAmmUlHndlStatusPdu(rbCb, cntrlPdu, fByte) \n");
3437 RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
3439 /* Extract the Control PDU */
3440 hdrInfo.hdr = (*fByte << 1);
3443 /* D/C has been shifted in the calling function */
3444 if (hdrInfo.hdr & 0xE0)
3446 RLCDBGP_ERROR(gCb, "rgAmmUlHndlStatusPdu: Reserved value for CPT received \n");
3450 RLC_ALLOC_SHRABL_BUF(udxPst->region,
3453 sizeof(RlcUdxStaPdu));
3455 #if (ERRCLASS & ERRCLS_ADD_RES)
3456 /* Memory allocation failure can not be expected */
3463 if (rbCb->m.amDl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
3466 resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_12BITS;
3467 resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_12BITS;
3469 else if (rbCb->m.amDl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
3472 resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_18BITS;
3473 resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_18BITS;
3478 resrvdBitsAckSn = 0;
3479 resrvdBitsAckSn = 0;
3482 pStaPdu->nackCnt = 0;
3484 hdrInfo.hdr = hdrInfo.hdr << RLC_CPT_LEN;
3487 hdrInfo.len = RLC_SN_LEN;
3488 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3489 pStaPdu->ackSn = hdrInfo.val;
3491 /* Check if NACK Exists */
3492 hdrInfo.len = RLC_E1_LEN;
3493 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3494 e1 = (uint8_t)hdrInfo.val;
3495 RLCDBGP_DETAIL(gCb, "rgAmmUlHndlStatusPdu: ACK SN = %d \n", pStaPdu->ackSn);
3497 /* Extract the Reserved Bits after ACK SN field */
3498 hdrInfo.len = resrvdBitsAckSn;
3499 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3502 /* If NACK exists in control PDU */
3503 /* For ACKs and NACKs */
3504 while (e1 && (pStaPdu->nackCnt < RLC_MAX_NACK_CNT))
3506 hdrInfo.len = snLen;
3507 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3508 pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
3510 hdrInfo.len = RLC_E1_LEN;
3511 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3512 e1 = (uint8_t)hdrInfo.val;
3515 /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
3517 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3518 /* e2 = (uint8_t) hdrInfo.val;*/
3520 /* Store e2 value */
3521 pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (uint8_t) hdrInfo.val;
3523 /* Extract e3 : 5GNR */
3524 /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
3526 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3527 e3 = (uint8_t) hdrInfo.val;
3529 /* Extract Reserved Bits after NACK SN */
3530 hdrInfo.len = resrvdBitsNackSn;
3531 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3533 /* Test for resegmentation */
3534 if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
3536 hdrInfo.len = RLC_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
3537 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3538 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
3540 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3541 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = hdrInfo.val;
3544 "rgAmmUlHndlStatusPdu: soStart and soEnd = %d %d \n",
3545 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
3546 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd);
3551 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
3552 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = 0;
3555 /* NACK RANGE Field is SET */
3558 /* Extract NACK range field */
3559 hdrInfo.len = RLC_NACK_RANGE_LEN;
3560 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3561 snRange = (uint8_t)hdrInfo.val;
3563 pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
3569 gRlcStats.amRlcStats.numULStaPduRcvd++;
3570 gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
3572 /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
3573 to the last NACK SN + 1 and discard the original ACK_SN*/
3574 if(pStaPdu->nackCnt == RLC_MAX_NACK_CNT)
3576 pStaPdu->ackSn = (pStaPdu->nackInfo[RLC_MAX_NACK_CNT-1].sn + 1) & amDl->snModMask;
3580 /* Parse & send Status PDU to RLC-DL */
3581 //rlcUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
3582 rlcUlUdxStaUpdReq(udxPst, suId, &rbCb->rlcId, pStaPdu);
3587 S16 rlcProcDlStatusPdu(Pst *udxPst,SuId suId,
3588 CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu)
3590 RlcDlRbCb *rbCb = NULLP;
3591 RlcDlUeCb *ueCb = NULLP;
3594 S16 retVal = RFAILED;
3596 Pst dlRlcPst = *udxPst;
3598 gCb = RLC_GET_RLCCB(1); /* DL RLC instance */
3600 if( ROK != rlcDbmFetchDlUeCb(gCb,rnti,cellId,&(ueCb)))
3602 DU_LOG("\nERROR --> RLC_DL : RLC UECb Not found...\n");
3607 rbCb = ueCb->lCh[lcId - 1].dlRbCb;
3609 /* Skip if mode is not AM */
3610 if((rbCb == NULLP) || (rbCb->mode != RLC_MODE_AM))
3615 if(ROK != SExamMsg((Data *)(&fByte),
3618 DU_LOG("\nERROR --> RLC_DL : Failure in Rlc Hdr SExamMsg\n");
3622 if(RLC_CNTRL_PDU == ((fByte & RLC_DC_POS) >> RLC_DC_SHT))
3624 SRemPreMsg(&temp, rlcSdu);
3625 dlRlcPst.selector = 1;/* LWLC*/
3626 rgAmmUlHndlStatusPdu(&dlRlcPst,suId,gCb, rbCb, rlcSdu, &fByte);
3640 /********************************************************************30**
3643 **********************************************************************/