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 "rlc_err.h" /* Err defines */
45 #include "rlc_env.h" /* RLC environment options */
47 /* extern (.x) include files */
48 #include "lkw.x" /* LKW */
49 #include "ckw.x" /* CKW */
50 #include "kwu.x" /* KWU */
51 #include "rgu.x" /* RGU */
53 #include "rlc_utils.h" /* RLC defines */
54 #include "rlc_dl_ul_inf.h"
59 uint32_t rlcAmmStaPduList[512];
60 uint32_t rlcAmmStaPduListCnt = 0;
65 @brief RLC Acknowledged Mode Downlink Module
67 #define RLC_MODULE (RLC_DBGMASK_AM | RLC_DBGMASK_DL)
69 uint32_t rlcStatusPduCnt, rlcStatusAckCnt, rlcStatusNcnt, rlcSduSndCnt;
75 /* forward references */
76 Void rlcAmmDlHndlStatusPdu ARGS ((RlcCb *gCb,
78 RlcUdxStaPdu *pStaPdu));
80 /* public variable declarations */
82 /* This structure holds all the global structs we need. */
84 /* private variable declarations */
86 #define RLC_AM_REMOVE_HDR(_gCb, _rbCb, _retx) do { \
87 if ((_retx)->yetToConst == FALSE) \
90 SSegMsg((_retx)->seg, (_retx)->hdrSz, &_pduInfo); \
91 ODU_PUT_MSG_BUF((_retx)->seg); \
92 (_retx)->seg = _pduInfo; \
94 (_rbCb)->m.amDl.estHdrSz -= retx->hdrSz;\
97 /* private function declarations */
99 static Void rlcResegRetxPdus ARGS ((RlcCb *gCb,
101 RlcDatReq *rlcDatReq));
103 static Void rlcRemRetxPdu ARGS ((RlcCb *gCb,
107 static Void rlcAmmCreateStatusPdu ARGS ((RlcCb *gCb,
109 RlcDatReq *rlcDatReq));
111 static Void rlcAmmDlMarkPduForReTx ARGS ((RlcCb *gCb,
115 static Void rlcAmmDlProcessSuccessfulTxPdu ARGS((RlcCb *gCb,
118 KwuDatCfmInfo **datCfm));
120 static Void rlcAmmDlSetTxNextAck ARGS((RlcAmDl *amDl, RlcSn sn));
122 static Void rlcAmmDlCheckAndStopPollTmr ARGS((RlcCb *gCb,
126 static Void rlcAssembleSdus ARGS ((RlcCb *gCb,
128 RlcDatReq *rlcDatReq));
130 static bool rlcAmmDlCheckAndSetPoll ARGS ((RlcCb *gCb,
135 static Void rlcAmmCreatePdu ARGS ((RlcCb *gCb,
138 RlcDlPduInfo *pduInfo,
141 static Void rlcAmmSndStaInd ARGS ((RlcCb *gCb,RlcDlRbCb *rbCb, RlcRetx *retx));
143 static Void rlcGetNxtRetx ARGS ((RlcCb *gCb, RlcRetx **retx));
145 static Void rlcConstructAmHdr ARGS ((RlcAmHdr *amHdr,
150 static Void rlcAmmDlUpdateTxAndReTxBufForAckSn ARGS ((RlcCb *gCb,
154 KwuDatCfmInfo **datCfm));
156 static Void rlcAmmDlMoveFrmTxtoRetxBuffer ARGS ((RlcCb *gCb,
161 static Void rlcAmmDlCheckIsSDUDelivered ARGS((RlcCb *gCb,
164 KwuDatCfmInfo **datCfm));
166 static Void rlcAmmAddPduToRetxLst ARGS((RlcAmDl *amDl,
169 static Void rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer ARGS(
174 RlcDlPduInfo *pduInfo
177 static Void rlcAmmDlHndlStatus4SduByteSegInTxBuf ARGS(
181 RlcNackInfo *nackSnInfo,
183 KwuDatCfmInfo **datCfm
186 static Void rlcAmmDlUpdateTxAndReTxBufForNackSn ARGS(
190 RlcNackInfo *nackSnInfo,
192 KwuDatCfmInfo **datCfm
195 static Void RlcDlAmmGetNackSnInfoFrmNackRangeIdx ARGS(
198 RlcNackInfo *nackInfo,
200 RlcNackInfo *nackSnInfo,
204 static Void rlcAmmDlUpdTxAndReTxBufForLessThanNackSn ARGS(
211 KwuDatCfmInfo **datCfm
213 /*****************************************************************************
215 AM Module contains the following funcitons:
219 - rlcAmmDlAssembleCntrlInfo
222 - rlcAmmDlCheckAndSetPoll
228 *******************************************************************************/
229 /** @addtogroup ammode */
233 * @brief Function to send a Status Response to MAC for a dedicated logical
237 * Function calculates the current bo and send a Status response for the
238 * dedicated logical channel if the bo is non zero
240 * @param[in] gCb RLC instance control block
241 * @param[in] rbCb Radio Bearer control block
242 * @param[in] amDl AM downlink control block
246 void rlcAmmSendDedLcBoStatus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcAmDl *amDl)
248 int32_t bo = rlcAmmCalculateBo(amDl);
252 rlcUtlSendDedLcBoStatus(gCb, rbCb, bo, amDl->estHdrSz, \
253 amDl->cntrlBo ?TRUE:FALSE,amDl->cntrlBo);
260 * @brief Function to check if the pollSn is acked and stop the poll timer
262 * @param[in] gCb RLC instance control block
263 * @param[in] rbCb Radio Bearer control block
264 * @param[in] mAckSn The last received ACKSN. The base modulus value should
269 static Void rlcAmmDlCheckAndStopPollTmr(RlcCb *gCb,RlcDlRbCb *rbCb,RlcSn mAckSn)
273 MODAMT(rbCb->m.amDl.pollSn, mPollSn, rbCb->m.amDl.txNextAck,rbCb->m.amDl.snModMask);
275 if (mPollSn <= mAckSn)
277 if (rlcChkTmr(gCb, (PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR))
279 rlcStopTmr(gCb, (PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR);
287 * @brief Function to set VT(A) and VT(MS). Calculates the VT(MS) from VT(A)
289 * @param[in,out] amDl AM downlink control block
290 * @param[in]sn Sequence number to be set as VT(A)
294 static Void rlcAmmDlSetTxNextAck(RlcAmDl *amDl,RlcSn sn)
296 amDl->txNextAck = sn;
302 * @brief Function to process a successfully re-transmitted PDU/segment
305 * Checks if the SDU has been completely delivered or not. Removes the PDU
306 * from the re-transmission buffer
308 * @param[in] gCb RLC instance control block
309 * @param[in] rbCb Downlink Radio Bearer control block
310 * @param[in] retx The PDU/segment which was successfully re-transmitted
314 static Void rlcAmmDlProcessSuccessfulReTx
319 KwuDatCfmInfo **datCfm
322 rlcAmmDlCheckIsSDUDelivered(gCb, rbCb, &(retx->sduMap), datCfm);
324 rlcRemRetxPdu(gCb, rbCb, retx);
330 * @brief Handler to Move the PDU from txBuf to re-transmission buffer
333 * This function is used to move the PDU from the txBuf to re-transmit buffer
335 * @param[in]RlcCb *gCb RLC instance control block
336 * @param[in]RlcAmDl *amDl AM Downlink Control Block
337 * @param[in]RlcRetx **retx node in the reTx buffer to be moved to, allocated by
339 * @param[in]RlcDlPduInfo *pduInfo TX PDU which needs to be moved
345 static Void rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer
350 RlcDlPduInfo *pduInfo
354 RLC_ALLOC_WC(gCb,*retx, sizeof(RlcRetx));
356 #if (ERRCLASS & ERRCLS_ADD_RES)
359 DU_LOG("\nERROR --> RLC_DL : Memory allocation failed");
362 #endif /* ERRCLASS & ERRCLS_RES */
364 (*retx)->seg = pduInfo->pdu;
365 (*retx)->segSz = pduInfo->pduSz;
366 /* MS_FIX for DL stall */
367 (*retx)->soEnd = (pduInfo->amHdr.so + pduInfo->pduSz - 1);
369 (*retx)->hdrSz = pduInfo->hdrSz;
370 (*retx)->retxCnt = 1;
371 (*retx)->yetToConst = 0;
372 (*retx)->pendingReTrans = TRUE;
374 /* initialize the list pointer to 0 instead of memset */
375 (*retx)->lstEnt.next = 0;
376 (*retx)->lstEnt.prev = 0;
377 /* copy the sdu maps */
378 RLC_MEM_CPY(&((*retx)->sduMap),
382 RLC_MEM_CPY(&((*retx)->amHdr), &pduInfo->amHdr, sizeof(RlcAmHdr));
383 rlcAmmAddPduToRetxLst(amDl, (*retx));
385 /* Update the BO appropriately */
386 amDl->retxBo += (*retx)->segSz;
387 amDl->estHdrSz += (*retx)->hdrSz;
389 gRlcStats.amRlcStats.numDLRetransPdus++;
392 } /*rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer */
395 * @brief Function to handle Status of Sdu byte segment for a nackSn
398 * This function is used to move the PDU from the txBuf to re-transmit buffer
400 * @param[in]RlcCb *gCb RLC instance control block
401 * @param[in]RlcDlRbCb *rbCb AM Downlink Control Block
402 * @param[in]RlcNackInfo *nackSnInfo Nack Information of a NACK_SN
403 * @param[in]RlcRetx **retx node in the reTx buffer to be moved to, allocated by
405 * @param[in]KwuDatCfmInfo **datCfm Ptr to datCfm
411 static Void rlcAmmDlHndlStatus4SduByteSegInTxBuf
415 RlcNackInfo *nackSnInfo,
417 KwuDatCfmInfo ** datCfm
424 txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, nackSnInfo->sn);
429 lnk = txBuf->pduLst.first;
432 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(lnk->node);
433 RlcSn pduSoEnd = (pduInfo->amHdr.so + pduInfo->sduMap.sduSz - 1);
435 /* If So of Sdu byte segment(pduInfo/seg) is < status pdu
436 soStart that means it's ACKED*/
437 if(pduSoEnd < nackSnInfo->soStart)
439 rlcAmmDlCheckIsSDUDelivered(gCb,
445 else if (pduSoEnd <= nackSnInfo->soEnd)
447 /* Move Sdu byte segment from TX buf to retx buf*/
448 rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb,
459 /* Delete node from the txBuf Pdu lst */
460 cmLListDelFrm(&txBuf->pduLst, lnk);
461 RLC_FREE(gCb, pduInfo, sizeof(RlcDlPduInfo));
464 if(!txBuf->pduLst.count)
466 /*No more Sdu byte segment are left. Hence delete txBuf*/
467 rlcUtlDelTxBuf(RLC_AMDL.txBufLst, txBuf,gCb);
474 * @brief Function to handle Status of Sdu byte segment for a nackSn
477 * This function is used to move the PDU from the txBuf to re-transmit buffer
479 * @param[in]RlcCb *gCb RLC instance control block
480 * @param[in]RlcDlRbCb *rbCb AM Downlink Control Block
481 * @param[in]RlcNackInfo *nackSnInfo Nack Information of a NACK_SN
482 * @param[in]RlcRetx **retx node in the reTx buffer to be moved to, allocated by
484 * @param[in]KwuDatCfmInfo **datCfm Ptr to datCfm
489 static Void rlcAmmDlUpdateTxAndReTxBufForNackSn
493 RlcNackInfo *nackSnInfo,
495 KwuDatCfmInfo **datCfm
501 /* Now process the NACK_SN received. Now the NACK_SN is */
502 /* either the first element of RETX or is in TX array */
503 /* To remove the remaining acks from the pdu byte segments */
505 /* if the NACK_SN is in the transmit buffer, move it to the re-
507 txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, nackSnInfo->sn);
510 if(nackSnInfo->isSegment)
512 /* Go through all the AMD PDUs of a particular SN
513 and check if segment is ACKED if yes then mark succesfully sent,
514 if segment is NACKed then move it to to retx lst */
515 rlcAmmDlHndlStatus4SduByteSegInTxBuf(gCb, rbCb, nackSnInfo, &retx, datCfm);
519 /*e2= 0 and e3= 0: Move complete PDU from TX buf to retx buf*/
520 rlcAmmDlMoveFrmTxtoRetxBuffer(gCb,
526 #if (ERRCLASS & ERRCLS_ADD_RES)
530 (*retxNode) = retx->lstEnt.next;
536 /* process the pdus/segments in the re-transmit buffer with
540 retx = (RlcRetx *)((*retxNode)->node);
541 if (retx->amHdr.sn != nackSnInfo->sn)
545 if ((nackSnInfo->isSegment) &&
546 ((retx->soEnd < nackSnInfo->soStart) /*|| (retx->amHdr.so > soEnd)*/))
548 DU_LOG( "\nDEBUG --> RLC_DL : rlcHndlStaRsp: Handle ACK for byte segment, Its "
549 "sn = %d UEID:%d CELLID:%d",
553 DU_LOG("\nDEBUG --> RLC_DL : soStart and soEnd = %d, %d, UEID:%d CELLID:%d",
554 retx->amHdr.so, retx->soEnd,
558 (*retxNode) = (*retxNode)->next;
559 rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
561 else if((!nackSnInfo->isSegment) || (retx->soEnd <= nackSnInfo->soEnd))
563 /* This case covers the NACKED segments and also the case */
564 /* when there are segments and the entire SN is nacked. */
565 /* This case also covers the case of nonsegmented retx PDU*/
567 (*retxNode) = (*retxNode)->next;
568 /* Mark the retx PDU we found for further retransmission */
569 rlcAmmDlMarkPduForReTx(gCb, rbCb, retx);
573 /* If we are here that means this segment and segments after this are ACKed*/
576 } /* end of retxNode while loop*/
581 * @brief Function to get nack Sn information from nackRange index
584 * This function is used to get nack Sn information from nackRange index
586 * @param[in]RlcAmDl *amDl,
587 * @param[in]RlcUdxStaPdu *StaPdu,
588 * @param[in]RlcNackInfo *nackSnInfo,
589 * @param[in]RlcRetx *retx;
590 * @param[in]RlcSn sn,
591 * @param[in]uint8_t idx
596 static Void RlcDlAmmGetNackSnInfoFrmNackRangeIdx
599 RlcNackInfo *nackInfo,
601 RlcNackInfo *nackSnInfo,
609 nackSnInfo->isSegment = FALSE;
611 if((!nackInfo->isSegment) || (!idx && nackSnInfo->nackRange && (!nackInfo->soStart)))
613 nackSnInfo->soStart = 0;
614 nackSnInfo->soEnd = 0;
617 txBuf = rlcUtlGetTxBuf(amDl->txBufLst, nackSnInfo->sn);
620 node = txBuf->pduLst.first;
623 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(node->node);
624 uint16_t pduSoEnd = pduInfo->amHdr.so + pduInfo->sduMap.sduSz - 1;
625 if((!idx) && (pduInfo->amHdr.so == nackInfo->soStart))
627 nackSnInfo->isSegment = TRUE;
628 nackSnInfo->soStart = pduInfo->amHdr.so;
629 nackSnInfo->soEnd = pduSoEnd;
632 else if((idx == nackSnInfo->nackRange - 1) && \
633 (pduSoEnd == nackInfo->soEnd))
635 nackSnInfo->isSegment = TRUE;
636 nackSnInfo->soStart = pduInfo->amHdr.so;
637 nackSnInfo->soEnd = pduSoEnd;
643 if(!nackSnInfo->isSegment)
647 retx = (RlcRetx *)(retxNode->node);
648 if(retx->amHdr.sn != nackSnInfo->sn)
652 if((!idx) && (retx->amHdr.so == nackInfo->soStart))
654 nackSnInfo->isSegment = TRUE;
655 nackSnInfo->soStart = retx->amHdr.so;
656 nackSnInfo->soEnd = retx->soEnd;
659 else if((idx == nackSnInfo->nackRange - 1) && \
660 (retx->soEnd == nackInfo->soEnd))
662 nackSnInfo->isSegment = TRUE;
663 nackSnInfo->soStart = retx->amHdr.so;
664 nackSnInfo->soEnd = retx->soEnd;
667 retxNode = retxNode->next;
673 * @brief Function to update transmission buffers and send confimations to
674 * PDCP on the reception of Status PDU
677 * First processes the NACKs received
678 * -# Removes the pdus which are acked by each of the NACK SN from the
679 * transmission and re-transmission buffer
680 * -# If NACKed SN in in the transmisson buffer, moves it to re-transmission
682 * -# Removes PDU segments of the NACKed SN which have been successfully
683 * received by the other end. For the un-successful ones, marks them for
685 * -# When PDUs/segments are removed from the buffer, indicates to upper
686 * layer if the SDU is completely delivered
687 * -# Removes the PDUs/segments which are acked by the ACK_SN but not by the
690 * @param[in] gCb RLC Instance control block
691 * @param[in] rbCb Downlink Radio Bearer control block
692 * @param[in] pStaPdu The decoded Status Pdu
696 Void rlcAmmDlHndlStatusPdu(RlcCb *gCb,RlcDlRbCb *rbCb,RlcUdxStaPdu *pStaPdu)
701 KwuDatCfmInfo* datCfm;
702 RlcKwuSapCb *rlckwuSap;
707 rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
708 /* store the re-transmission bo, to check if it changes due to the
709 processing of the status pdu */
710 oldRetxBo = RLC_AMDL.retxBo;
712 /* Allocate memory for datCfm Info */
713 RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
715 #if (ERRCLASS & ERRCLS_ADD_RES)
718 DU_LOG("\nERROR --> RLC_DL : Memory allocation failed UEID:%d CELLID:%d",
721 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
724 #endif /* ERRCLASS & ERRCLS_RES */
726 datCfm->numSduIds = 0;
727 datCfm->rlcId = rbCb->rlcId;
729 MODAMT(pStaPdu->ackSn, mAckSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
730 MODAMT(RLC_AMDL.txNext,mTxNext, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
734 DU_LOG("\nERROR --> RLC_DL : Invalid ACK SN = %d received. Current Vta =%d"
740 /* RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo)); */
741 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
745 /* Venki - stopping the poll retx timer */
746 /*Stop PollRetx Tmr */
747 rlcAmmDlCheckAndStopPollTmr(gCb, rbCb, mAckSn);
749 /* Set the first node in retx list to retxNode */
750 retxNode = RLC_AMDL.retxLst.first;
752 /* If NACK exists in control PDU */
753 if (pStaPdu->nackCnt)
756 RlcNackInfo nackSnInfo;
759 RlcSn transWinStartSn = RLC_AMDL.txNextAck; /*used to track the SN from which
760 to start processing the transmission
764 /* if any NACKs then txNextAck should be equal to the first NACK_SN*/
765 txNextAck = pStaPdu->nackInfo[0].sn;
767 rlcStatusNcnt += pStaPdu->nackCnt;
770 while (idx < pStaPdu->nackCnt)
772 nackSnInfo.isSegment = pStaPdu->nackInfo[idx].isSegment;
773 nackSnInfo.nackRange = pStaPdu->nackInfo[idx].nackRange;
774 nackSnInfo.sn = pStaPdu->nackInfo[idx].sn;
776 DU_LOG("\nDEBUG --> RLC_DL : rlcHndlStaRsp: NACK SN = %d UEID:%d CELLID:%d",
781 nackSnInfo.soStart = pStaPdu->nackInfo[idx].soStart;
782 nackSnInfo.soEnd = pStaPdu->nackInfo[idx].soEnd;
784 /* e2 is used as a boolean indicating presence of SOStart or SOEnd */
786 sn = transWinStartSn;
788 /* move transWinStartSn to nackSnInfo.sn + 1, as the pdu's before that
789 will be removed from the buffer */
790 transWinStartSn = (nackSnInfo.sn + (nackSnInfo.nackRange ?\
791 (nackSnInfo.nackRange - 1) : 0) + 1) & RLC_AMDL.snModMask;
793 /* Clear the acked SNs from the retx list */
794 MODAMT(nackSnInfo.sn, mNackSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
796 if ((mNackSn > mAckSn) || (mNackSn >= mTxNext))
798 /* Erroneous NACK_SN, we should raise an error towards L3 */
799 DU_LOG("\nERROR --> RLC_DL : Status Pdu is not correct UEID:%d CELLID:%d",
802 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
806 /* clear all the SNs < NACK_SN from re-transmission list */
807 rlcAmmDlUpdTxAndReTxBufForLessThanNackSn(gCb, rbCb, sn, mNackSn,
810 if(!nackSnInfo.nackRange)
812 rlcAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, &nackSnInfo, &retxNode, &datCfm);
813 gRlcStats.amRlcStats.numRlcAmCellNackRx++;
818 /* Update issegment, soStart, soEnd ,sn in nackSnInfo and handle
822 RlcDlAmmGetNackSnInfoFrmNackRangeIdx(&RLC_AMDL, &pStaPdu->nackInfo[idx],
823 retxNode, &nackSnInfo, idx1);
825 rlcAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, &nackSnInfo,
827 nackSnInfo.sn = ((nackSnInfo.sn + 1) & (RLC_AMDL.snModMask));
828 gRlcStats.amRlcStats.numRlcAmCellNackRx++;
830 }while((++idx1) < (nackSnInfo.nackRange));
834 } /* End of nackCnt while loop */
836 /* Remove the PDUs with are further acked by the ACK_SN after taking
837 care of all the NACK_SN related acknowledgments*/
838 rlcAmmDlUpdateTxAndReTxBufForAckSn(gCb,rbCb, mAckSn, retxNode, &datCfm);
840 /* Update txNextAck */
841 rlcAmmDlSetTxNextAck(&RLC_AMDL,txNextAck);
847 DU_LOG("\nDEBUG --> RLC_DL : rlcHndlStaRsp: Received All ACKS UEID:%d CELLID:%d",
851 /* For the remaining ACKs after last nackSn */
852 rlcAmmDlUpdateTxAndReTxBufForAckSn(gCb,rbCb, mAckSn, retxNode, &datCfm);
854 /* update txNextAck */
855 rlcAmmDlSetTxNextAck(&RLC_AMDL, pStaPdu->ackSn);
858 if(datCfm->numSduIds != 0)
860 if(datCfm->numSduIds > 1024)
862 DU_LOG("\nDEBUG --> RLC_DL : Sending [%u] SDU Cfms to PDCP & [%u] lost for"
865 datCfm->numSduIds-1024,
868 datCfm->numSduIds = 1024;
870 rlcSduSndCnt += datCfm->numSduIds;
871 /* Sap control block */
872 RlcUiKwuDatCfm(&rlckwuSap->pst, rlckwuSap->suId, datCfm);
876 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
879 /* Fix for memory corruption */
880 RLC_LLIST_FIRST_RETX(RLC_AMDL.retxLst, RLC_AMDL.nxtRetx);
881 /* BO update, if retransmission BO has changed. RLC_AMDL.retxBo would have
882 canged inside the above called functions */
883 if (oldRetxBo != RLC_AMDL.retxBo)
885 rlcAmmSendDedLcBoStatus(gCb, rbCb, &RLC_AMDL);
892 * @brief Function to calculate the current buffer occupancy
895 * Function to calculate the current bo depending on the control,
896 * re-transmit, transmit bo's and the state of the transmit window.
897 * If the transmit window is stalled, then the transmit bo is not
900 * @param[in] amDl AM mode donwlink control block
905 S32 rlcAmmCalculateBo(RlcAmDl *amDl)
909 /* Make sure non of the bo's are negative */
915 if (amDl->cntrlBo < 0)
920 if (amDl->retxBo < 0)
925 bo = amDl->cntrlBo + amDl->retxBo;
927 /* if window is not stalled then add the transmit bo also */
928 if (! RLC_AM_IS_TRANS_WIN_STALLED(amDl))
938 * @brief Handler to queue the SDUs received from PDCP
941 * This function is invoked by UIM to queue the SDU received from PDCP in the
942 * SDU queue of the corresponding RbCb. It also updates the BO and report the
944 * - Allocate memory for and assign received buffer to the SDU
945 * - Add SDU in the sduQ of RlcAmDl
946 * - Calculate bo with the buffer received
947 * - Accumulate bo with retransmission bo and control pdu's bo if available
948 * - Estimate the header size for the bo; Fill in StaRspInfo and send it
951 * @param[in] gCb RLC Instance control block
952 * @param[in] rbCb RB control block
953 * @param[in] mBuf Sdu to be queued
954 * @param[in] datReq Ptr to the datReq sent from PDCP
959 void rlcAmmQSdu(RlcCb *gCb, RlcDlRbCb *rbCb, Buffer *mBuf, RlcDatReqInfo *datReq)
971 RLC_ALLOC_WC(gCb,sdu, sizeof(RlcSdu));
973 #if (ERRCLASS & ERRCLS_ADD_RES)
976 DU_LOG("\nERROR --> RLC_DL : rlcAmmQSdu : Memory allocation failed UEID:%d CELLID:%d",\
977 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
980 #endif /* ERRCLASS & ERRCLS_RES */
982 RLC_UPD_L2_DL_TOT_SDU_STS(gCb,rbCb);
983 /* Discard new changes starts */
984 rlcUtlGetCurrTime(&sdu->arrTime);
985 /* Discard new changes ends */
986 /* Assign values to sdu */
987 ODU_GET_MSG_LEN(mBuf, &sdu->sduSz);
990 sdu->actSz = sdu->sduSz;
991 sdu->mode.am.sduId = datReq->sduId;
992 /* initialize values for AM mode to 0 */
993 sdu->mode.am.rcvdSz = 0;
994 sdu->mode.am.isSegmented = 0;
995 #ifndef RGL_SPECIFIC_CHANGES
999 dlrate_kwu += sdu->sduSz;
1003 /* Update nxtTx to point to the added sdu if this is the first SDU in the
1005 if (RLC_AMDL.nxtTx == NULLP)
1007 DU_LOG("\nDEBUG --> RLC_DL : rlcAmmQSdu: Received SDU will be transmitted next \
1008 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1009 RLC_AMDL.nxtTx = sdu;
1012 /* Add sdu to the sdu list */
1013 cmLListAdd2Tail(&RLC_AMDL.sduQ, &sdu->lstEnt);
1014 sdu->lstEnt.node = (PTR)sdu;
1018 if (rbCb->ueCb->tenbStats)
1020 if (RLC_AMDL.sduQ.count > rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxPktsInSduQ)
1022 rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxPktsInSduQ = RLC_AMDL.sduQ.count;
1024 rlcWinSz = RLC_AM_TRANS_WIN_SIZE(&RLC_AMDL);
1025 if (rlcWinSz > rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxWindowSz)
1027 rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxWindowSz = rlcWinSz;
1033 /* Update BO and estimate header size for the current BO */
1034 RLC_AMDL.bo = RLC_AMDL.bo + sdu->sduSz;
1035 if(RLC_AMDL.snLen == RLC_AM_CFG_12BIT_SN_LEN)
1037 RLC_AMDL.estHdrSz += 2;
1041 RLC_AMDL.estHdrSz += 3;
1043 #ifdef LTE_L2_MEAS_RLC
1044 /* Update numActUe if it is not active */
1045 if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_ACT_UE) &&
1046 (rbCb->ueCb->numActRb[rbCb->qci] == 0))
1048 rbCb->ueCb->numActRb[rbCb->qci]++;
1049 gCb.rlcL2Cb.numActUe[rbCb->qci]++;
1053 if(!rlcDlUtlIsReestInProgress(rbCb))
1055 rlcAmmSendDedLcBoStatus(gCb, rbCb, &RLC_AMDL);
1063 * @brief Private handler to construct control PDU
1066 * This function sets the pduSz correctly after eliminating the fixed
1067 * header sizes and the MAC header size. It copies the already prepared
1068 * STATUS PDU to the data to be sent to MAC.
1070 * @param[in] gCb RLC instance control block
1071 * @param[in] rbCb Downlink RB control block
1072 * @param[in] kwdatReq DatReq to be sent to MAC
1077 static void rlcAmmDlAssembleCntrlInfo(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
1079 RlcUdxDlSapCb *sapCb;
1082 macHdrEstmt = (rbCb->m.amDl.cntrlBo < 256) ?
1083 RLC_MAC_HDR_SZ2 : RLC_MAC_HDR_SZ3;
1084 /* Eliminate fixed hdr size (14bits including ACK_SN) */
1085 if (rlcDatReq->pduSz >= (RLC_CNTRL_PDU_FIXED_HDRSZ + macHdrEstmt))
1087 /* Check the TB size whether it is sufficcient enough to fit the
1088 status Pdu into it otherwise make arrangement such that it can fit
1089 into in a way of possible NACks*/
1090 /* ccpu00135743 : fix for MAC Hdr size calc */
1091 rlcDatReq->pduSz -= macHdrEstmt;
1093 /* Create the status Pdu with the required NACKs */
1094 rlcAmmCreateStatusPdu(gCb,rbCb,rlcDatReq);
1096 sapCb = RLC_GET_DL_SAPCB(gCb, rbCb);
1097 rlcDlUdxStaProhTmrStart(&(gCb->u.dlCb->udxDlSap->pst),
1098 sapCb->suId, &(rbCb->rlcId));
1100 /* Update number of pdus in pduInfo */
1101 rlcDatReq->pduInfo.mBuf[rlcDatReq->pduInfo.numPdu] = RLC_AMDL.mBuf;
1102 rlcDatReq->pduInfo.numPdu++;
1103 gRlcStats.amRlcStats.numDLStaPduSent++;
1105 RLC_FREE_SHRABL_BUF(gCb->u.dlCb->udxDlSap->pst.region,
1106 gCb->u.dlCb->udxDlSap->pst.pool,
1108 sizeof(RlcUdxDlStaPdu));
1110 RLC_AMDL.pStaPdu = NULLP;
1111 RLC_AMDL.mBuf = NULLP;
1112 gRlcStats.amRlcStats.numDLStaPduSent++;
1119 * @brief Handler to form the PDUs with the size indicated by MAC
1122 * This function is invoked by UTL with the PDU size indicated by
1123 * MAC (after eliminating MAC header size). It assembles control
1124 * Info / data (New SDUs / Retx PDUs), check if polling needs to be
1125 * set for the data PDU and returns PDU(s) and updated BO with
1126 * estimated header size to be sent to MAC.
1128 * - Check if the control BO is available and call rlcAssembleCntrlInfo
1129 * to assemble control Information
1130 * - Check if the pdu size is available to form PDUs from retransmission
1131 * buffer and call rlcResegRetxPdus
1132 * - Check if the pdu size is available and assemble SDUs from sduQ
1133 * if exist, using rlcAssembleSdus
1134 * - PDU Info and bo are filled in and then sent to MAC from the
1137 * @param[in] gCb RLC instance control block
1138 * @param[in] rbCb RB control block
1139 * @param[in] kwdatReq DatReq to be sent to MAC
1140 * @param[in] fillCtrlPdu Indicates whether cntrl PDU to be filled or not
1145 void rlcAmmProcessSdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq, bool fillCtrlPdu)
1147 /* Assemble control information. fillCtrlPdu parameter check is added for CA
1148 * It is used to force cntrl Pdu scheduling on PCell. for Non CA case this
1149 * flag will always be TRUE. In CA case, for PCELL it is TRUE and for SCEll
1152 if ((RLC_AMDL.cntrlBo != 0)
1158 rlcDatReq->boRep.staPduPrsnt = TRUE;
1159 rlcDatReq->boRep.staPduBo = RLC_AMDL.cntrlBo;
1161 if (RLC_AMDL.pStaPdu != NULLP)
1163 rlcAmmDlAssembleCntrlInfo (gCb, rbCb, rlcDatReq);
1167 DU_LOG("\nERROR --> RLC_DL : rlcAmmProcessSdus: Miscomputation of control Bo. \
1168 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1170 RLC_AMDL.cntrlBo = 0;
1173 /* Retransmit PDUs /portions of PDUs available in retxLst */
1174 if ((rlcDatReq->pduSz > 0) && (RLC_AMDL.nxtRetx != NULLP))
1176 rlcResegRetxPdus (gCb,rbCb, rlcDatReq);
1179 /* Assemble SDUs to form new PDUs */
1180 if ((rlcDatReq->pduSz > 0) && (RLC_AMDL.nxtTx != 0))
1182 rlcAssembleSdus(gCb,rbCb, rlcDatReq);
1185 if (RLC_AMDL.nxtRetx != NULLP)
1187 rlcDatReq->boRep.oldestSduArrTime = RLC_AMDL.nxtRetx->sduMap.sdu->arrTime;
1189 else if (RLC_AMDL.nxtTx != NULLP)
1191 rlcDatReq->boRep.oldestSduArrTime = RLC_AMDL.nxtTx->arrTime;
1194 rlcDatReq->boRep.bo = rlcAmmCalculateBo(&RLC_AMDL);
1195 rlcDatReq->boRep.staPduBo = RLC_AMDL.cntrlBo;
1197 /* Hdr estimation is moved to kwAmmCreatePDu */
1198 rlcDatReq->boRep.estHdrSz = RLC_AMDL.estHdrSz;
1200 if(rlcDatReq->pduSz > 0)
1202 gRlcStats.amRlcStats.numDLBytesUnused += rlcDatReq->pduSz;
1208 * @brief Private handler split a PDU/segment into two
1211 * Its a private function called by kwResegRetxPdu to split a segment
1212 * or a retransmit PDU into two segments splitting at the passed size.
1213 * This function is called only for those PDUs that dont have any LIs.
1215 * @param[in] gCb RLC instance control block
1216 * @param[in] rbCb RB control block
1217 * @param[in,out] crnt The PDU to be split, first part of split pdu remians
1219 * @param[out] next The second part of the split pdu
1220 * @param[in] size The size witin crnt, at which to split
1225 static void rlcSplitPdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcRetx *crnt, RlcRetx *next, uint16_t size)
1228 RlcAmDl *amDl = &RLC_AMDL;
1230 /* Set the SN for the new segment */
1231 next->amHdr.sn = crnt->amHdr.sn;
1233 /* Set the protocol specific fields appropriately */
1234 si = crnt->amHdr.si;
1235 crnt->amHdr.si = si | RLC_SI_FIRST_SEG;
1236 next->amHdr.si = si | RLC_SI_LAST_SEG;
1240 /* Update seg size */
1241 next->segSz = crnt->segSz - size;
1244 /* Set the SO fields appropriately */
1245 /* MS_FIX for DL stall */
1246 next->soEnd = crnt->soEnd;
1248 /* Set the SO fields appropriately */
1249 /* SO of next will be after the end of current */
1250 next->amHdr.so = crnt->amHdr.so + crnt->segSz;
1251 /* SO End of current will be one less than the start of next */
1252 crnt->soEnd = next->amHdr.so - 1;
1254 /* intialize the other fields in the amHdr of next to 0 */
1258 /* This macro is called for No LI case - one SDU */
1259 /* Update the size of SDU in each node's sduMap */
1260 next->sduMap.sdu = crnt->sduMap.sdu;
1261 crnt->sduMap.sduSz = crnt->segSz;
1262 next->sduMap.sduSz = next->segSz;
1264 /* Segment the payload into two parts based on the size passed */
1265 ODU_SEGMENT_MSG(crnt->seg, size, &next->seg);
1266 next->retxCnt = crnt->retxCnt;
1267 next->yetToConst = TRUE;
1268 next->pendingReTrans = crnt->pendingReTrans;
1270 /* Compute the header size and update the BO appropriately */
1271 if(amDl->snLen == RLC_AM_CFG_12BIT_SN_LEN)
1273 next->hdrSz = RLC_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1274 if(crnt->amHdr.si == RLC_SI_FIRST_SEG)
1276 crnt->hdrSz = RLC_AM_SEG_12BIT_SN_WITHOUT_SO_HDRSZ;
1280 crnt->hdrSz = RLC_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1285 next->hdrSz = RLC_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1286 if(crnt->amHdr.si == RLC_SI_FIRST_SEG)
1288 crnt->hdrSz = RLC_AM_SEG_18BIT_SN_WITHOUT_SO_HDRSZ;
1292 crnt->hdrSz = RLC_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1296 /* Add the next to the retx list */
1297 RLC_AMDL.retxLst.crnt = &crnt->lstEnt;
1298 CM_LLIST_INS_AFT_CRNT(RLC_AMDL.retxLst, next);
1299 RLC_AMDL.nxtRetx = next;
1300 amDl->estHdrSz += next->hdrSz;
1306 * @brief Private handler to retransmit PDUs or PDU segments
1309 * Its a private function called by kwProcessSdus, to create the
1310 * PDUs / its segments from the retransmission buffer available in RbCb.
1312 * - Eliminate the fixed header size and MAC header size while
1313 * forming PDUs/segments
1314 * - While pdusize is available and retxBuf has data (pdu or portion
1315 * of pdu) to be sent, form the pdu as it is if it matches with the
1316 * pdusize else segment the PDUs/portion of PDUs
1317 * - Call rlcAmmDlCheckAndSetPoll function to check and set the poll bit as
1319 * - Concatenate data and header info and fill pduInfo
1320 * - Update retxCnt and send indication to PDCP if it reaches maxRetx
1323 * @param[in] gCb RLC instance control block
1324 * @param[in] rbCb RB control block
1325 * @param[in] kwdatReq DatReq to be sent to MAC
1330 static void rlcResegRetxPdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
1334 uint8_t hdr[RLC_MAX_HDRSZ];
1340 RlcL2MeasTb *l2MeasTb;
1341 RlclchInfo *lchInfo;
1347 /* TODO : This shoould be taken care in new Trasmissions */
1348 /* This lchInfo should be retrieved there */
1349 l2MeasTb = rlcUtlGetCurMeasTb(gCb, rbCb);
1350 if (l2MeasTb == NULLP)
1354 /* TODO : This lcid needs to be searched in case of normal Tx */
1355 /* In retx here, its fine as this will be higher priority */
1356 lchInfo = &l2MeasTb->lchInfo[l2MeasTb->numLchInfo];
1357 if (l2MeasTb->numLchInfo >= RLC_MAX_ACTV_DRB)
1361 l2MeasTb->numLchInfo++;
1362 lchInfo->lcId = rbCb->lch.lChId;
1363 lchInfo->numSdus = 0;
1366 while ((rlcDatReq->pduSz > 0) && (amDl->nxtRetx != NULLP)&&
1367 (rlcDatReq->pduInfo.numPdu < RLC_MAX_PDU))
1371 retx = amDl->nxtRetx;
1372 /* kw003.201 : Add header size to seg size to determine if the */
1373 /* the segment can be completed within the allocation */
1374 /* kw003.201 - Eliminate MAC Header Size based on bites needed */
1375 tmpSz = RLC_MIN((retx->segSz + retx->hdrSz), rlcDatReq->pduSz);
1376 pduSz = (retx->segSz + retx->hdrSz);
1377 /* 5GNR_RLC_DL : length field in 5GNR MAC Hdr is 8/16 btis*/
1378 rlcDatReq->pduSz -= (tmpSz < 255) ? RLC_MAC_HDR_SZ2 : RLC_MAC_HDR_SZ3;
1380 /* kw003.201 - We should have at least one more than basic header */
1381 if (rlcDatReq->pduSz <= retx->hdrSz)
1385 rlcGetNxtRetx(gCb, &(amDl->nxtRetx));
1387 /* Send retx buf without segmentation */
1388 if (rlcDatReq->pduSz >= pduSz)
1392 DU_LOG("\nINFO --> RLC_DL : rlcResegRetxPdus: Send retx buf without segmentation "
1393 "UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1395 if (retx->yetToConst)
1397 /* Construct hdr with the available hdr values */
1398 rlcConstructAmHdr(&retx->amHdr, hdr, amDl->snLen, &idx);
1399 /* Add header to the pdu/segment */
1400 ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx + 1, retx->seg);
1401 retx->yetToConst = FALSE;
1404 /* kw003.201 - Check if poll bit needs to be set. Retx size does */
1405 /* not affect the poll bit so it is being passed as zero */
1406 pollBit = rlcAmmDlCheckAndSetPoll(gCb,rbCb, FALSE, 0);
1407 RLC_UPD_POLL_BIT(gCb, retx, pollBit);
1409 rlcDatReq->pduSz -= pduSz;
1410 RLC_AMDL.estHdrSz -= retx->hdrSz;
1413 if (rbCb->rlcId.rbType == CM_LTE_DRB)
1416 for (sduIdx = lchInfo->numSdus ;
1417 ((numSdus < retx->numSdu) && (sduIdx < RLC_L2MEAS_SDUIDX)) ;
1418 sduIdx++, numSdus++)
1420 lchInfo->sduInfo[sduIdx].arvlTime = retx->sduMap[numSdus].sdu->arrTime;
1421 lchInfo->sduInfo[sduIdx].isRetxPdu = TRUE; /* TODO : for later use */
1423 lchInfo->numSdus += numSdus;
1431 /* Segment this pdu / portion of pdu. Insert this segment into */
1432 /* retxLst and update offset */
1433 DU_LOG("\nINFO --> RLC_DL : rlcResegRetxPdus: Segment retx buf UEID:%d CELLID:%d",
1434 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1436 /* Eliminate fixed header size if the pdu is segmented for the */
1438 if(amDl->snLen == RLC_AM_CFG_12BIT_SN_LEN)
1440 if(retx->amHdr.si < RLC_SI_LAST_SEG)
1442 rlcDatReq->pduSz -= RLC_AM_SEG_12BIT_SN_WITHOUT_SO_HDRSZ;
1446 rlcDatReq->pduSz -= RLC_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1451 if(retx->amHdr.si < RLC_SI_LAST_SEG)
1453 rlcDatReq->pduSz -= RLC_AM_SEG_18BIT_SN_WITHOUT_SO_HDRSZ;
1457 rlcDatReq->pduSz -= RLC_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1460 if (rlcDatReq->pduSz <= 0)
1465 /* Allocate memory for tracking a new segment */
1466 RLC_ALLOC_WC(gCb,tNode, sizeof(RlcRetx));
1467 #if (ERRCLASS & ERRCLS_ADD_RES)
1470 DU_LOG("\nERROR --> RLC_DL : rlcResegRetxPdus: Memory allocation failed UEID:%d CELLID:%d",
1471 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1474 #endif /* ERRCLASS & ERRCLS_RES */
1476 /* initialize the list pointer to 0 instead of memset */
1477 tNode->lstEnt.next = 0;
1478 tNode->lstEnt.prev = 0;
1480 /* Segment header and data */
1481 RLC_AM_REMOVE_HDR(gCb, rbCb, retx);
1483 /* kw003.201 - Split the payload and update other fields */
1484 rlcSplitPdu(gCb,rbCb, retx, tNode, rlcDatReq->pduSz);
1489 sduIdx = lchInfo->numSdus;
1490 for (numSdus = 0, sduIdx = lchInfo->numSdus;
1491 ((numSdus < retx->numSdu) && (sduIdx < RLC_L2MEAS_SDUIDX));
1492 numSdus++, sduIdx++)
1494 lchInfo->sduInfo[sduIdx].arvlTime =
1495 retx->sduMap[numSdus].sdu->arrTime;
1496 lchInfo->sduInfo[sduIdx].isRetxPdu = TRUE;
1498 lchInfo->numSdus = sduIdx;
1499 if ((retx->amHdr.lsf == 0) && (lchInfo->numSdus > 0))
1504 /* Construct hdr with the available hdr values */
1505 rlcConstructAmHdr(&retx->amHdr, hdr, amDl->snLen, &idx);
1506 ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx + 1, retx->seg);
1508 retx->hdrSz = idx + 1;
1510 /* Poll bit need not be set for this seg, since its second */
1511 /* half remains in retxLst */
1512 RLC_UPD_POLL_BIT(gCb, retx, FALSE);
1513 retx->yetToConst = FALSE;
1514 rlcDatReq->pduSz = 0;
1517 rlcCpyMsg(gCb,retx->seg, &pdu);
1519 /* Update pduInfo */
1520 rlcDatReq->pduInfo.mBuf[rlcDatReq->pduInfo.numPdu] = pdu;
1521 rlcDatReq->pduInfo.numPdu++;
1522 /* kw005.201 ccpu00117318, updating the statistics */
1523 gCb->genSts.pdusRetx += 1;
1524 gRlcStats.amRlcStats.numRlcAmCellRetxPdu++;
1525 retx->soEnd = retx->amHdr.so + retx->segSz - 1;
1526 retx->pendingReTrans = FALSE;
1527 amDl->retxBo -= retx->segSz;
1530 DU_LOG("\nINFO --> RLC_DL : rlcResegRetxPdus: retxBo after resegmentation = %ld"
1531 "UEID:%d CELLID:%d", amDl->retxBo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1533 DU_LOG("\nINFO --> RLC_DL : rlcResegRetxPdus: retxBo after resegmentation = %d "
1534 "UEID:%d CELLID:%d", amDl->retxBo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1542 * @brief Private handler to assemble SDUs to form new data PDU(s)
1545 * Its a private function called by kwProcessSdus, to create the new data
1546 * PDUs from the SDU queue of RbCb.
1548 * - While pdusize is available, segment/concatenate SDUs or else if it
1549 * matches the pdu size form PDUs accordingly.
1550 * - RLC header and MAC header size are eliminated while forming the PDUs
1551 * - Call rlcAmmDlCheckAndSetPoll function to check and set the poll bit
1553 * - Concatenate data and header info and fill pduInfo
1555 * @param[in] rbCb RB control block
1556 * @param[in] kwdatReq DatReq to be sent to MAC
1561 static void rlcAssembleSdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
1563 Buffer *pdu = NULLP;
1564 MsgLen macGrntSz = rlcDatReq->pduSz;
1565 RlcAmDl *amDl = &RLC_AMDL;
1566 RlcSdu *sdu = amDl->nxtTx;
1568 bool nxtTxUpd = FALSE;
1569 KwuDiscSduInfo *discSduInfo = NULLP;
1570 RlcKwuSapCb* rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
1572 RlcContSduLst contSduLst; /*Contained sduLst */
1573 int32_t dataVol = amDl->bo;
1574 uint32_t *totMacGrant = &rlcDatReq->totMacGrant;
1575 RlcL2MeasDlIpTh *dlIpThPut = &rbCb->l2MeasIpThruput.dlIpTh;
1576 uint8_t *sduIdx = &dlIpThPut->lastSduIdx;
1578 bool isSduSegmented;
1581 RlclchInfo *dstLchInfo;
1582 uint32_t segSduCnt = 0;
1584 uint32_t numSdus = 0;
1585 uint32_t currSduIdx = 0;
1586 RlcL2MeasTb *l2MeasTb;
1588 /* Discard new changes starts */
1591 uint8_t numNewPdu = 0;
1592 RlcTx *txBuf = NULLP;
1593 /* Discard new changes ends */
1594 volatile uint32_t startTime = 0;
1596 uint32_t fixedHdrSz;
1598 RlcAmHdr *amHdr = NULLP;
1599 RlcDlPduInfo *pduInfo = NULLP;
1602 contSduLst.numSdus = 0;
1603 contSduLst.lcId = rbCb->lch.lChId;
1605 lchInfo.lcId = rbCb->lch.lChId;
1606 lchInfo.numSdus = 0;
1608 /* Discard new changes starts */
1609 /* Allocate memory for discSdu Info */
1610 RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region,
1611 rlckwuSap->pst.pool,
1613 sizeof(KwuDiscSduInfo));
1615 #if (ERRCLASS & ERRCLS_ADD_RES)
1616 if (discSduInfo == NULLP)
1618 DU_LOG("\nERROR --> RLC_DL : rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1619 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1622 #endif /* ERRCLASS & ERRCLS_RES */
1624 discSduInfo->numSduIds = 0;
1625 discSduInfo->rlcId = rbCb->rlcId;
1627 rlcUtlGetCurrTime(&curTime);
1628 amDl->sduQ.crnt = &sdu->lstEnt;
1629 /* Eliminate fixed header size */
1630 if(amDl->snLen == RLC_AM_CFG_12BIT_SN_LEN)
1632 fixedHdrSz = RLC_AM_PDU_12BIT_SN_HDRSZ;
1636 fixedHdrSz = RLC_AM_PDU_18BIT_SN_HDRSZ;
1639 while ((macGrntSz > fixedHdrSz) && (sdu != NULLP) &&
1640 (rlcDatReq->pduInfo.numPdu < RLC_MAX_PDU) &&
1641 (numNewPdu < RLC_MAX_NEW_DL_PDU))
1644 isSduSegmented = sdu->mode.am.isSegmented;
1646 /* Discard new changes starts */
1647 if ((sdu->mode.am.isSegmented == FALSE) && (rbCb->discTmrInt > 0) && \
1648 (rbCb->rlcId.rbType == CM_LTE_DRB))
1650 timeDiff = RLC_TIME_DIFF(curTime,sdu->arrTime);
1651 if (timeDiff > rbCb->discTmrInt)
1655 SStartTask(&startTime, PID_RLC_AMM_DISC_SDUS);
1657 RLC_UPD_L2_DL_DISC_SDU_STS(gCb,rbCb);
1658 /* TODO need to send disc cfm to pdcp */
1660 /* Update bo for boReport */
1661 amDl->bo -= sdu->sduSz;
1663 /* Get next sdu for assembly */
1664 nxtNode = sdu->lstEnt.next;
1666 /* store the info for sending it to PDCP */
1667 if(discSduInfo->numSduIds > 500)
1669 DU_LOG("\nERROR --> RLC_DL : rlcAssembleSdus: This is a big error, we shouldn't be here"
1670 "UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1674 discSduInfo->sduIds[discSduInfo->numSduIds] = sdu->mode.am.sduId;
1675 discSduInfo->numSduIds++;
1677 cmLListDelFrm(&amDl->sduQ, &sdu->lstEnt);
1679 rlcUtlAddSduToBeFreedQueue(gCb, sdu);
1680 rlcUtlRaiseDlCleanupEvent(gCb);
1682 /* We need to restore the crnt in the linked list which
1683 * would have become NULL in the DelFrm above */
1684 amDl->sduQ.crnt = nxtNode;
1687 sdu = (RlcSdu*)nxtNode->node;
1692 ODU_STOP_TASK(startTime, PID_RLC_AMM_DISC_SDUS);
1701 /** Check for window stall when you are creating a new PDU */
1702 if (RLC_AM_IS_TRANS_WIN_STALLED(amDl))
1704 DU_LOG("\nINFO --> RLC_DL : Window stalled \n");
1705 gRlcStats.amRlcStats.numRlcAmCellWinStall++;
1709 hdrEstmt = fixedHdrSz;
1711 if (sdu->mode.am.isSegmented)
1713 /* Adding two byte for SO */
1716 /* Eliminate MAC header */
1717 pduSz = RLC_MIN(macGrntSz, (sdu->sduSz + hdrEstmt));
1718 hdrEstmt += (pduSz < 255) ? RLC_MAC_HDR_SZ2 : RLC_MAC_HDR_SZ3;
1720 macGrntSz -= hdrEstmt;
1721 /* Check for PDU Size is large enough */
1727 /* Dont create new txBuf for segmented SDU */
1728 if (!sdu->mode.am.isSegmented)
1731 RLC_ALLOC_WC(gCb,txBuf, sizeof(RlcTx));
1733 cmLListInit(&txBuf->pduLst);
1735 #if (ERRCLASS & ERRCLS_ADD_RES)
1738 uint32_t avblMem = 0;
1739 SRegInfoShow(gCb->init.region, &avblMem);
1740 DU_LOG("\nERROR --> RLC_DL : rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1741 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1744 #endif /* ERRCLASS & ERRCLS_RES */
1746 rlcUtlStoreTxBuf(amDl->txBufLst, txBuf, amDl->txNext);
1750 txBuf = rlcUtlGetTxBuf(amDl->txBufLst, amDl->txNext);
1753 RLC_ALLOC_WC(gCb,pduInfo, sizeof(RlcDlPduInfo));
1754 #if (ERRCLASS & ERRCLS_ADD_RES)
1755 if (pduInfo == NULLP)
1757 uint32_t avblMem = 0;
1758 SRegInfoShow(gCb->init.region, &avblMem);
1759 DU_LOG("\nERROR --> RLC_DL : rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1760 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1763 #endif /* ERRCLASS & ERRCLS_RES */
1765 /*Initialize DL segment structure */
1766 pduInfo->lstEnt.next = NULLP;
1767 pduInfo->lstEnt.prev = NULLP;
1768 pduInfo->lstEnt.node = NULLP;
1770 pduInfo->pdu = NULLP;
1771 pduInfo->amHdr.dc = 0;
1772 pduInfo->amHdr.p = 0;
1773 pduInfo->amHdr.si = 0;
1774 pduInfo->amHdr.so = 0;
1776 pduInfo->amHdr.sn = amDl->txNext;
1778 /* No Segmentation scenario :
1779 * If SDU size is less than or equal to the requested PDU size
1780 * - Allocate memory and copy SDU into it.
1782 * -# Remove SDU from the Queue.
1784 if (macGrntSz >= sdu->sduSz)
1788 /* Update Framing Info */
1789 if (sdu->mode.am.isSegmented)
1791 /*5GNR RLC_DL : SN should be same for all segment of a SDU*/
1792 pduInfo->amHdr.sn = sdu->mode.am.sn;
1793 pduInfo->amHdr.si = RLC_SI_LAST_SEG; /* binary 10 */
1794 pduInfo->amHdr.so = sdu->actSz - sdu->sduSz;
1795 sdu->mode.am.isSegmented = FALSE;
1797 gRlcStats.amRlcStats.numRlcAmCellSduTx++;
1801 gRlcStats.amRlcStats.numRlcAmCellSduTx++;
1803 amHdr = &pduInfo->amHdr;
1804 /* Create PDU with hdr and data */
1805 rlcAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
1807 #ifdef LTE_L2_MEAS_RLC
1808 rlcUtlUpdSduSnMap(rbCb, sdu, rlcDatReq, TRUE);
1809 #endif /* LTE_L2_MEAS */
1811 /* kw005.201 ccpu00117318, updating the statistics */
1812 rlcUtlIncrementKwuStsSduTx(gCb->u.dlCb->rlcKwuDlSap + rbCb->k1wuSapId);
1814 if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb))
1818 *sduIdx = dlIpThPut->lastSduIdx;
1822 RLC_GETSDUIDX(*sduIdx);
1825 rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
1826 rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
1827 sdu->mode.am.sduId, newIdx);
1828 /* Update the arrival time for each SDU */
1829 if ( lchInfo.numSdus < RLC_L2MEAS_SDUIDX)
1831 lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime;
1836 sduMap.sduSz = sdu->sduSz;
1841 * Allocate buffer for next PDU
1842 * Remove the segmented portion from SDUQ
1843 * Calculate the hdr with LI for SDU */
1845 Buffer *remSeg = NULLP;
1848 if(RLC_MEAS_IS_DL_IP_MEAS_ON_FOR_RB(gCb,rbCb) ||
1849 RLC_MEAS_IS_DL_DELAY_MEAS_ON_FOR_RB(gCb,rbCb) ||
1850 RLC_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb) )
1852 /* If actual size of the sdu is equal to msgLen
1853 * then it is first segment of the SDU */
1854 if(sdu->actSz == sdu->sduSz)
1856 RLC_GETSDUIDX(*sduIdx);
1861 *sduIdx = dlIpThPut->lastSduIdx;
1863 rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
1864 rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
1865 sdu->mode.am.sduId, newIdx);
1866 if(RLC_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb))
1868 /* If actual size of the sdu is equal to msgLen
1869 * then it is first segment of the SDU */
1870 if(sdu->actSz == sdu->sduSz)
1878 /* Segment the SDU to the size of the PDU and update header Info */
1879 ODU_SEGMENT_MSG(sdu->mBuf, macGrntSz, &remSeg);
1883 /* Update SI and SN */
1884 if (sdu->mode.am.isSegmented)
1886 /*5GNR RLC_DL : SN should be same for all segment of a SDU.
1887 * Sdu was already segmented and segmenting again*/
1888 pduInfo->amHdr.sn = sdu->mode.am.sn;
1889 pduInfo->amHdr.si = RLC_SI_MID_SEG; /* binary 11 */
1890 pduInfo->amHdr.so = sdu->actSz - sdu->sduSz;
1894 /*5GNR RLC_DL : This means it is the first*/
1895 pduInfo->amHdr.si = RLC_SI_FIRST_SEG; /* binary 01 */
1896 /*5GNR_RLC_DL : Store SN so that in sub-seqent SDU segments will use this SN*/
1897 sdu->mode.am.sn = pduInfo->amHdr.sn;
1898 pduInfo->amHdr.so = 0;
1902 amHdr = &pduInfo->amHdr;
1903 /* Create PDU with hdr and data */
1904 rlcAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
1906 sdu->mode.am.isSegmented = TRUE;
1907 sdu->sduSz -= macGrntSz;
1908 sduMap.sduSz = macGrntSz;
1910 #ifdef LTE_L2_MEAS_RLC
1911 rlcUtlUpdSduSnMap(rbCb, sdu, rlcDatReq, FALSE);
1912 #endif /* LTE_L2_MEAS */
1918 /* Update bo for boReport */
1919 amDl->bo -= sduMap.sduSz;
1923 /* Update pduInfo */
1924 rlcDatReq->pduInfo.mBuf[rlcDatReq->pduInfo.numPdu] = pdu;
1925 rlcDatReq->pduInfo.numPdu++;
1927 /* kw005.201 ccpu00117318, updating the statistics */
1928 gCb->genSts.pdusSent++;
1929 gRlcStats.amRlcStats.numRlcAmCellSduBytesTx = gRlcStats.amRlcStats.numRlcAmCellSduBytesTx + sduMap.sduSz;
1930 /* Update the RLC Tx buffer with the new PDU info */
1931 RLC_MEM_CPY(&pduInfo->sduMap, &sduMap, sizeof(RlcSduMap));
1934 macGrntSz -= sduMap.sduSz;
1935 /* Get next sdu for assembly */
1936 RLC_LLIST_NEXT_SDU(amDl->sduQ, sdu);
1938 } /*End of pduSz loop */
1940 rlcDatReq->pduSz = macGrntSz;
1941 /* Updating nxtTx to sdu in the Q */
1946 if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) &&
1947 (rbCb->rlcId.rbType == CM_LTE_DRB))
1951 l2MeasTb = rlcUtlGetCurMeasTb(gCb, rbCb);
1952 rlcUtlUpdateBurstSdus(gCb, rbCb, &contSduLst, dataVol, *totMacGrant);
1953 if ((lchInfo.numSdus != 0) && (l2MeasTb != NULLP))
1955 for (lchIdx = 0; ((lchIdx < l2MeasTb->numLchInfo)
1956 && (lchIdx < RLC_MAX_ACTV_DRB )); lchIdx++)
1958 if (l2MeasTb->lchInfo[lchIdx].lcId == rbCb->lch.lChId)
1960 /* Lch Info already added in Retx procedure */
1964 if (lchIdx < RLC_MAX_ACTV_DRB)
1966 if (lchIdx == l2MeasTb->numLchInfo)
1968 l2MeasTb->lchInfo[lchIdx].lcId = rbCb->lch.lChId;
1969 l2MeasTb->lchInfo[lchIdx].numSdus = 0;
1970 l2MeasTb->numLchInfo++;
1972 dstLchInfo = &l2MeasTb->lchInfo[lchIdx];
1973 currSduIdx = l2MeasTb->lchInfo[lchIdx].numSdus;
1974 while ((numSdus < lchInfo.numSdus) && (currSduIdx < RLC_L2MEAS_SDUIDX))
1976 dstLchInfo->sduInfo[currSduIdx].arvlTime = lchInfo.sduInfo[numSdus].arvlTime;
1977 dstLchInfo->sduInfo[currSduIdx].isRetxPdu = FALSE;
1981 l2MeasTb->lchInfo[lchIdx].numSdus += numSdus;
1984 /* Fix Klock warning */
1985 if(l2MeasTb != NULLP)
1987 l2MeasTb->txSegSduCnt += segSduCnt;
1990 *totMacGrant -= (oldBo - amDl->bo);
1993 if(discSduInfo->numSduIds != 0)
1995 /* Sap control block */
1996 RlcUiKwuDiscSduCfm(&rlckwuSap->pst, rlckwuSap->suId, discSduInfo);
2000 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, discSduInfo, sizeof(KwuDiscSduInfo));
2003 DU_LOG("\nDEBUG --> RLC_DL : rlcAssembleSdus: BO after assembly = %d UEID:%d CELLID:%d",
2004 amDl->bo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
2009 * @brief Private handler to check if the poll bit needs to be set for data PDU
2012 * Its a private function called by kwProcessSdus, to checks if the
2013 * polling bit needs to be set for any RLC data PDU and updates the
2015 * - For the new PDUs, if the counters exceed the configured
2016 * pduWoPoll/byteWoPoll values, return poll bit.
2017 * - For the PDUs/portion of PDUs, if the SDU list / retxBuf is
2018 * empty, return poll bit.
2019 * - Update the pollPdu, pollByte counters and Poll_SN; start staProhTmr
2021 * @param[in] rCb RLC instance control block
2022 * @param[in] rbCb RB control block
2023 * @param[in] newPdu Flag to indicate if its a new AMD PDU.
2024 * @param[in] bufSz Length of the PDU
2027 * -# 1 - To set the poll bit
2028 * -# 0 - Poll bit is not set
2031 static bool rlcAmmDlCheckAndSetPoll(RlcCb *gCb, RlcDlRbCb *rbCb, bool newPdu, MsgLen bufSz)
2033 bool pollBit = FALSE;
2034 RlcAmDl *amDl = &(rbCb->m.amDl);
2036 /* If it's a new PDU increment PDU without poll and bytes without poll
2037 and check if they cross the configured number of poll pdu and poll bytes*/
2041 /* Patch kw004.201 */
2042 amDl->byteWoPoll += bufSz;
2044 if (((amDl->pollPdu != -1) && (amDl->pduWoPoll >= amDl->pollPdu)) ||
2045 ((amDl->pollByte != -1) && (amDl->byteWoPoll >= amDl->pollByte)))
2051 /* Check if both tx/retx buffer are empty or if tx window is stalled */
2052 if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) ||
2053 RLC_AM_IS_TRANS_WIN_STALLED(amDl))
2060 amDl->pduWoPoll = 0;
2061 amDl->byteWoPoll = 0;
2063 amDl->pollSn = (amDl->txNext - 1) & amDl->snModMask;
2065 DU_LOG("\nINFO --> RLC_DL : rlcAmmDlCheckAndSetPoll: Poll SN = %d UEID:%d CELLID:%d",
2066 amDl->pollSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
2068 /* kw005.201: Fix for poll retransmission timer.
2069 * Timer is stopped if it is already running and
2070 * then starting the timer. Fixes crs
2071 * ccpu00117216 and ccpu00118284 .
2073 if( TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMDL_POLL_RETX_TMR) )
2075 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR);
2078 rlcStartTmr(gCb,(PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR);
2085 * @brief Private handler to create AMD PDU
2088 * This function constructs header and concatenate it with the data for
2089 * the PDU. It also updates the txBuf with the created PDU.
2091 * @param[in] gCB RLC instance control block
2092 * @param[in] rbCb Downlink RB control block
2093 * @param[in] amHdr AM header
2094 * @param[in] RlcDlPduInfo Pointer to PduInfo
2095 * @param[in] pdu PDU buffer
2100 static void rlcAmmCreatePdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcAmHdr *amHdr,
2101 RlcDlPduInfo *pduInfo, Buffer *pdu)
2103 uint8_t hdr[RLC_MAX_HDRSZ];
2107 RlcAmDl *amDl = &(rbCb->m.amDl);
2110 amHdr->sn = amDl->txNext;
2111 /*5GNR RLC_DL : Increment txNext only if no segmentation of it is a last segment */
2112 if((!amHdr->si) || (amHdr->si == RLC_SI_LAST_SEG))
2114 amDl->txNext = (amDl->txNext + 1) & amDl->snModMask;
2117 /* Update hdr Info */
2118 ODU_GET_MSG_LEN(pdu, &pduSz);
2120 /* passing newPDU = TRUE*/
2121 amHdr->p = rlcAmmDlCheckAndSetPoll(gCb,rbCb, TRUE, pduSz);
2123 /* Construct header with the available hdr Info, set isSegment to FALSE */
2124 rlcConstructAmHdr(amHdr, hdr, amDl->snLen, &idx);
2126 /* Concatenate hdr and data */
2127 ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx+1, pdu);
2129 txBuf = rlcUtlGetTxBuf(amDl->txBufLst, amHdr->sn);
2130 rlcCpyMsg(gCb,pdu,&(pduInfo->pdu));
2131 pduInfo->pduSz = pduSz;
2132 pduInfo->hdrSz = idx+1;
2134 /*Update estHdrSz. deduct current hdrSz */
2135 amDl->estHdrSz -= pduInfo->hdrSz;
2136 /* Reestimate estHdrSz for mid and last seg */
2139 amDl->estHdrSz += ((amHdr->si == RLC_SI_MID_SEG)? pduInfo->hdrSz : (pduInfo->hdrSz + 2));
2142 cmLListAdd2Tail(&txBuf->pduLst, &pduInfo->lstEnt);
2143 pduInfo->lstEnt.node = (PTR)pduInfo;
2145 gCb->genSts.bytesSent += pduSz;
2151 * @brief Private handler to remove the retx PDU from the rbCb
2154 * This function releases a retx PDU stored on DL portion of rbCb.
2155 * It also updates the BO if wtForAck flag is not set which implies
2156 * that it is not sent out yet.
2158 * @param[in] gCb RLC instance control block
2159 * @param[in] retx retransmit PDU to be removed
2160 * @param[in] rbCb Radio Bearer Control Block
2165 static Void rlcRemRetxPdu(RlcCb *gCb,RlcDlRbCb *rbCb,RlcRetx *retx)
2167 cmLListDelFrm(&RLC_AMDL.retxLst, &retx->lstEnt);
2169 if( RLC_AMDL.retxLst.count == 0)
2171 RLC_AMDL.nxtRetx = NULLP;
2174 if(retx->pendingReTrans == TRUE)
2176 RLC_AMDL.retxBo -= retx->segSz;
2177 RLC_AMDL.estHdrSz -= retx->hdrSz;
2180 rlcUtlAddReTxPduToBeFreedQueue(gCb, retx);
2181 rlcUtlRaiseDlCleanupEvent(gCb);
2187 * @brief Private handler to mark a retx PDU for further retransmission
2190 * This function sets a retx PDU that has not been ACKed in the
2191 * received Status PDU for futher retransmission. If the retransmission
2192 * limit is reached, it releases the retx PDU and informs the higher
2193 * layers about the same.
2195 * @param[in] gCb RLC instance control block
2196 * @param[in] retx retransmit PDU to be removed
2197 * @param[in] rbCb Radio Bearer Control Block
2202 static Void rlcAmmDlMarkPduForReTx(RlcCb *gCb,RlcDlRbCb *rbCb,RlcRetx *retx)
2204 if (RLC_AMDL.maxReTxReached == TRUE)
2209 if(retx->pendingReTrans == FALSE)
2211 retx->pendingReTrans = TRUE;
2214 RLC_AMDL.retxBo += retx->segSz;
2215 RLC_AMDL.estHdrSz += retx->hdrSz;
2217 if (retx->retxCnt > RLC_AMDL.maxRetx)
2219 /* RLC_DL_MAX_RETX fix */
2220 /* Marking the RB stalled for DL scheduling. This is to avoid unnecessary */
2221 /* preparation of RLC PDUs and adding the same to Tx Buffer */
2222 /* This condition is to avoid sending StaIndication more than once */
2223 if (TRUE != rbCb->m.amDl.maxReTxReached)
2225 rbCb->m.amDl.maxReTxReached = TRUE;
2226 rbCb->m.amDl.bo = 0;
2227 rbCb->m.amDl.cntrlBo = 0;
2228 rbCb->m.amDl.retxBo = 0;
2229 /* Sending BO update to SCH */
2230 rlcUtlSendDedLcBoStatus(gCb, rbCb, 0,0,0,0);
2231 rlcAmmSndStaInd(gCb, rbCb, retx);
2232 gRlcStats.amRlcStats.numDLMaxRetx++;
2235 rlcRemRetxPdu(gCb,rbCb, retx);
2241 if (RLC_AMDL.nxtRetx == NULLP)
2243 RLC_AMDL.nxtRetx = retx;
2246 gRlcStats.amRlcStats.numDLRetransPdus++;
2254 * @brief Private handler to check if SDU is completely deliverd and
2255 * send higher layers data confirmation
2258 * This function sends higher layers data confirmation for SDUs which
2259 * have been successfully delivered to the peer RLC entity.
2261 * @param[in] gCb RLC instance control block
2262 * @param[in] rbCb Radio Bearer Control Block
2263 * @param[in] sduLst List of SDUs that were part of the PDU
2264 * @param[in] numSdu Number of SDUs in the list
2269 static Void rlcAmmDlCheckIsSDUDelivered
2274 KwuDatCfmInfo **datCfm
2281 sdu->mode.am.rcvdSz += sduMap->sduSz;
2283 /* send a dat cfm if all the bytes of the sdu have been received */
2284 if (sdu->mode.am.rcvdSz == sdu->actSz)
2286 /* Send DatCfm for this sdu */
2287 if((*datCfm)->numSduIds < KWU_MAX_DAT_CFM)
2289 (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2293 /* This is an error that should never happen, we should resize
2294 * the #define to a larger value or check why we need to
2295 * send so many confirms in one go
2296 * Confrims to PDCP are being dropped in this case
2298 RlcKwuSapCb *rlckwuSap;
2299 rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
2300 RlcUiKwuDatCfm(&rlckwuSap->pst, rlckwuSap->suId, *datCfm);
2302 RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, *datCfm, sizeof(KwuDatCfmInfo));
2304 #if (ERRCLASS & ERRCLS_ADD_RES)
2305 if (*datCfm == NULLP)
2307 DU_LOG("\nERROR --> RLC_DL : Memory allocation failed UEID:%d CELLID:%d",
2309 rbCb->rlcId.cellId);
2312 #endif /* ERRCLASS & ERRCLS_RES */
2314 (*datCfm)->numSduIds = 0;
2315 (*datCfm)->rlcId = rbCb->rlcId;
2316 /* ccpu00135618: say total 1026 sduIds to copy the 1025 sduId after
2317 * new allocation of datCfm */
2318 (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2321 /* Remove SDU from the sduQ */
2322 cmLListDelFrm(&RLC_AMDL.sduQ, &sdu->lstEnt);
2323 rlcUtlAddSduToBeFreedQueue(gCb, sdu);
2324 rlcUtlRaiseDlCleanupEvent(gCb);
2331 * @brief Private handler to mark a PDU successful.
2334 * This function is called when we receive a STATUS pdu that marks
2335 * a PDU as successful. It releases the PDU from RLC entity and
2336 * informs PDCP of successful SDUs delivered as a result of this PDU.
2338 * @param[in] gCb RLC instance control block
2339 * @param[in] rbCb Radio Bearer Control Block
2340 * @param[in] sn SN that is successfully delivered to the peer
2345 static Void rlcAmmDlProcessSuccessfulTxPdu
2350 KwuDatCfmInfo **datCfm
2355 RlcTx *txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, sn);
2361 pduNode = txBuf->pduLst.first;
2364 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(pduNode->node);
2365 rlcAmmDlCheckIsSDUDelivered(gCb,
2369 pduNode = pduNode->next;
2372 rlcUtlAddTxPduToBeFreedQueue(gCb, txBuf);
2373 rlcUtlRaiseDlCleanupEvent(gCb);
2374 /* so that it is not processed again */
2375 rlcUtlRemovTxBuf(RLC_AMDL.txBufLst, txBuf, gCb);
2381 * @brief Handler to send Status Indication to PDCP
2384 * This function is used to send status indication to PDCP when the
2385 * maximum retransmission threshold value is reached for a PDU.
2387 * @param[in] gCb RLC instance control block
2388 * @param[in] rbCb RB control block
2389 * @param[in] retx The PDU/segment that failed max re-transmissions
2394 static Void rlcAmmSndStaInd
2401 KwuStaIndInfo *staInd;
2402 RlcKwuSapCb *rlckwuSap;
2404 /* Sap control block */
2405 rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
2407 /* Allocate memory for staInd Info */
2408 RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, staInd, sizeof(KwuStaIndInfo));
2410 #if (ERRCLASS & ERRCLS_ADD_RES)
2411 if (staInd == NULLP)
2413 DU_LOG("\nERROR --> RLC_DL : Memory allocation failed UEID:%d CELLID:%d",
2415 rbCb->rlcId.cellId);
2418 #endif /* ERRCLASS & ERRCLS_RES */
2420 /* Fill staInd Info */
2421 RLC_MEM_CPY(&staInd->rlcId, &rbCb->rlcId, sizeof(CmLteRlcId));
2424 staInd->sduId[0] = retx->sduMap.sdu->mode.am.sduId;
2428 RlcUiKwuStaInd(&rlckwuSap->pst, rlckwuSap->suId, staInd);
2429 #endif /* KW_PDCP */
2435 * @brief Handler to get the next node to be retransmitted from retxLst
2438 * This function is used to get the next node to be retransmitted
2441 * @param[in] gCb RLC instance control block
2442 * @param[in] retx The PDU/segment after which to find a node to be
2448 static void rlcGetNxtRetx(RlcCb *gCb, RlcRetx **retx)
2454 tNode = &((*retx)->lstEnt);
2455 tNode = tNode->next;
2459 *retx = (RlcRetx *)tNode->node;
2466 }while((*retx)->pendingReTrans == FALSE);
2472 * @brief Handler to process the re-establishment request received from UIM
2474 * @param[in] gCb RLC instance control block
2475 * @param[in] rlcId Identity of the RB in the UE/Cell for which
2476 * re-establishment is to be done
2477 * @param[in] rbCb Downlink RB control block (rbCb is freed in this
2483 Void rlcAmmDlReEstablish
2490 /* create a new AM DL RB, reset it and replace in the UeCb*/
2495 RLC_ALLOC(gCb, resetRb, sizeof(RlcDlRbCb));
2497 /* ccpu00135170 Removing KLOCK warning */
2498 if(resetRb == NULLP)
2503 RLC_MEM_CPY(resetRb, rbCb, sizeof(RlcDlRbCb));
2504 RLC_MEM_SET(&resetRb->m.amDl, 0 , sizeof(RlcAmDl));
2506 /* AGHOSH changes start */
2507 /* restore the old AM values */
2508 newAmDl = &resetRb->m.amDl;
2509 oldAmDl = &rbCb->m.amDl;
2511 newAmDl->pollPdu = oldAmDl->pollPdu;
2512 newAmDl->pollByte = oldAmDl->pollByte;
2513 newAmDl->maxRetx = oldAmDl->maxRetx;
2514 newAmDl->snLen = oldAmDl->snLen;
2515 newAmDl->snModMask = oldAmDl->snModMask;
2516 newAmDl->pollRetxTmrInt = oldAmDl->pollRetxTmrInt;
2517 rbCb->boUnRprtdCnt = (uint32_t)0;
2518 rbCb->lastRprtdBoToMac = (uint32_t)0;
2519 cmInitTimers(&(resetRb->m.amDl.pollRetxTmr), 1);
2520 /* AGHOSH changes end */
2522 if (ROK != rlcDbmFetchDlUeCb(gCb,rlcId.ueId, rlcId.cellId, &ueCb))
2524 DU_LOG("\nERROR --> RLC_DL : UeId [%d]: UeCb not found RBID;%d",
2530 if(rlcId.rbType == CM_LTE_SRB)
2532 ueCb->srbCb[rlcId.rbId] = resetRb;
2536 ueCb->drbCb[rlcId.rbId] = resetRb;
2538 /* update into the logical channel array also */
2539 ueCb->lCh[rbCb->lch.lChId - 1].dlRbCb = resetRb;
2541 if((resetRb->rlcId.rbType == CM_LTE_SRB)
2542 &&(resetRb->rlcId.rbId == 1))
2544 /* To stop the traffic on SRB2 and other DRBs*/
2545 rlcDlUtlSetReestInProgressForAllRBs(gCb, ueCb);
2549 rlcDlUtlSetReestInProgressForRB(gCb, resetRb);
2552 /* allocate the TX array again */
2556 resetRb->m.amDl.txBufLst,
2557 (RLC_TX_BUF_BIN_SIZE * sizeof(CmLListCp)));
2558 for(hashIndex = 0; hashIndex < RLC_TX_BUF_BIN_SIZE; hashIndex++)
2560 cmLListInit(&(resetRb->m.amDl.txBufLst[hashIndex]));
2563 /* send the old rb of deletion */
2564 rlcAmmFreeDlRbCb(gCb,rbCb);
2567 /* TODO: for now we are re-settting the re-establishment flag here
2568 this needs to be fixed
2569 There should be a proper intreface to resume the RBs */
2570 if(rlcId.rbType == CM_LTE_SRB)
2572 rlcDlUtlResetReestInProgress(ueCb->srbCb[rlcId.rbId]);
2576 rlcDlUtlResetReestInProgress(ueCb->drbCb[rlcId.rbId]);
2583 * @brief Handler to discard a SDU.
2586 * This function is used to discard a SDU after receiving
2587 * the Discard Request from UIM. The SDU is discarded if its
2588 * available and is not mapped to any PDU yet.
2590 * @param[in] gCb RLC instance control block
2591 * @param[in] rbCb RB control block
2592 * @param[in] sduId Sdu ID of the SDU to be discarded
2595 * -# ROK In case of successful discard
2596 * -# RFAILED In case the SDU is not found or already mapped
2598 S16 rlcAmmDiscSdu(RlcCb *gCb,RlcDlRbCb *rbCb,uint32_t sduId )
2604 * @brief Handler for Poll retransmit timer expiry
2607 * This function is used to handle events upon expiry of Poll
2610 * @param[in] gCb RLC instance control block
2611 * @param[in] rbCb Downlink RB control block
2615 Void rlcAmmPollRetxTmrExp(RlcCb *gCb,RlcDlRbCb *rbCb)
2618 RlcAmDl *amDl = &(rbCb->m.amDl);
2622 /* kw003.201 - Correcting the logic for determmining whether to do */
2623 /* any transmission of PDU. As per the spec section */
2624 /* 5.2.2.3, if there is any to transmit or retransmit, */
2625 /* do nothing. Else, pick up the VT(S) -1 for retx */
2626 /* We have nothing to transmit if window is stalled or */
2627 /* there are no SDUs to be transmitted or if there are */
2628 /* PDUs to be retransmitted. */
2629 if(CM_LTE_SRB == rbCb->rlcId.rbType)
2631 gRlcStats.amRlcStats.numDLPollTimerExpiresSrb++;
2635 gRlcStats.amRlcStats.numDLPollTimerExpiresDrb++;
2638 if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) ||
2639 RLC_AM_IS_TRANS_WIN_STALLED(amDl))
2641 sn = (amDl->txNext - 1) & amDl->snModMask;
2642 txBuf = rlcUtlGetTxBuf(amDl->txBufLst, sn);
2646 rlcAmmDlMoveFrmTxtoRetxBuffer(gCb,amDl, &retx, sn);
2648 if (RLC_AMDL.nxtRetx == NULLP)
2650 RLC_AMDL.nxtRetx = retx;
2653 rlcAmmSendDedLcBoStatus(gCb, rbCb, &RLC_AMDL);
2656 /* Get the last node in retxLst */
2657 RLC_LLIST_LAST_RETX(amDl->retxLst, retx);
2659 /* Unset wtForAck flag for the NACK PDUs */
2662 rlcAmmDlMarkPduForReTx(gCb, rbCb, retx);
2663 rlcAmmSendDedLcBoStatus(gCb, rbCb, &RLC_AMDL);
2671 * @brief Handler to update Acks for the remaining PDUs after the last accessed
2675 * This function is used to handle ACKs for the PDUs remaining after the
2676 * last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and
2677 * sends DatCfm to PDCP for the same.
2679 * @param[in] gCb RLC instance control block
2680 * @param[in] rbCb Downlink Radio Bearer control block
2681 * @param[in] mAckSn The ACK SN after doing the base modulus
2682 * @param[in] rextNode Next node in the re-transmission buffer
2688 static Void rlcAmmDlUpdateTxAndReTxBufForAckSn
2694 KwuDatCfmInfo **datCfm
2702 /* Remove pdus/segs from retxLst */
2705 retx = (RlcRetx *)(retxNode->node);
2706 retxNode = retxNode->next;
2707 MODAMT(retx->amHdr.sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2710 rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
2714 /* For the remaining; pdus not acknowldeged by the NACK_SN but being
2715 acknowledged by the ACK_SN*/
2716 /* start from the starting of the transmission window and remove till just
2718 mSn = 0; /* same as MODAMT(RLC_AMDL.txNextAck, mSn, RLC_AMDL.txNextAck);*/
2719 sn = RLC_AMDL.txNextAck;
2722 txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, sn);
2726 DU_LOG("\nDEBUG --> RLC_DL : rlcAmmDlUpdateTxAndReTxBufForAckSn: ACK for PDU "
2727 "with sn = %d UEID:%d CELLID:%d",
2730 rbCb->rlcId.cellId);
2732 rlcAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
2735 sn = (sn + 1) & RLC_AMDL.snModMask;
2736 MODAMT(sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2743 * @brief Handler to update Acks for the remaining PDUs after the last accessed
2747 * This function is used to handle ACKs for the PDUs remaining after the
2748 * last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and
2749 * sends DatCfm to PDCP for the same.
2751 * @param[in] gCb RLC instance control block
2752 * @param[in] rbCb Downlink Radio Bearer control block
2753 * @param[in] mAckSn The ACK SN after doing the base modulus
2754 * @param[in] rextNode Next node in the re-transmission buffer
2759 static Void rlcAmmDlUpdTxAndReTxBufForLessThanNackSn
2766 KwuDatCfmInfo **datCfm
2775 retx = (RlcRetx *)((*retxNode)->node);
2776 MODAMT(retx->amHdr.sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2779 (*retxNode) = (*retxNode)->next;
2780 rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
2788 /* Remove all pdus with SN < NACK_SN from the transmission buffer */
2789 MODAMT(sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2790 while (mSn < mNackSn)
2792 /* this if check seems redundant,why should mSn ever be mTxSn
2793 (which actually is VT(A) */
2794 txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, sn);
2795 if ((txBuf != NULLP))
2797 DU_LOG("\nDEBUG --> RLC_DL : rlcHndlStaRsp: Handle ACK (sn = %d) UEID:%d CELLID:%d",
2800 rbCb->rlcId.cellId);
2802 /* Remove pdus from txBuf */
2803 rlcAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
2806 sn = (sn + 1) & RLC_AMDL.snModMask;
2807 MODAMT(sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2815 * @brief Handler to form construct AM header
2818 * This function is used to construct am header with the available header
2821 * @param[in] gCb RLC instance control block
2822 * @param[in] amHdr AM Header
2823 * @param[in] isSeg Check for Segmentation of PDU
2824 * @param[in] hdr Header field
2825 * @param[in] idx Index
2830 static void rlcConstructAmHdr(RlcAmHdr *amHdr, uint8_t *hdr, uint8_t snLen, uint16_t *idx)
2833 hdr[0] = RLC_DATA_BITMASK;
2835 hdr[0] = hdr[0] | (amHdr->p << 6);
2836 hdr[0] = hdr[0] | ((amHdr->si & 0x3) << 4);
2837 if(snLen == RLC_AM_CFG_12BIT_SN_LEN)
2839 hdr[0] = hdr[0] | (uint8_t)((amHdr->sn & 0xF00) >> 8);
2840 hdr[1] = (uint8_t)(amHdr->sn & 0x0FF);
2845 hdr[0] = hdr[0] | (uint8_t)((amHdr->sn & 0x30000) >> 16);
2846 hdr[1] = (uint8_t)((amHdr->sn & 0xFF00) >> 8);
2848 hdr[2] = (uint8_t)(amHdr->sn & 0xFF);
2852 if ((amHdr->si == RLC_SI_MID_SEG) || (amHdr->si == RLC_SI_LAST_SEG))
2855 hdr[(*idx)] = (uint8_t)((amHdr->so & 0xFF00)>> 8);
2857 hdr[(*idx)] = (uint8_t)(amHdr->so & 0xFF);
2864 * @brief This function adds a retx PDU to list of retx PDUs
2867 * kw003.201 - Poll expiry may cause an SN to be added to retx
2868 * out of sequence and hence all additions to retx
2869 * must validate that they are added in sequence
2871 * @param[in] amDl AM Downlink Control Block
2872 * @param[in] retx Retransmit PDU
2877 static Void rlcAmmAddPduToRetxLst(RlcAmDl *amDl,RlcRetx *retx)
2884 node = amDl->retxLst.last;
2885 MODAMT(retx->amHdr.sn, retxMSn, amDl->txNextAck,amDl->snModMask);
2886 while(node != NULLP)
2888 tRetx = (RlcRetx *)(node->node);
2889 MODAMT(tRetx->amHdr.sn, tMSn, amDl->txNextAck,amDl->snModMask);
2901 amDl->retxLst.crnt = node;
2902 cmLListInsAfterCrnt(&amDl->retxLst, &retx->lstEnt);
2903 retx->lstEnt.node = (PTR)retx;
2907 amDl->retxLst.crnt = amDl->retxLst.first;
2908 cmLListInsCrnt(&amDl->retxLst, &retx->lstEnt);
2909 retx->lstEnt.node = (PTR)retx;
2912 if (amDl->nxtRetx == NULLP)
2914 amDl->nxtRetx = retx;
2921 * @brief Handler to Move the PDU from txBuf to re-transmission buffer
2924 * This function is used to move the PDU from the txBuf to re-transmit buffer
2926 * @param[in] gCb RLC instance control block
2927 * @param[in] amDl AM Downlink Control Block
2928 * @param[in] retx node in the reTx buffer to be moved to, allocated by
2930 * @param[in] sn SN in the tx buffer which needs to be moved
2936 static Void rlcAmmDlMoveFrmTxtoRetxBuffer
2944 RlcTx* txBuf = rlcUtlGetTxBuf(amDl->txBufLst, sn);
2950 while(txBuf->pduLst.first)
2952 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(txBuf->pduLst.first->node);
2954 /* Move Sdu byte segment from TX buf to retx buf*/
2955 rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb,
2960 /* Delete node from the txBuf Pdu lst */
2961 cmLListDelFrm(&txBuf->pduLst, txBuf->pduLst.first);
2962 RLC_FREE(gCb, pduInfo, sizeof(RlcDlPduInfo));
2964 /* Remove PDU from txBuf */
2965 rlcUtlDelTxBuf(amDl->txBufLst, txBuf,gCb);
2974 * function to free/release the Acknowledged mode RBCB buffers
2977 * This primitive Frees the Acknowledged Mode RbCb transmission Buffer,
2978 * retransmission Buffer and reciption Buffers
2980 * @param [in] gCb - RLC instance control block
2981 * @param [in] rbCb - Downlink RB Control Block
2985 Void rlcAmmFreeDlRbCb(RlcCb *gCb,RlcDlRbCb *rbCb)
2987 /* stop the re-transmission timer */
2988 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMDL_POLL_RETX_TMR))
2990 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR);
2993 /* store the entire Rb pointer */
2994 rbCb->rlsLnk.node = (PTR)rbCb;
2995 cmLListAdd2Tail(&gCb->u.dlCb->toBeFreed.rbLst, &rbCb->rlsLnk);
2998 cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.amDl.sduQ));
3000 rlcUtlRaiseDlCleanupEvent(gCb);
3006 * @brief Handler to create STATUS Pdu
3009 * This function is used to create status pdu
3011 * @param[in] gCb RLC instance control block
3012 * @param[in] rbCb Downlink RB control block
3013 * @param[in] rlcDatReq The data to be passed to MAC
3018 static void rlcAmmCreateStatusPdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
3020 RlcSn sn; /* sequence number */
3021 RlcSn ack_sn; /* Ack sequence number */
3022 Buffer *mBuf; /* control pdu buffer */
3023 MsgLen cntrlPduSz; /* control pdu size */
3024 uint8_t cntrlPdu[RLC_MAX_CNTRL_FIELDS]; /* control pdu to be added to mBuf */
3025 RlcUdxDlStaPdu *pStaPdu;
3026 uint16_t bytesToEncode = 0; /* bytes required to encode the STATUS PDU */
3027 uint16_t encIdx = 0;
3028 uint16_t prevEncIdx = 0;
3029 RlcNackInfo *rlcNackInfo;
3032 pStaPdu = RLC_AMDL.pStaPdu;
3041 /* ACK SN Field will be set in the end based on available Grant */
3043 encIdx = bytesToEncode = 3; /* Num Octets before NACK SN info encoding*/
3045 ack_sn = pStaPdu->ackSn;
3047 if (rbCb->m.amDl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
3050 /* If alteast one NACK SN Info then set the E1 field */
3051 if (pStaPdu->nackCount)
3061 for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3063 sn = pStaPdu->nackInfo[nkCnt].sn;
3065 rlcNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3067 bytesToEncode += 2; /* 2 Octets for NACK SN */
3069 /* Check if E2 : isSegment is set */
3070 if (rlcNackInfo->isSegment)
3072 bytesToEncode += 4; /* 4 Octets: SOstart, SOend */
3075 /* Check if E3 : nackRange is set */
3076 if (rlcNackInfo->nackRange)
3078 bytesToEncode += 1; /* 1 Octet: NACK range */
3081 /* Check if this NACK info can be accomodated in the Grant */
3082 if( rlcDatReq->pduSz >= bytesToEncode)
3084 /* If there is a NACK SN before this then set its
3088 /* NACKSN E1 E2 E3 R */
3089 cntrlPdu[prevEncIdx + 1] |= 0x8;
3092 /* 12 BIT Nack SN encode */
3093 cntrlPdu[encIdx] = (sn & 0xFF0) >> 4;
3096 cntrlPdu[encIdx + 1] = (sn & 0xF) << 4;
3098 if (rlcNackInfo->isSegment)
3101 cntrlPdu[encIdx + 1] |= 0x4;
3104 /* Add soStart and soEnd */
3106 cntrlPdu[encIdx + 2] = (rlcNackInfo->soStart) >> 8;
3107 cntrlPdu[encIdx + 3] = rlcNackInfo->soStart & 0xFF;
3110 cntrlPdu[encIdx + 4] = (rlcNackInfo->soEnd) >> 8;
3111 cntrlPdu[encIdx + 5] = rlcNackInfo->soEnd & 0xFF;
3114 if (rlcNackInfo->nackRange)
3117 cntrlPdu[encIdx + 1] |= 0x2;
3118 if(rlcNackInfo->isSegment)
3120 cntrlPdu[encIdx + 6] = rlcNackInfo->nackRange;
3124 cntrlPdu[encIdx + 2] = rlcNackInfo->nackRange;
3128 gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3130 /* Set ACK SN now */
3133 ack_sn = rlcNackInfo->sn;
3135 /* Not even one nack can be accomodated */
3144 prevEncIdx = encIdx;
3145 encIdx = bytesToEncode;
3147 }/* Loop is done for the NackCount */
3152 DU_LOG("\nINFO --> RLC_DL : rlcAssembleCntrlInfo: ACK PDU's SN = %d"\
3153 "UEID:%d CELLID:%d", ack_sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
3155 cntrlPdu[0] |= (ack_sn & 0xF00)>> 8;
3156 cntrlPdu[1] = (uint8_t)ack_sn;
3160 else if (rbCb->m.amDl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
3162 /* If alteast one NACK SN Info then set the E1 field */
3163 if (pStaPdu->nackCount)
3173 for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3175 sn = pStaPdu->nackInfo[nkCnt].sn;
3177 rlcNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3179 bytesToEncode += 3; /* 3 Octets for NACK SN */
3181 /* Check if E2 : isSegment is set */
3182 if (rlcNackInfo->isSegment)
3184 bytesToEncode += 4; /* 4 Octets: SOstart, SOend */
3187 /* Check if E3 : nackRange is set */
3188 if (rlcNackInfo->nackRange)
3190 bytesToEncode += 1; /* 1 Octet: NACK range */
3193 /* Check if this NACK info can be accomodated in the Grant */
3194 if( rlcDatReq->pduSz >= bytesToEncode)
3196 /* If there is a NACK SN before this then set its
3200 /* NACKSN E1 E2 E3 R R R */
3201 cntrlPdu[prevEncIdx + 2] |= 0x20;
3204 /* 18 BIT Nack SN encode */
3205 cntrlPdu[encIdx] = (uint8_t)((sn & 0x3FC00) >> 10);
3208 cntrlPdu[encIdx + 1] = (uint8_t)((sn & 0x3FC) >> 2);
3211 cntrlPdu[encIdx + 2] = (uint8_t)((sn & 0x3)<< 6);
3213 if (rlcNackInfo->isSegment)
3215 /* NACKSN E1 E2 E3 R R R */
3217 cntrlPdu[encIdx + 2] |= 0x10;
3220 /* Add soStart and soEnd */
3222 cntrlPdu[encIdx + 3] = (rlcNackInfo->soStart) >> 8;
3223 cntrlPdu[encIdx + 4] = (uint8_t)rlcNackInfo->soStart;
3226 cntrlPdu[encIdx + 5] = (rlcNackInfo->soEnd) >> 8;
3227 cntrlPdu[encIdx + 6] = (uint8_t)(rlcNackInfo->soEnd);
3230 if (rlcNackInfo->nackRange)
3232 /* NACKSN E1 E2 E3 R R R */
3234 cntrlPdu[encIdx + 2] |= 0x08;
3236 if (rlcNackInfo->isSegment)
3238 cntrlPdu[encIdx + 7] = rlcNackInfo->nackRange;
3242 cntrlPdu[encIdx + 3] = rlcNackInfo->nackRange;
3246 gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3248 /* Set ACK SN now */
3251 ack_sn = rlcNackInfo->sn;
3253 /* Not even one nack can be accomodated */
3256 cntrlPdu[2] &= 0xFD;
3262 prevEncIdx = encIdx;
3263 encIdx = bytesToEncode;
3265 }/* Loop is done for the NackCount */
3270 DU_LOG("\nINFO --> RLC_DL : rlcAssembleCntrlInfo: ACK PDU's SN = %d"
3271 "UEID:%d CELLID:%d", ack_sn, rbCb->rlcId.ueId,rbCb->rlcId.cellId);
3273 cntrlPdu[0] |= (ack_sn & 0x3C000) >> 14;
3274 cntrlPdu[1] = (ack_sn & 0x3FC0) >> 6;
3275 cntrlPdu[2] |= (ack_sn & 0x3F)<< 2;
3282 DU_LOG("\nERROR --> RLC_DL : rlcAssembleCntrlInfo:Conf SN LEN %d is INVALID !!!! \
3283 UEID:%d CELLID:%d", rbCb->m.amDl.snLen, rbCb->rlcId.ueId,
3284 rbCb->rlcId.cellId);
3289 ODU_GET_MSG_BUF(RLC_MEM_REGION_DL, RLC_POOL, &mBuf);
3291 mBuf = (Buffer *)rlcAmmStaPduList[rlcAmmStaPduListCnt++];
3293 if(rlcAmmStaPduListCnt > 511)
3294 rlcAmmStaPduListCnt = 0;
3297 cntrlPduSz = encIdx;
3298 ODU_ADD_POST_MSG_MULT(cntrlPdu, cntrlPduSz, mBuf);
3300 rlcDatReq->pduSz -= cntrlPduSz;
3301 /* Add mBuf to RLC_AMDL.mBuf */
3302 RLC_AMDL.mBuf = mBuf;
3307 #ifdef RLC_STA_PROC_IN_MAC/* RLC Status PDU Processing */
3309 S16 rlcProcDlStatusPdu(Pst *udxPst,SuId suId,
3310 CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu);
3312 static Void rgAmmExtractElmnt(RlcCb *gCb,Buffer *pdu,RlcExtHdr *hdrInfo)
3315 uint8_t pLen = hdrInfo->pLen;
3316 uint8_t len = (uint8_t)hdrInfo->len;
3321 /* uint8_t rLen1 = 0; */
3328 SRemPreMsg(&hdr, pdu);
3334 val = tHdr >> (RLC_BYTE_LEN - (len));
3338 else /*if (len > 8) */
3342 val = val >> (RLC_BYTE_LEN - fLen);
3343 val = val << (len - fLen);
3345 SRemPreMsg(&hdr, pdu);
3349 hdr = hdr >> (RLC_BYTE_LEN - rLen);
3352 pLen = (RLC_BYTE_LEN - rLen);
3356 rLen = rLen - RLC_BYTE_LEN;
3358 tVal = tVal << rLen;
3361 SRemPreMsg(&hdr, pdu);
3363 hdr = hdr >> (RLC_BYTE_LEN - rLen);
3366 pLen = (RLC_BYTE_LEN - rLen);
3370 hdrInfo->pLen = pLen;
3380 static Void rgAmmUlHndlStatusPdu
3392 RlcUdxStaPdu *pStaPdu;
3393 uint8_t e3; /* NACK RANGE : 5GNR */
3396 uint32_t resrvdBitsAckSn;
3397 uint32_t resrvdBitsNackSn;
3399 RLCDBGP_BRIEF(gCb, "rgAmmUlHndlStatusPdu(rbCb, cntrlPdu, fByte) \n");
3401 RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
3403 /* Extract the Control PDU */
3404 hdrInfo.hdr = (*fByte << 1);
3407 /* D/C has been shifted in the calling function */
3408 if (hdrInfo.hdr & 0xE0)
3410 RLCDBGP_ERROR(gCb, "rgAmmUlHndlStatusPdu: Reserved value for CPT received \n");
3414 RLC_ALLOC_SHRABL_BUF(udxPst->region,
3417 sizeof(RlcUdxStaPdu));
3419 #if (ERRCLASS & ERRCLS_ADD_RES)
3420 /* Memory allocation failure can not be expected */
3427 if (rbCb->m.amDl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
3430 resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_12BITS;
3431 resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_12BITS;
3433 else if (rbCb->m.amDl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
3436 resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_18BITS;
3437 resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_18BITS;
3442 resrvdBitsAckSn = 0;
3443 resrvdBitsAckSn = 0;
3446 pStaPdu->nackCnt = 0;
3448 hdrInfo.hdr = hdrInfo.hdr << RLC_CPT_LEN;
3451 hdrInfo.len = RLC_SN_LEN;
3452 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3453 pStaPdu->ackSn = hdrInfo.val;
3455 /* Check if NACK Exists */
3456 hdrInfo.len = RLC_E1_LEN;
3457 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3458 e1 = (uint8_t)hdrInfo.val;
3459 RLCDBGP_DETAIL(gCb, "rgAmmUlHndlStatusPdu: ACK SN = %d \n", pStaPdu->ackSn);
3461 /* Extract the Reserved Bits after ACK SN field */
3462 hdrInfo.len = resrvdBitsAckSn;
3463 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3466 /* If NACK exists in control PDU */
3467 /* For ACKs and NACKs */
3468 while (e1 && (pStaPdu->nackCnt < RLC_MAX_NACK_CNT))
3470 hdrInfo.len = snLen;
3471 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3472 pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
3474 hdrInfo.len = RLC_E1_LEN;
3475 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3476 e1 = (uint8_t)hdrInfo.val;
3479 /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
3481 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3482 /* e2 = (uint8_t) hdrInfo.val;*/
3484 /* Store e2 value */
3485 pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (uint8_t) hdrInfo.val;
3487 /* Extract e3 : 5GNR */
3488 /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
3490 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3491 e3 = (uint8_t) hdrInfo.val;
3493 /* Extract Reserved Bits after NACK SN */
3494 hdrInfo.len = resrvdBitsNackSn;
3495 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3497 /* Test for resegmentation */
3498 if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
3500 hdrInfo.len = RLC_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
3501 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3502 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
3504 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3505 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = hdrInfo.val;
3508 "rgAmmUlHndlStatusPdu: soStart and soEnd = %d %d \n",
3509 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
3510 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd);
3515 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
3516 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = 0;
3519 /* NACK RANGE Field is SET */
3522 /* Extract NACK range field */
3523 hdrInfo.len = RLC_NACK_RANGE_LEN;
3524 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3525 snRange = (uint8_t)hdrInfo.val;
3527 pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
3533 gRlcStats.amRlcStats.numULStaPduRcvd++;
3534 gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
3536 /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
3537 to the last NACK SN + 1 and discard the original ACK_SN*/
3538 if(pStaPdu->nackCnt == RLC_MAX_NACK_CNT)
3540 pStaPdu->ackSn = (pStaPdu->nackInfo[RLC_MAX_NACK_CNT-1].sn + 1) & amDl->snModMask;
3544 /* Parse & send Status PDU to RLC-DL */
3545 //rlcUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
3546 rlcUlUdxStaUpdReq(udxPst, suId, &rbCb->rlcId, pStaPdu);
3551 S16 rlcProcDlStatusPdu(Pst *udxPst,SuId suId,
3552 CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu)
3554 RlcDlRbCb *rbCb = NULLP;
3555 RlcDlUeCb *ueCb = NULLP;
3558 S16 retVal = RFAILED;
3560 Pst dlRlcPst = *udxPst;
3562 gCb = RLC_GET_RLCCB(1); /* DL RLC instance */
3564 if( ROK != rlcDbmFetchDlUeCb(gCb,rnti,cellId,&(ueCb)))
3566 DU_LOG("\nERROR --> RLC_DL : RLC UECb Not found...\n");
3571 rbCb = ueCb->lCh[lcId - 1].dlRbCb;
3573 /* Skip if mode is not AM */
3574 if((rbCb == NULLP) || (rbCb->mode != RLC_MODE_AM))
3579 if(ROK != SExamMsg((Data *)(&fByte),
3582 DU_LOG("\nERROR --> RLC_DL : Failure in Rlc Hdr SExamMsg\n");
3586 if(RLC_CNTRL_PDU == ((fByte & RLC_DC_POS) >> RLC_DC_SHT))
3588 SRemPreMsg(&temp, rlcSdu);
3589 dlRlcPst.selector = 1;/* LWLC*/
3590 rgAmmUlHndlStatusPdu(&dlRlcPst,suId,gCb, rbCb, rlcSdu, &fByte);
3604 /********************************************************************30**
3607 **********************************************************************/