1 /*******************************************************************************
2 ################################################################################
3 # Copyright (c) [2017-2019] [Radisys] #
5 # Licensed under the Apache License, Version 2.0 (the "License"); #
6 # you may not use this file except in compliance with the License. #
7 # You may obtain a copy of the License at #
9 # http://www.apache.org/licenses/LICENSE-2.0 #
11 # Unless required by applicable law or agreed to in writing, software #
12 # distributed under the License is distributed on an "AS IS" BASIS, #
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
14 # See the License for the specific language governing permissions and #
15 # limitations under the License. #
16 ################################################################################
17 *******************************************************************************/
19 /********************************************************************20**
21 Name: RLC - AM DL module file
25 Desc: Source code for Acknowledged Mode Module functions such as,
27 Transmission of data/control PDUs
28 Retransmission (Feedback in terms of status)
31 Reception - reordering
32 Duplicate detection for byte segments
37 *********************************************************************21*/
38 static const char* RLOG_MODULE_NAME="AMM";
39 static int RLOG_MODULE_ID=2048;
40 static int RLOG_FILE_ID=189;
41 /* header include files (.h) */
42 #include "common_def.h"
43 #include "lkw.h" /* LKW defines */
44 #include "ckw.h" /* CKW defines */
45 #include "kwu.h" /* KWU defines */
46 #include "rgu.h" /* RGU defines */
47 #include "kw_err.h" /* Err defines */
48 #include "kw_env.h" /* RLC environment options */
50 #include "kw.h" /* RLC defines */
55 /* extern (.x) include files */
56 #include "lkw.x" /* LKW */
57 #include "ckw.x" /* CKW */
58 #include "kwu.x" /* KWU */
59 #include "rgu.x" /* RGU */
67 uint32_t rlcAmmStaPduList[512];
68 uint32_t rlcAmmStaPduListCnt = 0;
73 @brief RLC Acknowledged Mode Downlink Module
75 #define RLC_MODULE (RLC_DBGMASK_AM | RLC_DBGMASK_DL)
77 uint32_t rlcStatusPduCnt, rlcStatusAckCnt, rlcStatusNcnt, rlcSduSndCnt;
83 /* forward references */
84 Void rlcAmmDlHndlStatusPdu ARGS ((RlcCb *gCb,
86 RlcUdxStaPdu *pStaPdu));
88 /* public variable declarations */
90 /* This structure holds all the global structs we need. */
92 /* private variable declarations */
94 #define RLC_AM_RMV_HDR(_gCb, _rbCb, _retx) do { \
95 if ((_retx)->yetToConst == FALSE) \
98 SSegMsg((_retx)->seg, (_retx)->hdrSz, &_pduInfo); \
99 RLC_FREE_BUF((_retx)->seg); \
100 (_retx)->seg = _pduInfo; \
102 (_rbCb)->m.amDl.estHdrSz -= retx->hdrSz;\
105 /* private function declarations */
107 static Void rlcResegRetxPdus ARGS ((RlcCb *gCb,
109 RlcDatReq *rlcDatReq));
111 static Void rlcRemRetxPdu ARGS ((RlcCb *gCb,
115 static Void rlcAmmCreateStatusPdu ARGS ((RlcCb *gCb,
117 RlcDatReq *rlcDatReq));
119 static Void rlcAmmDlMarkPduForReTx ARGS ((RlcCb *gCb,
123 static Void rlcAmmDlProcessSuccessfulTxPdu ARGS((RlcCb *gCb,
126 KwuDatCfmInfo **datCfm));
128 static Void rlcAmmDlSetTxNextAck ARGS((RlcAmDl *amDl, RlcSn sn));
130 static Void rlcAmmDlCheckAndStopPollTmr ARGS((RlcCb *gCb,
134 static Void rlcAssembleSdus ARGS ((RlcCb *gCb,
136 RlcDatReq *rlcDatReq));
138 static bool rlcAmmDlCheckAndSetPoll ARGS ((RlcCb *gCb,
143 static Void rlcAmmCreatePdu ARGS ((RlcCb *gCb,
146 RlcDlPduInfo *pduInfo,
149 static Void rlcAmmSndStaInd ARGS ((RlcCb *gCb,RlcDlRbCb *rbCb, RlcRetx *retx));
151 static Void rlcGetNxtRetx ARGS ((RlcCb *gCb, RlcRetx **retx));
153 static Void rlcConstructAmHdr ARGS ((RlcAmHdr *amHdr,
158 static Void rlcAmmDlUpdateTxAndReTxBufForAckSn ARGS ((RlcCb *gCb,
162 KwuDatCfmInfo **datCfm));
164 static Void rlcAmmDlMoveFrmTxtoRetxBuffer ARGS ((RlcCb *gCb,
169 static Void rlcAmmDlCheckIsSDUDelivered ARGS((RlcCb *gCb,
172 KwuDatCfmInfo **datCfm));
174 static Void rlcAmmAddPduToRetxLst ARGS((RlcAmDl *amDl,
177 static Void rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer ARGS(
182 RlcDlPduInfo *pduInfo
185 static Void rlcAmmDlHndlStatus4SduByteSegInTxBuf ARGS(
189 RlcNackInfo *nackSnInfo,
191 KwuDatCfmInfo **datCfm
194 static Void rlcAmmDlUpdateTxAndReTxBufForNackSn ARGS(
198 RlcNackInfo *nackSnInfo,
200 KwuDatCfmInfo **datCfm
203 static Void RlcDlAmmGetNackSnInfoFrmNackRangeIdx ARGS(
206 RlcNackInfo *nackInfo,
208 RlcNackInfo *nackSnInfo,
212 static Void rlcAmmDlUpdTxAndReTxBufForLessThanNackSn ARGS(
219 KwuDatCfmInfo **datCfm
221 /*****************************************************************************
223 AM Module contains the following funcitons:
227 - rlcAmmDlAssembleCntrlInfo
230 - rlcAmmDlCheckAndSetPoll
236 *******************************************************************************/
237 /** @addtogroup ammode */
241 * @brief Function to send a Status Response to MAC for a dedicated logical
245 * Function calculates the current bo and send a Status response for the
246 * dedicated logical channel if the bo is non zero
248 * @param[in] gCb RLC instance control block
249 * @param[in] rbCb Radio Bearer control block
250 * @param[in] amDl AM downlink control block
254 void rlcAmmSendDedLcBoStatus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcAmDl *amDl)
256 int32_t bo = rlcAmmCalculateBo(amDl);
260 rlcUtlSendDedLcBoStatus(gCb, rbCb, bo, amDl->estHdrSz, \
261 amDl->cntrlBo ?TRUE:FALSE,amDl->cntrlBo);
268 * @brief Function to check if the pollSn is acked and stop the poll timer
270 * @param[in] gCb RLC instance control block
271 * @param[in] rbCb Radio Bearer control block
272 * @param[in] mAckSn The last received ACKSN. The base modulus value should
277 static Void rlcAmmDlCheckAndStopPollTmr(RlcCb *gCb,RlcDlRbCb *rbCb,RlcSn mAckSn)
281 MODAMT(rbCb->m.amDl.pollSn, mPollSn, rbCb->m.amDl.txNextAck,rbCb->m.amDl.snModMask);
283 if (mPollSn <= mAckSn)
285 if (rlcChkTmr(gCb, (PTR)rbCb, RLC_EVT_AMDL_POLL_RETX_TMR))
287 rlcStopTmr(gCb, (PTR)rbCb, RLC_EVT_AMDL_POLL_RETX_TMR);
295 * @brief Function to set VT(A) and VT(MS). Calculates the VT(MS) from VT(A)
297 * @param[in,out] amDl AM downlink control block
298 * @param[in]sn Sequence number to be set as VT(A)
302 static Void rlcAmmDlSetTxNextAck(RlcAmDl *amDl,RlcSn sn)
304 amDl->txNextAck = sn;
310 * @brief Function to process a successfully re-transmitted PDU/segment
313 * Checks if the SDU has been completely delivered or not. Removes the PDU
314 * from the re-transmission buffer
316 * @param[in] gCb RLC instance control block
317 * @param[in] rbCb Downlink Radio Bearer control block
318 * @param[in] retx The PDU/segment which was successfully re-transmitted
322 static Void rlcAmmDlProcessSuccessfulReTx
327 KwuDatCfmInfo **datCfm
330 rlcAmmDlCheckIsSDUDelivered(gCb, rbCb, &(retx->sduMap), datCfm);
332 rlcRemRetxPdu(gCb, rbCb, retx);
338 * @brief Handler to Move the PDU from txBuf to re-transmission buffer
341 * This function is used to move the PDU from the txBuf to re-transmit buffer
343 * @param[in]RlcCb *gCb RLC instance control block
344 * @param[in]RlcAmDl *amDl AM Downlink Control Block
345 * @param[in]RlcRetx **retx node in the reTx buffer to be moved to, allocated by
347 * @param[in]RlcDlPduInfo *pduInfo TX PDU which needs to be moved
353 static Void rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer
358 RlcDlPduInfo *pduInfo
362 RLC_ALLOC_WC(gCb,*retx, sizeof(RlcRetx));
364 #if (ERRCLASS & ERRCLS_ADD_RES)
367 RLOG0(L_FATAL, "Memory allocation failed");
370 #endif /* ERRCLASS & ERRCLS_RES */
372 (*retx)->seg = pduInfo->pdu;
373 (*retx)->segSz = pduInfo->pduSz;
374 /* MS_FIX for DL stall */
375 (*retx)->soEnd = (pduInfo->amHdr.so + pduInfo->pduSz - 1);
377 (*retx)->hdrSz = pduInfo->hdrSz;
378 (*retx)->retxCnt = 1;
379 (*retx)->yetToConst = 0;
380 (*retx)->pendingReTrans = TRUE;
382 /* initialize the list pointer to 0 instead of memset */
383 (*retx)->lstEnt.next = 0;
384 (*retx)->lstEnt.prev = 0;
385 /* copy the sdu maps */
386 RLC_MEM_CPY(&((*retx)->sduMap),
390 RLC_MEM_CPY(&((*retx)->amHdr), &pduInfo->amHdr, sizeof(RlcAmHdr));
391 rlcAmmAddPduToRetxLst(amDl, (*retx));
393 /* Update the BO appropriately */
394 amDl->retxBo += (*retx)->segSz;
395 amDl->estHdrSz += (*retx)->hdrSz;
397 gRlcStats.amRlcStats.numDLRetransPdus++;
400 } /*rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer */
403 * @brief Function to handle Status of Sdu byte segment for a nackSn
406 * This function is used to move the PDU from the txBuf to re-transmit buffer
408 * @param[in]RlcCb *gCb RLC instance control block
409 * @param[in]RlcDlRbCb *rbCb AM Downlink Control Block
410 * @param[in]RlcNackInfo *nackSnInfo Nack Information of a NACK_SN
411 * @param[in]RlcRetx **retx node in the reTx buffer to be moved to, allocated by
413 * @param[in]KwuDatCfmInfo **datCfm Ptr to datCfm
419 static Void rlcAmmDlHndlStatus4SduByteSegInTxBuf
423 RlcNackInfo *nackSnInfo,
425 KwuDatCfmInfo ** datCfm
432 txBuf = rlcUtlGetTxBuf(AMDL.txBufLst, nackSnInfo->sn);
437 lnk = txBuf->pduLst.first;
440 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(lnk->node);
441 RlcSn pduSoEnd = (pduInfo->amHdr.so + pduInfo->sduMap.sduSz - 1);
443 /* If So of Sdu byte segment(pduInfo/seg) is < status pdu
444 soStart that means it's ACKED*/
445 if(pduSoEnd < nackSnInfo->soStart)
447 rlcAmmDlCheckIsSDUDelivered(gCb,
453 else if (pduSoEnd <= nackSnInfo->soEnd)
455 /* Move Sdu byte segment from TX buf to retx buf*/
456 rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb,
467 /* Delete node from the txBuf Pdu lst */
468 cmLListDelFrm(&txBuf->pduLst, lnk);
469 RLC_FREE_WC(gCb, pduInfo, sizeof(RlcDlPduInfo));
472 if(!txBuf->pduLst.count)
474 /*No more Sdu byte segment are left. Hence delete txBuf*/
475 rlcUtlDelTxBuf(AMDL.txBufLst, txBuf,gCb);
482 * @brief Function to handle Status of Sdu byte segment for a nackSn
485 * This function is used to move the PDU from the txBuf to re-transmit buffer
487 * @param[in]RlcCb *gCb RLC instance control block
488 * @param[in]RlcDlRbCb *rbCb AM Downlink Control Block
489 * @param[in]RlcNackInfo *nackSnInfo Nack Information of a NACK_SN
490 * @param[in]RlcRetx **retx node in the reTx buffer to be moved to, allocated by
492 * @param[in]KwuDatCfmInfo **datCfm Ptr to datCfm
497 static Void rlcAmmDlUpdateTxAndReTxBufForNackSn
501 RlcNackInfo *nackSnInfo,
503 KwuDatCfmInfo **datCfm
509 /* Now process the NACK_SN received. Now the NACK_SN is */
510 /* either the first element of RETX or is in TX array */
511 /* To remove the remaining acks from the pdu byte segments */
513 /* if the NACK_SN is in the transmit buffer, move it to the re-
515 txBuf = rlcUtlGetTxBuf(AMDL.txBufLst, nackSnInfo->sn);
518 if(nackSnInfo->isSegment)
520 /* Go through all the AMD PDUs of a particular SN
521 and check if segment is ACKED if yes then mark succesfully sent,
522 if segment is NACKed then move it to to retx lst */
523 rlcAmmDlHndlStatus4SduByteSegInTxBuf(gCb, rbCb, nackSnInfo, &retx, datCfm);
527 /*e2= 0 and e3= 0: Move complete PDU from TX buf to retx buf*/
528 rlcAmmDlMoveFrmTxtoRetxBuffer(gCb,
534 #if (ERRCLASS & ERRCLS_ADD_RES)
538 (*retxNode) = retx->lstEnt.next;
544 /* process the pdus/segments in the re-transmit buffer with
548 retx = (RlcRetx *)((*retxNode)->node);
549 if (retx->amHdr.sn != nackSnInfo->sn)
553 if ((nackSnInfo->isSegment) &&
554 ((retx->soEnd < nackSnInfo->soStart) /*|| (retx->amHdr.so > soEnd)*/))
556 RLOG_ARG3(L_DEBUG, DBG_RBID, rbCb->rlcId.rbId,
557 "rlcHndlStaRsp: Handle ACK for byte segment, Its "
558 "sn = %d UEID:%d CELLID:%d",
562 RLOG_ARG4(L_DEBUG, DBG_RBID, rbCb->rlcId.rbId,
563 "soStart and soEnd = %d, %d, UEID:%d CELLID:%d",
564 retx->amHdr.so, retx->soEnd,
568 (*retxNode) = (*retxNode)->next;
569 rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
571 else if((!nackSnInfo->isSegment) || (retx->soEnd <= nackSnInfo->soEnd))
573 /* This case covers the NACKED segments and also the case */
574 /* when there are segments and the entire SN is nacked. */
575 /* This case also covers the case of nonsegmented retx PDU*/
577 (*retxNode) = (*retxNode)->next;
578 /* Mark the retx PDU we found for further retransmission */
579 rlcAmmDlMarkPduForReTx(gCb, rbCb, retx);
583 /* If we are here that means this segment and segments after this are ACKed*/
586 } /* end of retxNode while loop*/
591 * @brief Function to get nack Sn information from nackRange index
594 * This function is used to get nack Sn information from nackRange index
596 * @param[in]RlcAmDl *amDl,
597 * @param[in]RlcUdxStaPdu *StaPdu,
598 * @param[in]RlcNackInfo *nackSnInfo,
599 * @param[in]RlcRetx *retx;
600 * @param[in]RlcSn sn,
601 * @param[in]uint8_t idx
606 static Void RlcDlAmmGetNackSnInfoFrmNackRangeIdx
609 RlcNackInfo *nackInfo,
611 RlcNackInfo *nackSnInfo,
619 nackSnInfo->isSegment = FALSE;
621 if((!nackInfo->isSegment) || (!idx && nackSnInfo->nackRange && (!nackInfo->soStart)))
623 nackSnInfo->soStart = 0;
624 nackSnInfo->soEnd = 0;
627 txBuf = rlcUtlGetTxBuf(amDl->txBufLst, nackSnInfo->sn);
630 node = txBuf->pduLst.first;
633 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(node->node);
634 uint16_t pduSoEnd = pduInfo->amHdr.so + pduInfo->sduMap.sduSz - 1;
635 if((!idx) && (pduInfo->amHdr.so == nackInfo->soStart))
637 nackSnInfo->isSegment = TRUE;
638 nackSnInfo->soStart = pduInfo->amHdr.so;
639 nackSnInfo->soEnd = pduSoEnd;
642 else if((idx == nackSnInfo->nackRange - 1) && \
643 (pduSoEnd == nackInfo->soEnd))
645 nackSnInfo->isSegment = TRUE;
646 nackSnInfo->soStart = pduInfo->amHdr.so;
647 nackSnInfo->soEnd = pduSoEnd;
653 if(!nackSnInfo->isSegment)
657 retx = (RlcRetx *)(retxNode->node);
658 if(retx->amHdr.sn != nackSnInfo->sn)
662 if((!idx) && (retx->amHdr.so == nackInfo->soStart))
664 nackSnInfo->isSegment = TRUE;
665 nackSnInfo->soStart = retx->amHdr.so;
666 nackSnInfo->soEnd = retx->soEnd;
669 else if((idx == nackSnInfo->nackRange - 1) && \
670 (retx->soEnd == nackInfo->soEnd))
672 nackSnInfo->isSegment = TRUE;
673 nackSnInfo->soStart = retx->amHdr.so;
674 nackSnInfo->soEnd = retx->soEnd;
677 retxNode = retxNode->next;
683 * @brief Function to update transmission buffers and send confimations to
684 * PDCP on the reception of Status PDU
687 * First processes the NACKs received
688 * -# Removes the pdus which are acked by each of the NACK SN from the
689 * transmission and re-transmission buffer
690 * -# If NACKed SN in in the transmisson buffer, moves it to re-transmission
692 * -# Removes PDU segments of the NACKed SN which have been successfully
693 * received by the other end. For the un-successful ones, marks them for
695 * -# When PDUs/segments are removed from the buffer, indicates to upper
696 * layer if the SDU is completely delivered
697 * -# Removes the PDUs/segments which are acked by the ACK_SN but not by the
700 * @param[in] gCb RLC Instance control block
701 * @param[in] rbCb Downlink Radio Bearer control block
702 * @param[in] pStaPdu The decoded Status Pdu
706 Void rlcAmmDlHndlStatusPdu(RlcCb *gCb,RlcDlRbCb *rbCb,RlcUdxStaPdu *pStaPdu)
711 KwuDatCfmInfo* datCfm;
712 RlcKwuSapCb *rlckwuSap;
717 rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
718 /* store the re-transmission bo, to check if it changes due to the
719 processing of the status pdu */
720 oldRetxBo = AMDL.retxBo;
722 /* Allocate memory for datCfm Info */
723 RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
725 #if (ERRCLASS & ERRCLS_ADD_RES)
728 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
729 "Memory allocation failed UEID:%d CELLID:%d",
732 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
735 #endif /* ERRCLASS & ERRCLS_RES */
737 datCfm->numSduIds = 0;
738 datCfm->rlcId = rbCb->rlcId;
740 MODAMT(pStaPdu->ackSn, mAckSn, AMDL.txNextAck,AMDL.snModMask);
741 MODAMT(AMDL.txNext,mTxNext, AMDL.txNextAck,AMDL.snModMask);
745 RLOG_ARG4(L_WARNING,DBG_RBID, rbCb->rlcId.rbId,
746 "Invalid ACK SN = %d received. Current Vta =%d"
752 /* RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo)); */
753 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
757 /* Venki - stopping the poll retx timer */
758 /*Stop PollRetx Tmr */
759 rlcAmmDlCheckAndStopPollTmr(gCb, rbCb, mAckSn);
761 /* Set the first node in retx list to retxNode */
762 retxNode = AMDL.retxLst.first;
764 /* If NACK exists in control PDU */
765 if (pStaPdu->nackCnt)
768 RlcNackInfo nackSnInfo;
771 RlcSn transWinStartSn = AMDL.txNextAck; /*used to track the SN from which
772 to start processing the transmission
776 /* if any NACKs then txNextAck should be equal to the first NACK_SN*/
777 txNextAck = pStaPdu->nackInfo[0].sn;
779 rlcStatusNcnt += pStaPdu->nackCnt;
782 while (idx < pStaPdu->nackCnt)
784 nackSnInfo.isSegment = pStaPdu->nackInfo[idx].isSegment;
785 nackSnInfo.nackRange = pStaPdu->nackInfo[idx].nackRange;
786 nackSnInfo.sn = pStaPdu->nackInfo[idx].sn;
788 RLOG_ARG3(L_DEBUG,DBG_RBID, rbCb->rlcId.rbId,
789 "rlcHndlStaRsp: NACK SN = %d UEID:%d CELLID:%d",
794 nackSnInfo.soStart = pStaPdu->nackInfo[idx].soStart;
795 nackSnInfo.soEnd = pStaPdu->nackInfo[idx].soEnd;
797 /* e2 is used as a boolean indicating presence of SOStart or SOEnd */
799 sn = transWinStartSn;
801 /* move transWinStartSn to nackSnInfo.sn + 1, as the pdu's before that
802 will be removed from the buffer */
803 transWinStartSn = (nackSnInfo.sn + (nackSnInfo.nackRange ?\
804 (nackSnInfo.nackRange - 1) : 0) + 1) & AMDL.snModMask;
806 /* Clear the acked SNs from the retx list */
807 MODAMT(nackSnInfo.sn, mNackSn, AMDL.txNextAck,AMDL.snModMask);
809 if ((mNackSn > mAckSn) || (mNackSn >= mTxNext))
811 /* Erroneous NACK_SN, we should raise an error towards L3 */
812 RLOG_ARG2(L_ERROR,DBG_RBID, rbCb->rlcId.rbId,
813 "Status Pdu is not correct UEID:%d CELLID:%d",
816 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
820 /* clear all the SNs < NACK_SN from re-transmission list */
821 rlcAmmDlUpdTxAndReTxBufForLessThanNackSn(gCb, rbCb, sn, mNackSn,
824 if(!nackSnInfo.nackRange)
826 rlcAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, &nackSnInfo, &retxNode, &datCfm);
827 gRlcStats.amRlcStats.numRlcAmCellNackRx++;
832 /* Update issegment, soStart, soEnd ,sn in nackSnInfo and handle
836 RlcDlAmmGetNackSnInfoFrmNackRangeIdx(&AMDL, &pStaPdu->nackInfo[idx],
837 retxNode, &nackSnInfo, idx1);
839 rlcAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, &nackSnInfo,
841 nackSnInfo.sn = ((nackSnInfo.sn + 1) & (AMDL.snModMask));
842 gRlcStats.amRlcStats.numRlcAmCellNackRx++;
844 }while((++idx1) < (nackSnInfo.nackRange));
848 } /* End of nackCnt while loop */
850 /* Remove the PDUs with are further acked by the ACK_SN after taking
851 care of all the NACK_SN related acknowledgments*/
852 rlcAmmDlUpdateTxAndReTxBufForAckSn(gCb,rbCb, mAckSn, retxNode, &datCfm);
854 /* Update txNextAck */
855 rlcAmmDlSetTxNextAck(&AMDL,txNextAck);
861 RLOG_ARG2(L_UNUSED,DBG_RBID, rbCb->rlcId.rbId,
862 "rlcHndlStaRsp: Received All ACKS UEID:%d CELLID:%d",
866 /* For the remaining ACKs after last nackSn */
867 rlcAmmDlUpdateTxAndReTxBufForAckSn(gCb,rbCb, mAckSn, retxNode, &datCfm);
869 /* update txNextAck */
870 rlcAmmDlSetTxNextAck(&AMDL, pStaPdu->ackSn);
873 if(datCfm->numSduIds != 0)
875 if(datCfm->numSduIds > 1024)
877 RLOG_ARG4(L_DEBUG,DBG_RBID,datCfm->rlcId.rbId,
878 "Sending [%lu] SDU Cfms to PDCP & [%lu] lost for"
881 datCfm->numSduIds-1024,
884 datCfm->numSduIds = 1024;
886 rlcSduSndCnt += datCfm->numSduIds;
887 /* Sap control block */
888 RlcUiKwuDatCfm(&rlckwuSap->pst, rlckwuSap->suId, datCfm);
892 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
895 /* Fix for memory corruption */
896 RLC_LLIST_FIRST_RETX(AMDL.retxLst, AMDL.nxtRetx);
897 /* BO update, if retransmission BO has changed. AMDL.retxBo would have
898 canged inside the above called functions */
899 if (oldRetxBo != AMDL.retxBo)
901 rlcAmmSendDedLcBoStatus(gCb, rbCb, &AMDL);
908 * @brief Function to calculate the current buffer occupancy
911 * Function to calculate the current bo depending on the control,
912 * re-transmit, transmit bo's and the state of the transmit window.
913 * If the transmit window is stalled, then the transmit bo is not
916 * @param[in] amDl AM mode donwlink control block
921 S32 rlcAmmCalculateBo(RlcAmDl *amDl)
925 /* Make sure non of the bo's are negative */
931 if (amDl->cntrlBo < 0)
936 if (amDl->retxBo < 0)
941 bo = amDl->cntrlBo + amDl->retxBo;
943 /* if window is not stalled then add the transmit bo also */
944 if (! RLC_AM_IS_TRANS_WIN_STALLED(amDl))
954 * @brief Handler to queue the SDUs received from PDCP
957 * This function is invoked by UIM to queue the SDU received from PDCP in the
958 * SDU queue of the corresponding RbCb. It also updates the BO and report the
960 * - Allocate memory for and assign received buffer to the SDU
961 * - Add SDU in the sduQ of RlcAmDl
962 * - Calculate bo with the buffer received
963 * - Accumulate bo with retransmission bo and control pdu's bo if available
964 * - Estimate the header size for the bo; Fill in StaRspInfo and send it
967 * @param[in] gCb RLC Instance control block
968 * @param[in] rbCb RB control block
969 * @param[in] mBuf Sdu to be queued
970 * @param[in] datReq Ptr to the datReq sent from PDCP
975 void rlcAmmQSdu(RlcCb *gCb, RlcDlRbCb *rbCb, Buffer *mBuf, KwuDatReqInfo *datReq)
987 RLC_ALLOC_WC(gCb,sdu, sizeof(RlcSdu));
989 #if (ERRCLASS & ERRCLS_ADD_RES)
992 DU_LOG("\n RLC : rlcAmmQSdu : Memory allocation failed UEID:%d CELLID:%d",\
993 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
996 #endif /* ERRCLASS & ERRCLS_RES */
998 RLC_UPD_L2_DL_TOT_SDU_STS(gCb,rbCb);
999 /* Discard new changes starts */
1000 rlcUtlGetCurrTime(&sdu->arrTime);
1001 /* Discard new changes ends */
1002 /* Assign values to sdu */
1003 ODU_GET_MSG_LEN(mBuf, &sdu->sduSz);
1006 sdu->actSz = sdu->sduSz;
1007 sdu->mode.am.sduId = datReq->sduId;
1008 /* initialize values for AM mode to 0 */
1009 sdu->mode.am.rcvdSz = 0;
1010 sdu->mode.am.isSegmented = 0;
1011 #ifndef RGL_SPECIFIC_CHANGES
1014 uint32_t dlrate_kwu;
1015 dlrate_kwu += sdu->sduSz;
1019 /* Update nxtTx to point to the added sdu if this is the first SDU in the
1021 if (AMDL.nxtTx == NULLP)
1023 DU_LOG("\nRLC : rlcAmmQSdu: Received SDU will be transmitted next \
1024 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1028 /* Add sdu to the sdu list */
1029 cmLListAdd2Tail(&AMDL.sduQ, &sdu->lstEnt);
1030 sdu->lstEnt.node = (PTR)sdu;
1034 if (rbCb->ueCb->tenbStats)
1036 if (AMDL.sduQ.count > rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxPktsInSduQ)
1038 rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxPktsInSduQ = AMDL.sduQ.count;
1040 rlcWinSz = RLC_AM_TRANS_WIN_SIZE(&AMDL);
1041 if (rlcWinSz > rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxWindowSz)
1043 rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxWindowSz = rlcWinSz;
1049 /* Update BO and estimate header size for the current BO */
1050 AMDL.bo = AMDL.bo + sdu->sduSz;
1051 if(AMDL.snLen == RLC_AM_CFG_12BIT_SN_LEN)
1059 #ifdef LTE_L2_MEAS_RLC
1060 /* Update numActUe if it is not active */
1061 if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_ACT_UE) &&
1062 (rbCb->ueCb->numActRb[rbCb->qci] == 0))
1064 rbCb->ueCb->numActRb[rbCb->qci]++;
1065 gCb.rlcL2Cb.numActUe[rbCb->qci]++;
1069 if(!rlcDlUtlIsReestInProgress(rbCb))
1071 rlcAmmSendDedLcBoStatus(gCb, rbCb, &AMDL);
1079 * @brief Private handler to construct control PDU
1082 * This function sets the pduSz correctly after eliminating the fixed
1083 * header sizes and the MAC header size. It copies the already prepared
1084 * STATUS PDU to the data to be sent to MAC.
1086 * @param[in] gCb RLC instance control block
1087 * @param[in] rbCb Downlink RB control block
1088 * @param[in] kwdatReq DatReq to be sent to MAC
1093 static void rlcAmmDlAssembleCntrlInfo(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
1095 RlcUdxDlSapCb *sapCb;
1098 macHdrEstmt = (rbCb->m.amDl.cntrlBo < 256) ?
1099 RLC_MAC_HDR_SZ2 : RLC_MAC_HDR_SZ3;
1100 /* Eliminate fixed hdr size (14bits including ACK_SN) */
1101 if (rlcDatReq->pduSz >= (RLC_CNTRL_PDU_FIXED_HDRSZ + macHdrEstmt))
1103 /* Check the TB size whether it is sufficcient enough to fit the
1104 status Pdu into it otherwise make arrangement such that it can fit
1105 into in a way of possible NACks*/
1106 /* ccpu00135743 : fix for MAC Hdr size calc */
1107 rlcDatReq->pduSz -= macHdrEstmt;
1109 /* Create the status Pdu with the required NACKs */
1110 rlcAmmCreateStatusPdu(gCb,rbCb,rlcDatReq);
1112 sapCb = RLC_GET_DL_SAPCB(gCb, rbCb);
1113 rlcDlUdxStaProhTmrStart(&(gCb->u.dlCb->udxDlSap->pst),
1114 sapCb->suId, &(rbCb->rlcId));
1116 /* Update number of pdus in pduInfo */
1117 rlcDatReq->pduInfo.mBuf[rlcDatReq->pduInfo.numPdu] = AMDL.mBuf;
1118 rlcDatReq->pduInfo.numPdu++;
1119 gRlcStats.amRlcStats.numDLStaPduSent++;
1121 RLC_FREE_SHRABL_BUF(gCb->u.dlCb->udxDlSap->pst.region,
1122 gCb->u.dlCb->udxDlSap->pst.pool,
1124 sizeof(RlcUdxDlStaPdu));
1126 AMDL.pStaPdu = NULLP;
1128 gRlcStats.amRlcStats.numDLStaPduSent++;
1135 * @brief Handler to form the PDUs with the size indicated by MAC
1138 * This function is invoked by UTL with the PDU size indicated by
1139 * MAC (after eliminating MAC header size). It assembles control
1140 * Info / data (New SDUs / Retx PDUs), check if polling needs to be
1141 * set for the data PDU and returns PDU(s) and updated BO with
1142 * estimated header size to be sent to MAC.
1144 * - Check if the control BO is available and call rlcAssembleCntrlInfo
1145 * to assemble control Information
1146 * - Check if the pdu size is available to form PDUs from retransmission
1147 * buffer and call rlcResegRetxPdus
1148 * - Check if the pdu size is available and assemble SDUs from sduQ
1149 * if exist, using rlcAssembleSdus
1150 * - PDU Info and bo are filled in and then sent to MAC from the
1153 * @param[in] gCb RLC instance control block
1154 * @param[in] rbCb RB control block
1155 * @param[in] kwdatReq DatReq to be sent to MAC
1156 * @param[in] fillCtrlPdu Indicates whether cntrl PDU to be filled or not
1161 void rlcAmmProcessSdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq, bool fillCtrlPdu)
1163 /* Assemble control information. fillCtrlPdu parameter check is added for CA
1164 * It is used to force cntrl Pdu scheduling on PCell. for Non CA case this
1165 * flag will always be TRUE. In CA case, for PCELL it is TRUE and for SCEll
1168 if ((AMDL.cntrlBo != 0)
1174 rlcDatReq->boRep.staPduPrsnt = TRUE;
1175 rlcDatReq->boRep.staPduBo = AMDL.cntrlBo;
1177 if (AMDL.pStaPdu != NULLP)
1179 rlcAmmDlAssembleCntrlInfo (gCb, rbCb, rlcDatReq);
1183 DU_LOG("\nRLC: rlcAmmProcessSdus: Miscomputation of control Bo. \
1184 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1189 /* Retransmit PDUs /portions of PDUs available in retxLst */
1190 if ((rlcDatReq->pduSz > 0) && (AMDL.nxtRetx != NULLP))
1192 rlcResegRetxPdus (gCb,rbCb, rlcDatReq);
1195 /* Assemble SDUs to form new PDUs */
1196 if ((rlcDatReq->pduSz > 0) && (AMDL.nxtTx != 0))
1198 rlcAssembleSdus(gCb,rbCb, rlcDatReq);
1201 if (AMDL.nxtRetx != NULLP)
1203 rlcDatReq->boRep.oldestSduArrTime = AMDL.nxtRetx->sduMap.sdu->arrTime;
1205 else if (AMDL.nxtTx != NULLP)
1207 rlcDatReq->boRep.oldestSduArrTime = AMDL.nxtTx->arrTime;
1210 rlcDatReq->boRep.bo = rlcAmmCalculateBo(&AMDL);
1211 rlcDatReq->boRep.staPduBo = AMDL.cntrlBo;
1213 /* Hdr estimation is moved to kwAmmCreatePDu */
1214 rlcDatReq->boRep.estHdrSz = AMDL.estHdrSz;
1216 if(rlcDatReq->pduSz > 0)
1218 gRlcStats.amRlcStats.numDLBytesUnused += rlcDatReq->pduSz;
1224 * @brief Private handler split a PDU/segment into two
1227 * Its a private function called by kwResegRetxPdu to split a segment
1228 * or a retransmit PDU into two segments splitting at the passed size.
1229 * This function is called only for those PDUs that dont have any LIs.
1231 * @param[in] gCb RLC instance control block
1232 * @param[in] rbCb RB control block
1233 * @param[in,out] crnt The PDU to be split, first part of split pdu remians
1235 * @param[out] next The second part of the split pdu
1236 * @param[in] size The size witin crnt, at which to split
1241 static void rlcSplitPdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcRetx *crnt, RlcRetx *next, uint16_t size)
1244 RlcAmDl *amDl = &AMDL;
1246 /* Set the SN for the new segment */
1247 next->amHdr.sn = crnt->amHdr.sn;
1249 /* Set the protocol specific fields appropriately */
1250 si = crnt->amHdr.si;
1251 crnt->amHdr.si = si | RLC_SI_FIRST_SEG;
1252 next->amHdr.si = si | RLC_SI_LAST_SEG;
1256 /* Update seg size */
1257 next->segSz = crnt->segSz - size;
1260 /* Set the SO fields appropriately */
1261 /* MS_FIX for DL stall */
1262 next->soEnd = crnt->soEnd;
1264 /* Set the SO fields appropriately */
1265 /* SO of next will be after the end of current */
1266 next->amHdr.so = crnt->amHdr.so + crnt->segSz;
1267 /* SO End of current will be one less than the start of next */
1268 crnt->soEnd = next->amHdr.so - 1;
1270 /* intialize the other fields in the amHdr of next to 0 */
1274 /* This macro is called for No LI case - one SDU */
1275 /* Update the size of SDU in each node's sduMap */
1276 next->sduMap.sdu = crnt->sduMap.sdu;
1277 crnt->sduMap.sduSz = crnt->segSz;
1278 next->sduMap.sduSz = next->segSz;
1280 /* Segment the payload into two parts based on the size passed */
1281 ODU_SEGMENT_MSG(crnt->seg, size, &next->seg);
1282 next->retxCnt = crnt->retxCnt;
1283 next->yetToConst = TRUE;
1284 next->pendingReTrans = crnt->pendingReTrans;
1286 /* Compute the header size and update the BO appropriately */
1287 if(amDl->snLen == RLC_AM_CFG_12BIT_SN_LEN)
1289 next->hdrSz = RLC_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1290 if(crnt->amHdr.si == RLC_SI_FIRST_SEG)
1292 crnt->hdrSz = RLC_AM_SEG_12BIT_SN_WITHOUT_SO_HDRSZ;
1296 crnt->hdrSz = RLC_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1301 next->hdrSz = RLC_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1302 if(crnt->amHdr.si == RLC_SI_FIRST_SEG)
1304 crnt->hdrSz = RLC_AM_SEG_18BIT_SN_WITHOUT_SO_HDRSZ;
1308 crnt->hdrSz = RLC_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1312 /* Add the next to the retx list */
1313 AMDL.retxLst.crnt = &crnt->lstEnt;
1314 CM_LLIST_INS_AFT_CRNT(AMDL.retxLst, next);
1315 AMDL.nxtRetx = next;
1316 amDl->estHdrSz += next->hdrSz;
1322 * @brief Private handler to retransmit PDUs or PDU segments
1325 * Its a private function called by kwProcessSdus, to create the
1326 * PDUs / its segments from the retransmission buffer available in RbCb.
1328 * - Eliminate the fixed header size and MAC header size while
1329 * forming PDUs/segments
1330 * - While pdusize is available and retxBuf has data (pdu or portion
1331 * of pdu) to be sent, form the pdu as it is if it matches with the
1332 * pdusize else segment the PDUs/portion of PDUs
1333 * - Call rlcAmmDlCheckAndSetPoll function to check and set the poll bit as
1335 * - Concatenate data and header info and fill pduInfo
1336 * - Update retxCnt and send indication to PDCP if it reaches maxRetx
1339 * @param[in] gCb RLC instance control block
1340 * @param[in] rbCb RB control block
1341 * @param[in] kwdatReq DatReq to be sent to MAC
1346 static void rlcResegRetxPdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
1350 uint8_t hdr[RLC_MAX_HDRSZ];
1356 RlcL2MeasTb *l2MeasTb;
1357 RlclchInfo *lchInfo;
1363 /* TODO : This shoould be taken care in new Trasmissions */
1364 /* This lchInfo should be retrieved there */
1365 l2MeasTb = rlcUtlGetCurMeasTb(gCb, rbCb);
1366 if (l2MeasTb == NULLP)
1370 /* TODO : This lcid needs to be searched in case of normal Tx */
1371 /* In retx here, its fine as this will be higher priority */
1372 lchInfo = &l2MeasTb->lchInfo[l2MeasTb->numLchInfo];
1373 if (l2MeasTb->numLchInfo >= RLC_MAX_ACTV_DRB)
1377 l2MeasTb->numLchInfo++;
1378 lchInfo->lcId = rbCb->lch.lChId;
1379 lchInfo->numSdus = 0;
1382 while ((rlcDatReq->pduSz > 0) && (amDl->nxtRetx != NULLP)&&
1383 (rlcDatReq->pduInfo.numPdu < RLC_MAX_PDU))
1387 retx = amDl->nxtRetx;
1388 /* kw003.201 : Add header size to seg size to determine if the */
1389 /* the segment can be completed within the allocation */
1390 /* kw003.201 - Eliminate MAC Header Size based on bites needed */
1391 tmpSz = RLC_MIN((retx->segSz + retx->hdrSz), rlcDatReq->pduSz);
1392 pduSz = (retx->segSz + retx->hdrSz);
1393 /* 5GNR_RLC: length field in 5GNR MAC Hdr is 8/16 btis*/
1394 rlcDatReq->pduSz -= (tmpSz < 255) ? RLC_MAC_HDR_SZ2 : RLC_MAC_HDR_SZ3;
1396 /* kw003.201 - We should have at least one more than basic header */
1397 if (rlcDatReq->pduSz <= retx->hdrSz)
1401 rlcGetNxtRetx(gCb, &(amDl->nxtRetx));
1403 /* Send retx buf without segmentation */
1404 if (rlcDatReq->pduSz >= pduSz)
1408 DU_LOG("\nRLC: rlcResegRetxPdus: Send retx buf without segmentation "
1409 "UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1411 if (retx->yetToConst)
1413 /* Construct hdr with the available hdr values */
1414 rlcConstructAmHdr(&retx->amHdr, hdr, amDl->snLen, &idx);
1415 /* Add header to the pdu/segment */
1416 ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx + 1, retx->seg);
1417 retx->yetToConst = FALSE;
1420 /* kw003.201 - Check if poll bit needs to be set. Retx size does */
1421 /* not affect the poll bit so it is being passed as zero */
1422 pollBit = rlcAmmDlCheckAndSetPoll(gCb,rbCb, FALSE, 0);
1423 RLC_UPD_POLL_BIT(gCb, retx, pollBit);
1425 rlcDatReq->pduSz -= pduSz;
1426 AMDL.estHdrSz -= retx->hdrSz;
1429 if (rbCb->rlcId.rbType == CM_LTE_DRB)
1432 for (sduIdx = lchInfo->numSdus ;
1433 ((numSdus < retx->numSdu) && (sduIdx < RLC_L2MEAS_SDUIDX)) ;
1434 sduIdx++, numSdus++)
1436 lchInfo->sduInfo[sduIdx].arvlTime = retx->sduMap[numSdus].sdu->arrTime;
1437 lchInfo->sduInfo[sduIdx].isRetxPdu = TRUE; /* TODO : for later use */
1439 lchInfo->numSdus += numSdus;
1447 /* Segment this pdu / portion of pdu. Insert this segment into */
1448 /* retxLst and update offset */
1449 DU_LOG("\nRLC: rlcResegRetxPdus: Segment retx buf UEID:%d CELLID:%d",
1450 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1452 /* Eliminate fixed header size if the pdu is segmented for the */
1454 if(amDl->snLen == RLC_AM_CFG_12BIT_SN_LEN)
1456 if(retx->amHdr.si < RLC_SI_LAST_SEG)
1458 rlcDatReq->pduSz -= RLC_AM_SEG_12BIT_SN_WITHOUT_SO_HDRSZ;
1462 rlcDatReq->pduSz -= RLC_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1467 if(retx->amHdr.si < RLC_SI_LAST_SEG)
1469 rlcDatReq->pduSz -= RLC_AM_SEG_18BIT_SN_WITHOUT_SO_HDRSZ;
1473 rlcDatReq->pduSz -= RLC_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1476 if (rlcDatReq->pduSz <= 0)
1481 /* Allocate memory for tracking a new segment */
1482 RLC_ALLOC_WC(gCb,tNode, sizeof(RlcRetx));
1483 #if (ERRCLASS & ERRCLS_ADD_RES)
1486 DU_LOG("\nRLC: rlcResegRetxPdus: Memory allocation failed UEID:%d CELLID:%d",
1487 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1490 #endif /* ERRCLASS & ERRCLS_RES */
1492 /* initialize the list pointer to 0 instead of memset */
1493 tNode->lstEnt.next = 0;
1494 tNode->lstEnt.prev = 0;
1496 /* Segment header and data */
1497 RLC_AM_RMV_HDR(gCb, rbCb, retx);
1499 /* kw003.201 - Split the payload and update other fields */
1500 rlcSplitPdu(gCb,rbCb, retx, tNode, rlcDatReq->pduSz);
1505 sduIdx = lchInfo->numSdus;
1506 for (numSdus = 0, sduIdx = lchInfo->numSdus;
1507 ((numSdus < retx->numSdu) && (sduIdx < RLC_L2MEAS_SDUIDX));
1508 numSdus++, sduIdx++)
1510 lchInfo->sduInfo[sduIdx].arvlTime =
1511 retx->sduMap[numSdus].sdu->arrTime;
1512 lchInfo->sduInfo[sduIdx].isRetxPdu = TRUE;
1514 lchInfo->numSdus = sduIdx;
1515 if ((retx->amHdr.lsf == 0) && (lchInfo->numSdus > 0))
1520 /* Construct hdr with the available hdr values */
1521 rlcConstructAmHdr(&retx->amHdr, hdr, amDl->snLen, &idx);
1522 ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx + 1, retx->seg);
1524 retx->hdrSz = idx + 1;
1526 /* Poll bit need not be set for this seg, since its second */
1527 /* half remains in retxLst */
1528 RLC_UPD_POLL_BIT(gCb, retx, FALSE);
1529 retx->yetToConst = FALSE;
1530 rlcDatReq->pduSz = 0;
1533 rlcCpyMsg(gCb,retx->seg, &pdu);
1535 /* Update pduInfo */
1536 rlcDatReq->pduInfo.mBuf[rlcDatReq->pduInfo.numPdu] = pdu;
1537 rlcDatReq->pduInfo.numPdu++;
1538 /* kw005.201 ccpu00117318, updating the statistics */
1539 gCb->genSts.pdusRetx += 1;
1540 gRlcStats.amRlcStats.numRlcAmCellRetxPdu++;
1541 retx->soEnd = retx->amHdr.so + retx->segSz - 1;
1542 retx->pendingReTrans = FALSE;
1543 amDl->retxBo -= retx->segSz;
1546 DU_LOG("\nRLC: rlcResegRetxPdus: retxBo after resegmentation = %ld"
1547 "UEID:%d CELLID:%d", amDl->retxBo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1549 DU_LOG("\nRLC: rlcResegRetxPdus: retxBo after resegmentation = %d "
1550 "UEID:%d CELLID:%d", amDl->retxBo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1558 * @brief Private handler to assemble SDUs to form new data PDU(s)
1561 * Its a private function called by kwProcessSdus, to create the new data
1562 * PDUs from the SDU queue of RbCb.
1564 * - While pdusize is available, segment/concatenate SDUs or else if it
1565 * matches the pdu size form PDUs accordingly.
1566 * - RLC header and MAC header size are eliminated while forming the PDUs
1567 * - Call rlcAmmDlCheckAndSetPoll function to check and set the poll bit
1569 * - Concatenate data and header info and fill pduInfo
1571 * @param[in] rbCb RB control block
1572 * @param[in] kwdatReq DatReq to be sent to MAC
1577 static void rlcAssembleSdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
1579 Buffer *pdu = NULLP;
1580 MsgLen macGrntSz = rlcDatReq->pduSz;
1581 RlcAmDl *amDl = &AMDL;
1582 RlcSdu *sdu = amDl->nxtTx;
1584 bool nxtTxUpd = FALSE;
1585 KwuDiscSduInfo *discSduInfo = NULLP;
1586 RlcKwuSapCb* rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
1588 RlcContSduLst contSduLst; /*Contained sduLst */
1589 int32_t dataVol = amDl->bo;
1590 uint32_t *totMacGrant = &rlcDatReq->totMacGrant;
1591 RlcL2MeasDlIpTh *dlIpThPut = &rbCb->l2MeasIpThruput.dlIpTh;
1592 uint8_t *sduIdx = &dlIpThPut->lastSduIdx;
1594 bool isSduSegmented;
1597 RlclchInfo *dstLchInfo;
1598 uint32_t segSduCnt = 0;
1600 uint32_t numSdus = 0;
1601 uint32_t currSduIdx = 0;
1602 RlcL2MeasTb *l2MeasTb;
1604 /* Discard new changes starts */
1607 uint8_t numNewPdu = 0;
1608 RlcTx *txBuf = NULLP;
1609 /* Discard new changes ends */
1610 volatile uint32_t startTime = 0;
1612 uint32_t fixedHdrSz;
1614 RlcAmHdr *amHdr = NULLP;
1615 RlcDlPduInfo *pduInfo = NULLP;
1618 contSduLst.numSdus = 0;
1619 contSduLst.lcId = rbCb->lch.lChId;
1621 lchInfo.lcId = rbCb->lch.lChId;
1622 lchInfo.numSdus = 0;
1624 /* Discard new changes starts */
1625 /* Allocate memory for discSdu Info */
1626 RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region,
1627 rlckwuSap->pst.pool,
1629 sizeof(KwuDiscSduInfo));
1631 #if (ERRCLASS & ERRCLS_ADD_RES)
1632 if (discSduInfo == NULLP)
1634 DU_LOG("\nRLC: rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1635 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1638 #endif /* ERRCLASS & ERRCLS_RES */
1640 discSduInfo->numSduIds = 0;
1641 discSduInfo->rlcId = rbCb->rlcId;
1643 rlcUtlGetCurrTime(&curTime);
1644 amDl->sduQ.crnt = &sdu->lstEnt;
1645 /* Eliminate fixed header size */
1646 /*5GNR: value of RLC_AM_PDU_FIXED_HDRSZ will be 2 or 3 depending on SN Size*/
1647 if(amDl->snLen == RLC_AM_CFG_12BIT_SN_LEN)
1649 fixedHdrSz = RLC_AM_PDU_12BIT_SN_HDRSZ;
1653 fixedHdrSz = RLC_AM_PDU_18BIT_SN_HDRSZ;
1656 while ((macGrntSz > fixedHdrSz) && (sdu != NULLP) &&
1657 (rlcDatReq->pduInfo.numPdu < RLC_MAX_PDU) &&
1658 (numNewPdu < RLC_MAX_NEW_DL_PDU))
1661 isSduSegmented = sdu->mode.am.isSegmented;
1663 /* Discard new changes starts */
1664 if ((sdu->mode.am.isSegmented == FALSE) && (rbCb->discTmrInt > 0) && \
1665 (rbCb->rlcId.rbType == CM_LTE_DRB))
1667 //leftAmSdus[rbCb->qci]--;
1668 timeDiff = RLC_TIME_DIFF(curTime,sdu->arrTime);
1669 if (timeDiff > rbCb->discTmrInt)
1673 SStartTask(&startTime, PID_RLC_AMM_DISC_SDUS);
1675 RLC_UPD_L2_DL_DISC_SDU_STS(gCb,rbCb);
1676 /* TODO need to send disc cfm to pdcp */
1678 /* Update bo for boReport */
1679 amDl->bo -= sdu->sduSz;
1681 /* Get next sdu for assembly */
1682 nxtNode = sdu->lstEnt.next;
1684 /* store the info for sending it to PDCP */
1685 if(discSduInfo->numSduIds > 500)
1687 DU_LOG("\nRLC: rlcAssembleSdus: This is a big error, we shouldn't be here"
1688 "UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1692 discSduInfo->sduIds[discSduInfo->numSduIds] = sdu->mode.am.sduId;
1693 discSduInfo->numSduIds++;
1695 cmLListDelFrm(&amDl->sduQ, &sdu->lstEnt);
1697 rlcUtlAddSduToBeFreedQueue(gCb, sdu);
1698 rlcUtlRaiseDlCleanupEvent(gCb);
1700 /* We need to restore the crnt in the linked list which
1701 * would have become NULL in the DelFrm above */
1702 amDl->sduQ.crnt = nxtNode;
1705 sdu = (RlcSdu*)nxtNode->node;
1710 ODU_STOP_TASK(startTime, PID_RLC_AMM_DISC_SDUS);
1719 /** kw003.201 - Check for window stall when you are
1720 * creating a new PDU
1722 if (RLC_AM_IS_TRANS_WIN_STALLED(amDl))
1725 printf("\n Window stalled \n");
1726 gRlcStats.amRlcStats.numRlcAmCellWinStall++;
1731 hdrEstmt = fixedHdrSz;
1733 if (sdu->mode.am.isSegmented)
1735 /* Adding two byte for SO */
1738 /* Eliminate MAC header */
1739 /* ccpu00135743 : Fix for MAC Hdr size calculation */
1740 /*5GNR: value of mac hdr length field changed to 8/16bits */
1741 pduSz = RLC_MIN(macGrntSz, (sdu->sduSz + hdrEstmt));
1742 hdrEstmt += (pduSz < 255) ? RLC_MAC_HDR_SZ2 : RLC_MAC_HDR_SZ3;
1744 macGrntSz -= hdrEstmt;
1745 /* kw005.201 Check for PDU Size is large enough.
1746 * Fix for ccpu00118973
1753 /* Dont create new txBuf for segmented SDU */
1754 if (!sdu->mode.am.isSegmented)
1757 RLC_ALLOC_WC(gCb,txBuf, sizeof(RlcTx));
1759 cmLListInit(&txBuf->pduLst);
1761 #if (ERRCLASS & ERRCLS_ADD_RES)
1764 uint32_t avblMem = 0;
1765 SRegInfoShow(gCb->init.region, &avblMem);
1766 DU_LOG("\nRLC: rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1767 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1770 #endif /* ERRCLASS & ERRCLS_RES */
1772 rlcUtlStoreTxBuf(amDl->txBufLst, txBuf, amDl->txNext);
1776 txBuf = rlcUtlGetTxBuf(amDl->txBufLst, amDl->txNext);
1779 RLC_ALLOC_WC(gCb,pduInfo, sizeof(RlcDlPduInfo));
1780 #if (ERRCLASS & ERRCLS_ADD_RES)
1781 if (pduInfo == NULLP)
1783 uint32_t avblMem = 0;
1784 SRegInfoShow(gCb->init.region, &avblMem);
1785 DU_LOG("\nRLC: rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1786 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1789 #endif /* ERRCLASS & ERRCLS_RES */
1791 /*Initialize DL segment structure */
1792 pduInfo->lstEnt.next = NULLP;
1793 pduInfo->lstEnt.prev = NULLP;
1794 pduInfo->lstEnt.node = NULLP;
1796 pduInfo->pdu = NULLP;
1797 pduInfo->amHdr.dc = 0;
1798 pduInfo->amHdr.p = 0;
1799 pduInfo->amHdr.si = 0;
1800 pduInfo->amHdr.so = 0;
1802 pduInfo->amHdr.sn = amDl->txNext;
1804 if (macGrntSz >= sdu->sduSz)
1808 /* Update Framing Info */
1809 if (sdu->mode.am.isSegmented)
1811 /*5GNR RLC: SN should be same for all segment of a SDU*/
1812 pduInfo->amHdr.sn = sdu->mode.am.sn;
1813 pduInfo->amHdr.si = RLC_SI_LAST_SEG; /* binary 10 */
1814 pduInfo->amHdr.so = sdu->actSz - sdu->sduSz;
1815 sdu->mode.am.isSegmented = FALSE;
1818 gRlcStats.amRlcStats.numRlcAmCellSduTx++;
1819 //printf("\n 5GNRLOG: last segment of lcId %d SduId %u So %u macGrntSz %u sduActSz %u sdu->sduSz %u\n",
1820 // rbCb->lch.lChId, sdu->mode.am.sduId, pduInfo->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
1824 gRlcStats.amRlcStats.numRlcAmCellSduTx++;
1826 amHdr = &pduInfo->amHdr;
1827 /* Create PDU with hdr and data */
1828 rlcAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
1830 //printf("\n Segmentation not required case: numPdu %d pdu %p \n",rlcDatReq->pduInfo.numPdu, pdu);
1832 #ifdef LTE_L2_MEAS_RLC
1833 rlcUtlUpdSduSnMap(rbCb, sdu, rlcDatReq, TRUE);
1834 #endif /* LTE_L2_MEAS */
1836 /* kw005.201 ccpu00117318, updating the statistics */
1837 rlcUtlIncrementKwuStsSduTx(gCb->u.dlCb->rlcKwuDlSap + rbCb->k1wuSapId);
1839 if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb))
1843 *sduIdx = dlIpThPut->lastSduIdx;
1847 RLC_GETSDUIDX(*sduIdx);
1850 rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
1851 rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
1852 sdu->mode.am.sduId, newIdx);
1853 /* Update the arrival time for each SDU */
1855 if ( lchInfo.numSdus < RLC_L2MEAS_SDUIDX)
1857 lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime;
1862 sduMap.sduSz = sdu->sduSz;
1867 * Allocate buffer for next PDU
1868 * Remove the segmented portion from SDUQ
1869 * Calculate the hdr with LI for SDU */
1871 Buffer *remSeg = NULLP;
1873 //printf("\n SDU segmentation case: numPdu %d pdu %p \n", rlcDatReq->pduInfo.numPdu, pdu);
1875 if(RLC_MEAS_IS_DL_IP_MEAS_ON_FOR_RB(gCb,rbCb) ||
1876 RLC_MEAS_IS_DL_DELAY_MEAS_ON_FOR_RB(gCb,rbCb) ||
1877 RLC_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb) )
1879 /* If actual size of the sdu is equal to msgLen
1880 * then it is first segment of the SDU */
1881 if(sdu->actSz == sdu->sduSz)
1883 RLC_GETSDUIDX(*sduIdx);
1888 *sduIdx = dlIpThPut->lastSduIdx;
1890 rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
1891 rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
1892 sdu->mode.am.sduId, newIdx);
1893 if(RLC_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb))
1895 /* If actual size of the sdu is equal to msgLen
1896 * then it is first segment of the SDU */
1897 if(sdu->actSz == sdu->sduSz)
1905 /* Segment the SDU to the size of the PDU and update header Info */
1906 ODU_SEGMENT_MSG(sdu->mBuf, macGrntSz, &remSeg);
1910 /* Update SI and SN */
1911 if (sdu->mode.am.isSegmented)
1913 /*5GNR RLC: SN should be same for all segment of a SDU.
1914 * Sdu was already segmented and segmenting again*/
1915 pduInfo->amHdr.sn = sdu->mode.am.sn;
1916 pduInfo->amHdr.si = RLC_SI_MID_SEG; /* binary 11 */
1917 pduInfo->amHdr.so = sdu->actSz - sdu->sduSz;
1919 //printf("\n 5GNRLOG: mid segment of lcId %d SduId %u So %u macGrntSz %u sduActSz %u sdu->sduSz %u\n",
1920 // rbCb->lch.lChId, sdu->mode.am.sduId, txBuf->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
1924 /*5GNR RLC: This means it is the first*/
1925 pduInfo->amHdr.si = RLC_SI_FIRST_SEG; /* binary 01 */
1926 /*5GNR_RLC: Store SN so that in sub-seqent SDU segments will use this SN*/
1927 sdu->mode.am.sn = pduInfo->amHdr.sn;
1928 pduInfo->amHdr.so = 0;
1930 //printf("\n 5GNRLOG: First segment of lcId %d SduId %u So %u macGrntSz %u sduActSz %u sdu->sduSz %u\n",
1931 // rbCb->lch.lChId, sdu->mode.am.sduId, txBuf->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
1934 amHdr = &pduInfo->amHdr;
1935 /* Create PDU with hdr and data */
1936 rlcAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
1938 sdu->mode.am.isSegmented = TRUE;
1939 sdu->sduSz -= macGrntSz;
1940 sduMap.sduSz = macGrntSz;
1942 #ifdef LTE_L2_MEAS_RLC
1943 rlcUtlUpdSduSnMap(rbCb, sdu, rlcDatReq, FALSE);
1944 #endif /* LTE_L2_MEAS */
1950 /* Update bo for boReport */
1951 amDl->bo -= sduMap.sduSz;
1955 /* Update pduInfo */
1956 rlcDatReq->pduInfo.mBuf[rlcDatReq->pduInfo.numPdu] = pdu;
1957 rlcDatReq->pduInfo.numPdu++;
1959 /* kw005.201 ccpu00117318, updating the statistics */
1960 gCb->genSts.pdusSent++;
1961 gRlcStats.amRlcStats.numRlcAmCellSduBytesTx = gRlcStats.amRlcStats.numRlcAmCellSduBytesTx + sduMap.sduSz;
1962 /* Update the RLC Tx buffer with the new PDU info */
1963 RLC_MEM_CPY(&pduInfo->sduMap, &sduMap, sizeof(RlcSduMap));
1966 macGrntSz -= sduMap.sduSz;
1967 /* Get next sdu for assembly */
1968 RLC_LLIST_NEXT_SDU(amDl->sduQ, sdu);
1970 } /*End of pduSz loop */
1972 rlcDatReq->pduSz = macGrntSz;
1973 /* Updating nxtTx to sdu in the Q */
1978 if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) &&
1979 (rbCb->rlcId.rbType == CM_LTE_DRB))
1983 l2MeasTb = rlcUtlGetCurMeasTb(gCb, rbCb);
1984 rlcUtlUpdateBurstSdus(gCb, rbCb, &contSduLst, dataVol, *totMacGrant);
1985 if ((lchInfo.numSdus != 0) && (l2MeasTb != NULLP))
1987 for (lchIdx = 0; ((lchIdx < l2MeasTb->numLchInfo)
1988 && (lchIdx < RLC_MAX_ACTV_DRB )); lchIdx++)
1990 if (l2MeasTb->lchInfo[lchIdx].lcId == rbCb->lch.lChId)
1992 /* Lch Info already added in Retx procedure */
1996 if (lchIdx < RLC_MAX_ACTV_DRB)
1998 if (lchIdx == l2MeasTb->numLchInfo)
2000 l2MeasTb->lchInfo[lchIdx].lcId = rbCb->lch.lChId;
2001 l2MeasTb->lchInfo[lchIdx].numSdus = 0;
2002 l2MeasTb->numLchInfo++;
2004 dstLchInfo = &l2MeasTb->lchInfo[lchIdx];
2005 currSduIdx = l2MeasTb->lchInfo[lchIdx].numSdus;
2006 while ((numSdus < lchInfo.numSdus) && (currSduIdx < RLC_L2MEAS_SDUIDX))
2008 dstLchInfo->sduInfo[currSduIdx].arvlTime = lchInfo.sduInfo[numSdus].arvlTime;
2009 dstLchInfo->sduInfo[currSduIdx].isRetxPdu = FALSE;
2013 l2MeasTb->lchInfo[lchIdx].numSdus += numSdus;
2016 /* Fix Klock warning */
2017 if(l2MeasTb != NULLP)
2019 l2MeasTb->txSegSduCnt += segSduCnt;
2022 *totMacGrant -= (oldBo - amDl->bo);
2025 if(discSduInfo->numSduIds != 0)
2027 /* Sap control block */
2028 RlcUiKwuDiscSduCfm(&rlckwuSap->pst, rlckwuSap->suId, discSduInfo);
2032 RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, discSduInfo, sizeof(KwuDiscSduInfo));
2035 DU_LOG("\nRLC: rlcAssembleSdus: BO after assembly = %d UEID:%d CELLID:%d",
2036 amDl->bo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
2041 * @brief Private handler to check if the poll bit needs to be set for data PDU
2044 * Its a private function called by kwProcessSdus, to checks if the
2045 * polling bit needs to be set for any RLC data PDU and updates the
2047 * - For the new PDUs, if the counters exceed the configured
2048 * pduWoPoll/byteWoPoll values, return poll bit.
2049 * - For the PDUs/portion of PDUs, if the SDU list / retxBuf is
2050 * empty, return poll bit.
2051 * - Update the pollPdu, pollByte counters and Poll_SN; start staProhTmr
2053 * @param[in] rCb RLC instance control block
2054 * @param[in] rbCb RB control block
2055 * @param[in] newPdu Flag to indicate if its a new AMD PDU.
2056 * @param[in] bufSz Length of the PDU
2059 * -# 1 - To set the poll bit
2060 * -# 0 - Poll bit is not set
2063 static bool rlcAmmDlCheckAndSetPoll(RlcCb *gCb, RlcDlRbCb *rbCb, bool newPdu, MsgLen bufSz)
2065 bool pollBit = FALSE;
2066 RlcAmDl *amDl = &(rbCb->m.amDl);
2068 /* If it's a new PDU increment PDU without poll and bytes without poll
2069 and check if they cross the configured number of poll pdu and poll bytes*/
2073 /* Patch kw004.201 */
2074 amDl->byteWoPoll += bufSz;
2076 if (((amDl->pollPdu != -1) && (amDl->pduWoPoll >= amDl->pollPdu)) ||
2077 ((amDl->pollByte != -1) && (amDl->byteWoPoll >= amDl->pollByte)))
2083 /* Check if both tx/retx buffer are empty or if tx window is stalled */
2084 if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) ||
2085 RLC_AM_IS_TRANS_WIN_STALLED(amDl))
2092 amDl->pduWoPoll = 0;
2093 amDl->byteWoPoll = 0;
2095 amDl->pollSn = (amDl->txNext - 1) & amDl->snModMask;
2097 DU_LOG("\nRLC: rlcAmmDlCheckAndSetPoll: Poll SN = %d UEID:%d CELLID:%d",
2098 amDl->pollSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
2100 /* kw005.201: Fix for poll retransmission timer.
2101 * Timer is stopped if it is already running and
2102 * then starting the timer. Fixes crs
2103 * ccpu00117216 and ccpu00118284 .
2105 if( TRUE == rlcChkTmr(gCb,(PTR)rbCb,RLC_EVT_AMDL_POLL_RETX_TMR) )
2107 rlcStopTmr(gCb,(PTR)rbCb, RLC_EVT_AMDL_POLL_RETX_TMR);
2110 rlcStartTmr(gCb,(PTR)rbCb, RLC_EVT_AMDL_POLL_RETX_TMR);
2117 * @brief Private handler to create AMD PDU
2120 * This function constructs header and concatenate it with the data for
2121 * the PDU. It also updates the txBuf with the created PDU.
2123 * @param[in] gCB RLC instance control block
2124 * @param[in] rbCb Downlink RB control block
2125 * @param[in] amHdr AM header
2126 * @param[in] RlcDlPduInfo Pointer to PduInfo
2127 * @param[in] pdu PDU buffer
2132 static void rlcAmmCreatePdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcAmHdr *amHdr,
2133 RlcDlPduInfo *pduInfo, Buffer *pdu)
2135 uint8_t hdr[RLC_MAX_HDRSZ];
2139 RlcAmDl *amDl = &(rbCb->m.amDl);
2142 amHdr->sn = amDl->txNext;
2144 /*5GNR RLC: Increment txNext only if no segmentation of it is a last segment */
2145 if((!amHdr->si) || (amHdr->si == RLC_SI_LAST_SEG))
2147 //printf("\n 5GNRLOG: no segment/last seg SDU with lcId %d Sn %u txNext %u So %u\n",
2148 // rbCb->lch.lChId, amHdr->sn, amDl->txNext, amHdr->so);
2149 amDl->txNext = (amDl->txNext + 1) & amDl->snModMask;
2152 /* Update hdr Info */
2153 ODU_GET_MSG_LEN(pdu, &pduSz);
2155 /* passing newPDU = TRUE*/
2156 amHdr->p = rlcAmmDlCheckAndSetPoll(gCb,rbCb, TRUE, pduSz);
2158 /* Construct header with the available hdr Info, set isSegment to FALSE */
2159 rlcConstructAmHdr(amHdr, hdr, amDl->snLen, &idx);
2161 /* Concatenate hdr and data */
2162 ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx+1, pdu);
2164 txBuf = rlcUtlGetTxBuf(amDl->txBufLst, amHdr->sn);
2165 rlcCpyMsg(gCb,pdu,&(pduInfo->pdu));
2166 pduInfo->pduSz = pduSz;
2167 pduInfo->hdrSz = idx+1;
2169 /*Update estHdrSz. deduct current hdrSz */
2170 amDl->estHdrSz -= pduInfo->hdrSz;
2171 /* Reestimate estHdrSz for mid and last seg */
2174 amDl->estHdrSz += ((amHdr->si == RLC_SI_MID_SEG)? pduInfo->hdrSz : (pduInfo->hdrSz + 2));
2177 cmLListAdd2Tail(&txBuf->pduLst, &pduInfo->lstEnt);
2178 pduInfo->lstEnt.node = (PTR)pduInfo;
2180 gCb->genSts.bytesSent += pduSz;
2186 * @brief Private handler to remove the retx PDU from the rbCb
2189 * This function releases a retx PDU stored on DL portion of rbCb.
2190 * It also updates the BO if wtForAck flag is not set which implies
2191 * that it is not sent out yet.
2193 * @param[in] gCb RLC instance control block
2194 * @param[in] retx retransmit PDU to be removed
2195 * @param[in] rbCb Radio Bearer Control Block
2200 static Void rlcRemRetxPdu(RlcCb *gCb,RlcDlRbCb *rbCb,RlcRetx *retx)
2202 cmLListDelFrm(&AMDL.retxLst, &retx->lstEnt);
2204 if( AMDL.retxLst.count == 0)
2206 AMDL.nxtRetx = NULLP;
2209 if(retx->pendingReTrans == TRUE)
2211 AMDL.retxBo -= retx->segSz;
2212 AMDL.estHdrSz -= retx->hdrSz;
2215 rlcUtlAddReTxPduToBeFreedQueue(gCb, retx);
2216 rlcUtlRaiseDlCleanupEvent(gCb);
2222 * @brief Private handler to mark a retx PDU for further retransmission
2225 * This function sets a retx PDU that has not been ACKed in the
2226 * received Status PDU for futher retransmission. If the retransmission
2227 * limit is reached, it releases the retx PDU and informs the higher
2228 * layers about the same.
2230 * @param[in] gCb RLC instance control block
2231 * @param[in] retx retransmit PDU to be removed
2232 * @param[in] rbCb Radio Bearer Control Block
2237 static Void rlcAmmDlMarkPduForReTx(RlcCb *gCb,RlcDlRbCb *rbCb,RlcRetx *retx)
2239 if (AMDL.maxReTxReached == TRUE)
2244 if(retx->pendingReTrans == FALSE)
2246 retx->pendingReTrans = TRUE;
2249 AMDL.retxBo += retx->segSz;
2250 AMDL.estHdrSz += retx->hdrSz;
2252 if (retx->retxCnt > AMDL.maxRetx)
2254 /* RLC_DL_MAX_RETX fix */
2255 /* Marking the RB stalled for DL scheduling. This is to avoid unnecessary */
2256 /* preparation of RLC PDUs and adding the same to Tx Buffer */
2257 /* This condition is to avoid sending StaIndication more than once */
2258 if (TRUE != rbCb->m.amDl.maxReTxReached)
2260 rbCb->m.amDl.maxReTxReached = TRUE;
2261 rbCb->m.amDl.bo = 0;
2262 rbCb->m.amDl.cntrlBo = 0;
2263 rbCb->m.amDl.retxBo = 0;
2264 /* Sending BO update to SCH */
2265 rlcUtlSendDedLcBoStatus(gCb, rbCb, 0,0,0,0);
2266 rlcAmmSndStaInd(gCb, rbCb, retx);
2267 gRlcStats.amRlcStats.numDLMaxRetx++;
2270 rlcRemRetxPdu(gCb,rbCb, retx);
2276 if (AMDL.nxtRetx == NULLP)
2278 AMDL.nxtRetx = retx;
2281 gRlcStats.amRlcStats.numDLRetransPdus++;
2289 * @brief Private handler to check if SDU is completely deliverd and
2290 * send higher layers data confirmation
2293 * This function sends higher layers data confirmation for SDUs which
2294 * have been successfully delivered to the peer RLC entity.
2296 * @param[in] gCb RLC instance control block
2297 * @param[in] rbCb Radio Bearer Control Block
2298 * @param[in] sduLst List of SDUs that were part of the PDU
2299 * @param[in] numSdu Number of SDUs in the list
2304 static Void rlcAmmDlCheckIsSDUDelivered
2309 KwuDatCfmInfo **datCfm
2316 sdu->mode.am.rcvdSz += sduMap->sduSz;
2318 /* send a dat cfm if all the bytes of the sdu have been received */
2319 if (sdu->mode.am.rcvdSz == sdu->actSz)
2321 /* Send DatCfm for this sdu */
2322 if((*datCfm)->numSduIds < KWU_MAX_DAT_CFM)
2324 (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2328 /* This is an error that should never happen, we should resize
2329 * the #define to a larger value or check why we need to
2330 * send so many confirms in one go
2331 * Confrims to PDCP are being dropped in this case
2333 RlcKwuSapCb *rlckwuSap;
2334 rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
2335 RlcUiKwuDatCfm(&rlckwuSap->pst, rlckwuSap->suId, *datCfm);
2337 RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, *datCfm, sizeof(KwuDatCfmInfo));
2339 #if (ERRCLASS & ERRCLS_ADD_RES)
2340 if (*datCfm == NULLP)
2342 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
2343 "Memory allocation failed UEID:%d CELLID:%d",
2345 rbCb->rlcId.cellId);
2348 #endif /* ERRCLASS & ERRCLS_RES */
2350 (*datCfm)->numSduIds = 0;
2351 (*datCfm)->rlcId = rbCb->rlcId;
2352 /* ccpu00135618: say total 1026 sduIds to copy the 1025 sduId after
2353 * new allocation of datCfm */
2354 (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2357 /* Remove SDU from the sduQ */
2358 cmLListDelFrm(&AMDL.sduQ, &sdu->lstEnt);
2359 rlcUtlAddSduToBeFreedQueue(gCb, sdu);
2360 rlcUtlRaiseDlCleanupEvent(gCb);
2367 * @brief Private handler to mark a PDU successful.
2370 * This function is called when we receive a STATUS pdu that marks
2371 * a PDU as successful. It releases the PDU from RLC entity and
2372 * informs PDCP of successful SDUs delivered as a result of this PDU.
2374 * @param[in] gCb RLC instance control block
2375 * @param[in] rbCb Radio Bearer Control Block
2376 * @param[in] sn SN that is successfully delivered to the peer
2381 static Void rlcAmmDlProcessSuccessfulTxPdu
2386 KwuDatCfmInfo **datCfm
2391 RlcTx *txBuf = rlcUtlGetTxBuf(AMDL.txBufLst, sn);
2397 pduNode = txBuf->pduLst.first;
2400 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(pduNode->node);
2401 rlcAmmDlCheckIsSDUDelivered(gCb,
2405 pduNode = pduNode->next;
2408 rlcUtlAddTxPduToBeFreedQueue(gCb, txBuf);
2409 rlcUtlRaiseDlCleanupEvent(gCb);
2410 /* so that it is not processed again */
2411 rlcUtlRemovTxBuf(AMDL.txBufLst, txBuf, gCb);
2417 * @brief Handler to send Status Indication to PDCP
2420 * This function is used to send status indication to PDCP when the
2421 * maximum retransmission threshold value is reached for a PDU.
2423 * @param[in] gCb RLC instance control block
2424 * @param[in] rbCb RB control block
2425 * @param[in] retx The PDU/segment that failed max re-transmissions
2430 static Void rlcAmmSndStaInd
2437 KwuStaIndInfo *staInd;
2438 RlcKwuSapCb *rlckwuSap;
2440 /* Sap control block */
2441 rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
2443 /* Allocate memory for staInd Info */
2444 RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, staInd, sizeof(KwuStaIndInfo));
2446 #if (ERRCLASS & ERRCLS_ADD_RES)
2447 if (staInd == NULLP)
2449 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
2450 "Memory allocation failed UEID:%d CELLID:%d",
2452 rbCb->rlcId.cellId);
2455 #endif /* ERRCLASS & ERRCLS_RES */
2457 /* Fill staInd Info */
2458 RLC_MEM_CPY(&staInd->rlcId, &rbCb->rlcId, sizeof(CmLteRlcId));
2461 staInd->sduId[0] = retx->sduMap.sdu->mode.am.sduId;
2465 RlcUiKwuStaInd(&rlckwuSap->pst, rlckwuSap->suId, staInd);
2466 #endif /* KW_PDCP */
2472 * @brief Handler to get the next node to be retransmitted from retxLst
2475 * This function is used to get the next node to be retransmitted
2478 * @param[in] gCb RLC instance control block
2479 * @param[in] retx The PDU/segment after which to find a node to be
2485 static void rlcGetNxtRetx(RlcCb *gCb, RlcRetx **retx)
2491 tNode = &((*retx)->lstEnt);
2492 tNode = tNode->next;
2496 *retx = (RlcRetx *)tNode->node;
2503 }while((*retx)->pendingReTrans == FALSE);
2509 * @brief Handler to process the re-establishment request received from UIM
2511 * @param[in] gCb RLC instance control block
2512 * @param[in] rlcId Identity of the RB in the UE/Cell for which
2513 * re-establishment is to be done
2514 * @param[in] rbCb Downlink RB control block (rbCb is freed in this
2520 Void rlcAmmDlReEstablish
2527 /* create a new AM DL RB, reset it and replace in the UeCb*/
2532 RLC_ALLOC(gCb, resetRb, sizeof(RlcDlRbCb));
2534 /* ccpu00135170 Removing KLOCK warning */
2535 if(resetRb == NULLP)
2540 RLC_MEM_CPY(resetRb, rbCb, sizeof(RlcDlRbCb));
2541 RLC_MEM_SET(&resetRb->m.amDl, 0 , sizeof(RlcAmDl));
2543 /* AGHOSH changes start */
2544 /* restore the old AM values */
2545 newAmDl = &resetRb->m.amDl;
2546 oldAmDl = &rbCb->m.amDl;
2548 newAmDl->pollPdu = oldAmDl->pollPdu;
2549 newAmDl->pollByte = oldAmDl->pollByte;
2550 newAmDl->maxRetx = oldAmDl->maxRetx;
2551 newAmDl->snLen = oldAmDl->snLen;
2552 newAmDl->snModMask = oldAmDl->snModMask;
2553 newAmDl->pollRetxTmrInt = oldAmDl->pollRetxTmrInt;
2554 rbCb->boUnRprtdCnt = (uint32_t)0;
2555 rbCb->lastRprtdBoToMac = (uint32_t)0;
2556 cmInitTimers(&(resetRb->m.amDl.pollRetxTmr), 1);
2557 /* AGHOSH changes end */
2559 if (ROK != rlcDbmFetchDlUeCb(gCb,rlcId.ueId, rlcId.cellId, &ueCb))
2561 RLOG_ARG2(L_ERROR,DBG_CELLID, rlcId.cellId,
2562 "UeId [%d]: UeCb not found RBID;%d",
2568 if(rlcId.rbType == CM_LTE_SRB)
2570 ueCb->srbCb[rlcId.rbId] = resetRb;
2574 ueCb->drbCb[rlcId.rbId] = resetRb;
2576 /* update into the logical channel array also */
2577 ueCb->lCh[rbCb->lch.lChId - 1].dlRbCb = resetRb;
2579 if((resetRb->rlcId.rbType == CM_LTE_SRB)
2580 &&(resetRb->rlcId.rbId == 1))
2582 /* To stop the traffic on SRB2 and other DRBs*/
2583 rlcDlUtlSetReestInProgressForAllRBs(gCb, ueCb);
2587 rlcDlUtlSetReestInProgressForRB(gCb, resetRb);
2590 /* allocate the TX array again */
2594 resetRb->m.amDl.txBufLst,
2595 (RLC_TX_BUF_BIN_SIZE * sizeof(CmLListCp)));
2596 for(hashIndex = 0; hashIndex < RLC_TX_BUF_BIN_SIZE; hashIndex++)
2598 cmLListInit(&(resetRb->m.amDl.txBufLst[hashIndex]));
2601 /* send the old rb of deletion */
2602 rlcAmmFreeDlRbCb(gCb,rbCb);
2605 /* TODO: for now we are re-settting the re-establishment flag here
2606 this needs to be fixed
2607 There should be a proper intreface to resume the RBs */
2608 if(rlcId.rbType == CM_LTE_SRB)
2610 rlcDlUtlResetReestInProgress(ueCb->srbCb[rlcId.rbId]);
2614 rlcDlUtlResetReestInProgress(ueCb->drbCb[rlcId.rbId]);
2621 * @brief Handler to discard a SDU.
2624 * This function is used to discard a SDU after receiving
2625 * the Discard Request from UIM. The SDU is discarded if its
2626 * available and is not mapped to any PDU yet.
2628 * @param[in] gCb RLC instance control block
2629 * @param[in] rbCb RB control block
2630 * @param[in] sduId Sdu ID of the SDU to be discarded
2633 * -# ROK In case of successful discard
2634 * -# RFAILED In case the SDU is not found or already mapped
2636 S16 rlcAmmDiscSdu(RlcCb *gCb,RlcDlRbCb *rbCb,uint32_t sduId )
2642 * @brief Handler for Poll retransmit timer expiry
2645 * This function is used to handle events upon expiry of Poll
2648 * @param[in] gCb RLC instance control block
2649 * @param[in] rbCb Downlink RB control block
2653 Void rlcAmmPollRetxTmrExp(RlcCb *gCb,RlcDlRbCb *rbCb)
2656 RlcAmDl *amDl = &(rbCb->m.amDl);
2660 /* kw003.201 - Correcting the logic for determmining whether to do */
2661 /* any transmission of PDU. As per the spec section */
2662 /* 5.2.2.3, if there is any to transmit or retransmit, */
2663 /* do nothing. Else, pick up the VT(S) -1 for retx */
2664 /* We have nothing to transmit if window is stalled or */
2665 /* there are no SDUs to be transmitted or if there are */
2666 /* PDUs to be retransmitted. */
2667 if(CM_LTE_SRB == rbCb->rlcId.rbType)
2669 gRlcStats.amRlcStats.numDLPollTimerExpiresSrb++;
2673 gRlcStats.amRlcStats.numDLPollTimerExpiresDrb++;
2676 if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) ||
2677 RLC_AM_IS_TRANS_WIN_STALLED(amDl))
2679 sn = (amDl->txNext - 1) & amDl->snModMask;
2680 txBuf = rlcUtlGetTxBuf(amDl->txBufLst, sn);
2684 rlcAmmDlMoveFrmTxtoRetxBuffer(gCb,amDl, &retx, sn);
2686 if (AMDL.nxtRetx == NULLP)
2688 AMDL.nxtRetx = retx;
2691 rlcAmmSendDedLcBoStatus(gCb, rbCb, &AMDL);
2694 /* Get the last node in retxLst */
2695 RLC_LLIST_LAST_RETX(amDl->retxLst, retx);
2697 /* Unset wtForAck flag for the NACK PDUs */
2700 rlcAmmDlMarkPduForReTx(gCb, rbCb, retx);
2701 rlcAmmSendDedLcBoStatus(gCb, rbCb, &AMDL);
2709 * @brief Handler to update Acks for the remaining PDUs after the last accessed
2713 * This function is used to handle ACKs for the PDUs remaining after the
2714 * last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and
2715 * sends DatCfm to PDCP for the same.
2717 * @param[in] gCb RLC instance control block
2718 * @param[in] rbCb Downlink Radio Bearer control block
2719 * @param[in] mAckSn The ACK SN after doing the base modulus
2720 * @param[in] rextNode Next node in the re-transmission buffer
2726 static Void rlcAmmDlUpdateTxAndReTxBufForAckSn
2732 KwuDatCfmInfo **datCfm
2740 /* Remove pdus/segs from retxLst */
2743 retx = (RlcRetx *)(retxNode->node);
2744 retxNode = retxNode->next;
2745 MODAMT(retx->amHdr.sn, mSn, AMDL.txNextAck,AMDL.snModMask);
2748 rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
2752 /* For the remaining; pdus not acknowldeged by the NACK_SN but being
2753 acknowledged by the ACK_SN*/
2754 /* start from the starting of the transmission window and remove till just
2756 mSn = 0; /* same as MODAMT(AMDL.txNextAck, mSn, AMDL.txNextAck);*/
2757 sn = AMDL.txNextAck;
2760 txBuf = rlcUtlGetTxBuf(AMDL.txBufLst, sn);
2763 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
2764 "rlcAmmDlUpdateTxAndReTxBufForAckSn: ACK for PDU "
2765 "with sn = %ld UEID:%ld CELLID:%ld",
2768 rbCb->rlcId.cellId);
2770 rlcAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
2773 sn = (sn + 1) & AMDL.snModMask;
2774 MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
2781 * @brief Handler to update Acks for the remaining PDUs after the last accessed
2785 * This function is used to handle ACKs for the PDUs remaining after the
2786 * last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and
2787 * sends DatCfm to PDCP for the same.
2789 * @param[in] gCb RLC instance control block
2790 * @param[in] rbCb Downlink Radio Bearer control block
2791 * @param[in] mAckSn The ACK SN after doing the base modulus
2792 * @param[in] rextNode Next node in the re-transmission buffer
2797 static Void rlcAmmDlUpdTxAndReTxBufForLessThanNackSn
2804 KwuDatCfmInfo **datCfm
2813 retx = (RlcRetx *)((*retxNode)->node);
2814 MODAMT(retx->amHdr.sn, mSn, AMDL.txNextAck,AMDL.snModMask);
2817 (*retxNode) = (*retxNode)->next;
2818 rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
2826 /* Remove all pdus with SN < NACK_SN from the transmission buffer */
2827 MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
2828 while (mSn < mNackSn)
2830 /* this if check seems redundant,why should mSn ever be mTxSn
2831 (which actually is VT(A) */
2832 txBuf = rlcUtlGetTxBuf(AMDL.txBufLst, sn);
2833 if ((txBuf != NULLP))
2835 RLOG_ARG3(L_DEBUG,DBG_RBID, rbCb->rlcId.rbId,
2836 "rlcHndlStaRsp: Handle ACK (sn = %d) UEID:%d CELLID:%d",
2839 rbCb->rlcId.cellId);
2841 /* Remove pdus from txBuf */
2842 rlcAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
2845 sn = (sn + 1) & AMDL.snModMask;
2846 MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
2854 * @brief Handler to form construct AM header
2857 * This function is used to construct am header with the available header
2860 * @param[in] gCb RLC instance control block
2861 * @param[in] amHdr AM Header
2862 * @param[in] isSeg Check for Segmentation of PDU
2863 * @param[in] hdr Header field
2864 * @param[in] idx Index
2869 static void rlcConstructAmHdr(RlcAmHdr *amHdr, uint8_t *hdr, uint8_t snLen, uint16_t *idx)
2872 hdr[0] = RLC_DATA_BITMASK;
2874 hdr[0] = hdr[0] | (amHdr->p << 6);
2875 hdr[0] = hdr[0] | ((amHdr->si & 0x3) << 4);
2876 if(snLen == RLC_AM_CFG_12BIT_SN_LEN)
2878 hdr[0] = hdr[0] | (uint8_t)((amHdr->sn & 0xF00) >> 8);
2879 hdr[1] = (uint8_t)(amHdr->sn & 0x0FF);
2884 hdr[0] = hdr[0] | (uint8_t)((amHdr->sn & 0x30000) >> 16);
2885 hdr[1] = (uint8_t)((amHdr->sn & 0xFF00) >> 8);
2887 hdr[2] = (uint8_t)(amHdr->sn & 0xFF);
2891 if ((amHdr->si == RLC_SI_MID_SEG) || (amHdr->si == RLC_SI_LAST_SEG))
2894 hdr[(*idx)] = (uint8_t)((amHdr->so & 0xFF00)>> 8);
2896 hdr[(*idx)] = (uint8_t)(amHdr->so & 0xFF);
2903 * @brief This function adds a retx PDU to list of retx PDUs
2906 * kw003.201 - Poll expiry may cause an SN to be added to retx
2907 * out of sequence and hence all additions to retx
2908 * must validate that they are added in sequence
2910 * @param[in] amDl AM Downlink Control Block
2911 * @param[in] retx Retransmit PDU
2916 static Void rlcAmmAddPduToRetxLst(RlcAmDl *amDl,RlcRetx *retx)
2923 node = amDl->retxLst.last;
2924 MODAMT(retx->amHdr.sn, retxMSn, amDl->txNextAck,amDl->snModMask);
2925 while(node != NULLP)
2927 tRetx = (RlcRetx *)(node->node);
2928 MODAMT(tRetx->amHdr.sn, tMSn, amDl->txNextAck,amDl->snModMask);
2940 amDl->retxLst.crnt = node;
2941 cmLListInsAfterCrnt(&amDl->retxLst, &retx->lstEnt);
2942 retx->lstEnt.node = (PTR)retx;
2946 amDl->retxLst.crnt = amDl->retxLst.first;
2947 cmLListInsCrnt(&amDl->retxLst, &retx->lstEnt);
2948 retx->lstEnt.node = (PTR)retx;
2951 if (amDl->nxtRetx == NULLP)
2953 amDl->nxtRetx = retx;
2960 * @brief Handler to Move the PDU from txBuf to re-transmission buffer
2963 * This function is used to move the PDU from the txBuf to re-transmit buffer
2965 * @param[in] gCb RLC instance control block
2966 * @param[in] amDl AM Downlink Control Block
2967 * @param[in] retx node in the reTx buffer to be moved to, allocated by
2969 * @param[in] sn SN in the tx buffer which needs to be moved
2975 static Void rlcAmmDlMoveFrmTxtoRetxBuffer
2983 RlcTx* txBuf = rlcUtlGetTxBuf(amDl->txBufLst, sn);
2989 while(txBuf->pduLst.first)
2991 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(txBuf->pduLst.first->node);
2992 RLC_ALLOC_WC(gCb,*retx, sizeof(RlcRetx));
2994 #if (ERRCLASS & ERRCLS_ADD_RES)
2997 RLOG0(L_FATAL, "Memory allocation failed");
3000 #endif /* ERRCLASS & ERRCLS_RES */
3002 /* Move Sdu byte segment from TX buf to retx buf*/
3003 rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb,
3008 /* Delete node from the txBuf Pdu lst */
3009 cmLListDelFrm(&txBuf->pduLst, txBuf->pduLst.first);
3010 RLC_FREE_WC(gCb, pduInfo, sizeof(RlcDlPduInfo));
3012 /* Remove PDU from txBuf */
3013 rlcUtlDelTxBuf(amDl->txBufLst, txBuf,gCb);
3022 * function to free/release the Acknowledged mode RBCB buffers
3025 * This primitive Frees the Acknowledged Mode RbCb transmission Buffer,
3026 * retransmission Buffer and reciption Buffers
3028 * @param [in] gCb - RLC instance control block
3029 * @param [in] rbCb - Downlink RB Control Block
3033 Void rlcAmmFreeDlRbCb(RlcCb *gCb,RlcDlRbCb *rbCb)
3035 /* stop the re-transmission timer */
3036 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,RLC_EVT_AMDL_POLL_RETX_TMR))
3038 rlcStopTmr(gCb,(PTR)rbCb, RLC_EVT_AMDL_POLL_RETX_TMR);
3041 /* store the entire Rb pointer */
3042 rbCb->rlsLnk.node = (PTR)rbCb;
3043 cmLListAdd2Tail(&gCb->u.dlCb->toBeFreed.rbLst, &rbCb->rlsLnk);
3046 cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.amDl.sduQ));
3048 rlcUtlRaiseDlCleanupEvent(gCb);
3054 * @brief Handler to create STATUS Pdu
3057 * This function is used to create status pdu
3059 * @param[in] gCb RLC instance control block
3060 * @param[in] rbCb Downlink RB control block
3061 * @param[in] rlcDatReq The data to be passed to MAC
3066 static void rlcAmmCreateStatusPdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
3068 RlcSn sn; /* sequence number */
3069 RlcSn ack_sn; /* Ack sequence number */
3070 Buffer *mBuf; /* control pdu buffer */
3071 MsgLen cntrlPduSz; /* control pdu size */
3072 uint8_t cntrlPdu[RLC_MAX_CNTRL_FIELDS]; /* control pdu to be added to mBuf */
3073 RlcUdxDlStaPdu *pStaPdu;
3074 uint16_t bytesToEncode = 0; /* bytes required to encode the STATUS PDU */
3075 uint16_t encIdx = 0;
3076 uint16_t prevEncIdx = 0;
3077 RlcNackInfo *rlcNackInfo;
3080 pStaPdu = AMDL.pStaPdu;
3089 /* ACK SN Field will be set in the end based on available Grant */
3091 encIdx = bytesToEncode = 3; /* Num Octets before NACK SN info encoding*/
3093 ack_sn = pStaPdu->ackSn;
3095 if (rbCb->m.amDl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
3098 /* If alteast one NACK SN Info then set the E1 field */
3099 if (pStaPdu->nackCount)
3109 for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3111 sn = pStaPdu->nackInfo[nkCnt].sn;
3113 rlcNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3115 bytesToEncode += 2; /* 2 Octets for NACK SN */
3117 /* Check if E2 : isSegment is set */
3118 if (rlcNackInfo->isSegment)
3120 bytesToEncode += 4; /* 4 Octets: SOstart, SOend */
3123 /* Check if E3 : nackRange is set */
3124 if (rlcNackInfo->nackRange)
3126 bytesToEncode += 1; /* 1 Octet: NACK range */
3129 /* Check if this NACK info can be accomodated in the Grant */
3130 if( rlcDatReq->pduSz >= bytesToEncode)
3132 /* If there is a NACK SN before this then set its
3136 /* NACKSN E1 E2 E3 R */
3137 cntrlPdu[prevEncIdx + 1] |= 0x8;
3140 /* 12 BIT Nack SN encode */
3141 cntrlPdu[encIdx] = (sn & 0xFF0) >> 4;
3144 cntrlPdu[encIdx + 1] = (sn & 0xF) << 4;
3146 if (rlcNackInfo->isSegment)
3149 cntrlPdu[encIdx + 1] |= 0x4;
3152 /* Add soStart and soEnd */
3154 cntrlPdu[encIdx + 2] = (rlcNackInfo->soStart) >> 8;
3155 cntrlPdu[encIdx + 3] = rlcNackInfo->soStart & 0xFF;
3158 cntrlPdu[encIdx + 4] = (rlcNackInfo->soEnd) >> 8;
3159 cntrlPdu[encIdx + 5] = rlcNackInfo->soEnd & 0xFF;
3162 if (rlcNackInfo->nackRange)
3165 cntrlPdu[encIdx + 1] |= 0x2;
3166 if(rlcNackInfo->isSegment)
3168 cntrlPdu[encIdx + 6] = rlcNackInfo->nackRange;
3172 cntrlPdu[encIdx + 2] = rlcNackInfo->nackRange;
3176 gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3178 /* Set ACK SN now */
3181 ack_sn = rlcNackInfo->sn;
3183 /* Not even one nack can be accomodated */
3192 prevEncIdx = encIdx;
3193 encIdx = bytesToEncode;
3195 }/* Loop is done for the NackCount */
3200 DU_LOG("\nRLC: rlcAssembleCntrlInfo: ACK PDU's SN = %d"\
3201 "UEID:%d CELLID:%d", ack_sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
3203 cntrlPdu[0] |= (ack_sn & 0xF00)>> 8;
3204 cntrlPdu[1] = (uint8_t)ack_sn;
3208 else if (rbCb->m.amDl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
3210 /* If alteast one NACK SN Info then set the E1 field */
3211 if (pStaPdu->nackCount)
3221 for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3223 sn = pStaPdu->nackInfo[nkCnt].sn;
3225 rlcNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3227 bytesToEncode += 3; /* 3 Octets for NACK SN */
3229 /* Check if E2 : isSegment is set */
3230 if (rlcNackInfo->isSegment)
3232 bytesToEncode += 4; /* 4 Octets: SOstart, SOend */
3235 /* Check if E3 : nackRange is set */
3236 if (rlcNackInfo->nackRange)
3238 bytesToEncode += 1; /* 1 Octet: NACK range */
3241 /* Check if this NACK info can be accomodated in the Grant */
3242 if( rlcDatReq->pduSz >= bytesToEncode)
3244 /* If there is a NACK SN before this then set its
3248 /* NACKSN E1 E2 E3 R R R */
3249 cntrlPdu[prevEncIdx + 2] |= 0x20;
3252 /* 18 BIT Nack SN encode */
3253 cntrlPdu[encIdx] = (uint8_t)((sn & 0x3FC00) >> 10);
3256 cntrlPdu[encIdx + 1] = (uint8_t)((sn & 0x3FC) >> 2);
3259 cntrlPdu[encIdx + 2] = (uint8_t)((sn & 0x3)<< 6);
3261 if (rlcNackInfo->isSegment)
3263 /* NACKSN E1 E2 E3 R R R */
3265 cntrlPdu[encIdx + 2] |= 0x10;
3268 /* Add soStart and soEnd */
3270 cntrlPdu[encIdx + 3] = (rlcNackInfo->soStart) >> 8;
3271 cntrlPdu[encIdx + 4] = (uint8_t)rlcNackInfo->soStart;
3274 cntrlPdu[encIdx + 5] = (rlcNackInfo->soEnd) >> 8;
3275 cntrlPdu[encIdx + 6] = (uint8_t)(rlcNackInfo->soEnd);
3278 if (rlcNackInfo->nackRange)
3280 /* NACKSN E1 E2 E3 R R R */
3282 cntrlPdu[encIdx + 2] |= 0x08;
3284 if (rlcNackInfo->isSegment)
3286 cntrlPdu[encIdx + 7] = rlcNackInfo->nackRange;
3290 cntrlPdu[encIdx + 3] = rlcNackInfo->nackRange;
3294 gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3296 /* Set ACK SN now */
3299 ack_sn = rlcNackInfo->sn;
3301 /* Not even one nack can be accomodated */
3304 cntrlPdu[2] &= 0xFD;
3310 prevEncIdx = encIdx;
3311 encIdx = bytesToEncode;
3313 }/* Loop is done for the NackCount */
3318 DU_LOG("\nRLC: rlcAssembleCntrlInfo: ACK PDU's SN = %d"
3319 "UEID:%d CELLID:%d", ack_sn, rbCb->rlcId.ueId,rbCb->rlcId.cellId);
3321 cntrlPdu[0] |= (ack_sn & 0x3C000) >> 14;
3322 cntrlPdu[1] = (ack_sn & 0x3FC0) >> 6;
3323 cntrlPdu[2] |= (ack_sn & 0x3F)<< 2;
3330 DU_LOG("\nRLC: rlcAssembleCntrlInfo:Conf SN LEN %d is INVALID !!!! \
3331 UEID:%d CELLID:%d", rbCb->m.amDl.snLen, rbCb->rlcId.ueId,
3332 rbCb->rlcId.cellId);
3337 SGetMsg(RLC_GET_MEM_REGION(gCb), RLC_GET_MEM_POOL(gCb),&mBuf);
3339 mBuf = (Buffer *)rlcAmmStaPduList[rlcAmmStaPduListCnt++];
3341 if(rlcAmmStaPduListCnt > 511)
3342 rlcAmmStaPduListCnt = 0;
3345 cntrlPduSz = encIdx;
3346 ODU_ADD_POST_MSG_MULT(cntrlPdu, cntrlPduSz, mBuf);
3348 rlcDatReq->pduSz -= cntrlPduSz;
3349 /* Add mBuf to AMDL.mBuf */
3355 #ifdef RLC_STA_PROC_IN_MAC/* RLC Status PDU Processing */
3357 S16 rlcProcDlStatusPdu(Pst *udxPst,SuId suId,
3358 CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu);
3360 static Void rgAmmExtractElmnt(RlcCb *gCb,Buffer *pdu,RlcExtHdr *hdrInfo)
3363 uint8_t pLen = hdrInfo->pLen;
3364 uint8_t len = (uint8_t)hdrInfo->len;
3369 /* uint8_t rLen1 = 0; */
3376 SRemPreMsg(&hdr, pdu);
3382 val = tHdr >> (RLC_BYTE_LEN - (len));
3386 else /*if (len > 8) */
3390 val = val >> (RLC_BYTE_LEN - fLen);
3391 val = val << (len - fLen);
3393 SRemPreMsg(&hdr, pdu);
3397 hdr = hdr >> (RLC_BYTE_LEN - rLen);
3400 pLen = (RLC_BYTE_LEN - rLen);
3404 rLen = rLen - RLC_BYTE_LEN;
3406 tVal = tVal << rLen;
3409 SRemPreMsg(&hdr, pdu);
3411 hdr = hdr >> (RLC_BYTE_LEN - rLen);
3414 pLen = (RLC_BYTE_LEN - rLen);
3418 hdrInfo->pLen = pLen;
3428 static Void rgAmmUlHndlStatusPdu
3440 RlcUdxStaPdu *pStaPdu;
3441 uint8_t e3; /* NACK RANGE : 5GNR */
3444 uint32_t resrvdBitsAckSn;
3445 uint32_t resrvdBitsNackSn;
3447 RLCDBGP_BRIEF(gCb, "rgAmmUlHndlStatusPdu(rbCb, cntrlPdu, fByte) \n");
3449 RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
3451 /* Extract the Control PDU */
3452 hdrInfo.hdr = (*fByte << 1);
3455 /* D/C has been shifted in the calling function */
3456 if (hdrInfo.hdr & 0xE0)
3458 RLCDBGP_ERROR(gCb, "rgAmmUlHndlStatusPdu: Reserved value for CPT received \n");
3462 RLC_ALLOC_SHRABL_BUF(udxPst->region,
3465 sizeof(RlcUdxStaPdu));
3467 #if (ERRCLASS & ERRCLS_ADD_RES)
3468 /* Memory allocation failure can not be expected */
3475 if (rbCb->m.amDl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
3478 resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_12BITS;
3479 resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_12BITS;
3481 else if (rbCb->m.amDl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
3484 resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_18BITS;
3485 resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_18BITS;
3490 resrvdBitsAckSn = 0;
3491 resrvdBitsAckSn = 0;
3494 pStaPdu->nackCnt = 0;
3496 hdrInfo.hdr = hdrInfo.hdr << RLC_CPT_LEN;
3499 hdrInfo.len = RLC_SN_LEN;
3500 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3501 pStaPdu->ackSn = hdrInfo.val;
3503 /* Check if NACK Exists */
3504 hdrInfo.len = RLC_E1_LEN;
3505 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3506 e1 = (uint8_t)hdrInfo.val;
3507 RLCDBGP_DETAIL(gCb, "rgAmmUlHndlStatusPdu: ACK SN = %d \n", pStaPdu->ackSn);
3509 /* Extract the Reserved Bits after ACK SN field */
3510 hdrInfo.len = resrvdBitsAckSn;
3511 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3514 /* If NACK exists in control PDU */
3515 /* For ACKs and NACKs */
3516 while (e1 && (pStaPdu->nackCnt < RLC_MAX_NACK_CNT))
3518 hdrInfo.len = snLen;
3519 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3520 pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
3522 hdrInfo.len = RLC_E1_LEN;
3523 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3524 e1 = (uint8_t)hdrInfo.val;
3527 /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
3529 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3530 /* e2 = (uint8_t) hdrInfo.val;*/
3532 /* Store e2 value */
3533 pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (uint8_t) hdrInfo.val;
3535 /* Extract e3 : 5GNR */
3536 /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
3538 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3539 e3 = (uint8_t) hdrInfo.val;
3541 /* Extract Reserved Bits after NACK SN */
3542 hdrInfo.len = resrvdBitsNackSn;
3543 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3545 /* Test for resegmentation */
3546 if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
3548 hdrInfo.len = RLC_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
3549 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3550 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
3552 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3553 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = hdrInfo.val;
3556 "rgAmmUlHndlStatusPdu: soStart and soEnd = %d %d \n",
3557 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
3558 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd);
3563 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
3564 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = 0;
3567 /* NACK RANGE Field is SET */
3570 /* Extract NACK range field */
3571 hdrInfo.len = RLC_NACK_RANGE_LEN;
3572 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3573 snRange = (uint8_t)hdrInfo.val;
3575 pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
3581 gRlcStats.amRlcStats.numULStaPduRcvd++;
3582 gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
3584 /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
3585 to the last NACK SN + 1 and discard the original ACK_SN*/
3586 if(pStaPdu->nackCnt == RLC_MAX_NACK_CNT)
3588 pStaPdu->ackSn = (pStaPdu->nackInfo[RLC_MAX_NACK_CNT-1].sn + 1) & amDl->snModMask;
3592 /* Parse & send Status PDU to RLC-DL */
3593 //rlcUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
3594 rlcUlUdxStaUpdReq(udxPst, suId, &rbCb->rlcId, pStaPdu);
3599 S16 rlcProcDlStatusPdu(Pst *udxPst,SuId suId,
3600 CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu)
3602 RlcDlRbCb *rbCb = NULLP;
3603 RlcDlUeCb *ueCb = NULLP;
3606 S16 retVal = RFAILED;
3608 Pst dlRlcPst = *udxPst;
3610 gCb = RLC_GET_RLCCB(1); /* DL RLC instance */
3612 if( ROK != rlcDbmFetchDlUeCb(gCb,rnti,cellId,&(ueCb)))
3614 printf("\n RLC UECb Not found...\n");
3619 rbCb = ueCb->lCh[lcId - 1].dlRbCb;
3621 /* Skip if mode is not AM */
3622 if((rbCb == NULLP) || (rbCb->mode != CM_LTE_MODE_AM))
3627 if(ROK != SExamMsg((Data *)(&fByte),
3630 printf("\n Failure in Rlc Hdr SExamMsg\n");
3634 if(RLC_CNTRL_PDU == ((fByte & RLC_DC_POS) >> RLC_DC_SHT))
3636 SRemPreMsg(&temp, rlcSdu);
3637 dlRlcPst.selector = 1;/* LWLC*/
3638 rgAmmUlHndlStatusPdu(&dlRlcPst,suId,gCb, rbCb, rlcSdu, &fByte);
3652 /********************************************************************30**
3655 **********************************************************************/