1 /*******************************************************************************
2 ################################################################################
3 # Copyright (c) [2017-2019] [Radisys] #
5 # Licensed under the Apache License, Version 2.0 (the "License"); #
6 # you may not use this file except in compliance with the License. #
7 # You may obtain a copy of the License at #
9 # http://www.apache.org/licenses/LICENSE-2.0 #
11 # Unless required by applicable law or agreed to in writing, software #
12 # distributed under the License is distributed on an "AS IS" BASIS, #
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
14 # See the License for the specific language governing permissions and #
15 # limitations under the License. #
16 ################################################################################
17 *******************************************************************************/
19 /********************************************************************20**
21 Name: RLC - AM DL module file
25 Desc: Source code for Acknowledged Mode Module functions such as,
27 Transmission of data/control PDUs
28 Retransmission (Feedback in terms of status)
31 Reception - reordering
32 Duplicate detection for byte segments
37 *********************************************************************21*/
38 static const char* RLOG_MODULE_NAME="AMM";
39 static int RLOG_MODULE_ID=2048;
40 static int RLOG_FILE_ID=189;
41 /* header include files (.h) */
42 #include "common_def.h"
43 #include "lkw.h" /* LKW defines */
44 #include "ckw.h" /* CKW defines */
45 #include "kwu.h" /* KWU defines */
46 #include "rgu.h" /* RGU defines */
47 #include "kw_err.h" /* Err defines */
48 #include "kw_env.h" /* RLC environment options */
50 #include "kw.h" /* RLC defines */
55 /* extern (.x) include files */
56 #include "lkw.x" /* LKW */
57 #include "ckw.x" /* CKW */
58 #include "kwu.x" /* KWU */
59 #include "rgu.x" /* RGU */
67 extern U32 kwAmmStaPduList[512];
68 U32 kwAmmStaPduListCnt = 0;
73 @brief RLC Acknowledged Mode Downlink Module
75 #define KW_MODULE (KW_DBGMASK_AM | KW_DBGMASK_DL)
77 U32 kwStatusPduCnt, kwStatusAckCnt, kwStatusNcnt, kwSduSndCnt;
83 /* forward references */
84 EXTERN Void kwAmmDlHndlStatusPdu ARGS ((RlcCb *gCb,
86 KwUdxStaPdu *pStaPdu));
88 /* public variable declarations */
90 /* This structure holds all the global structs we need. */
92 /* private variable declarations */
94 #define KW_AM_RMV_HDR(_gCb, _rbCb, _retx) do { \
95 if ((_retx)->yetToConst == FALSE) \
98 SSegMsg((_retx)->seg, (_retx)->hdrSz, &_pduInfo); \
99 RLC_FREE_BUF((_retx)->seg); \
100 (_retx)->seg = _pduInfo; \
102 (_rbCb)->m.amDl.estHdrSz -= retx->hdrSz;\
105 /* private function declarations */
107 PRIVATE Void kwResegRetxPdus ARGS ((RlcCb *gCb,
109 KwDatReq *kwDatReq));
111 PRIVATE Void kwRemRetxPdu ARGS ((RlcCb *gCb,
115 PRIVATE Void kwAmmCreateStatusPdu ARGS ((RlcCb *gCb,
117 KwDatReq *kwDatReq));
119 PRIVATE Void kwAmmDlMarkPduForReTx ARGS ((RlcCb *gCb,
123 PRIVATE Void kwAmmDlProcessSuccessfulTxPdu ARGS((RlcCb *gCb,
126 KwuDatCfmInfo **datCfm));
128 PRIVATE Void kwAmmDlSetTxNextAck ARGS((KwAmDl *amDl, KwSn sn));
130 PRIVATE Void kwAmmDlCheckAndStopPollTmr ARGS((RlcCb *gCb,
134 PRIVATE Void kwAssembleSdus ARGS ((RlcCb *gCb,
136 KwDatReq *kwDatReq));
138 PRIVATE Bool kwAmmDlCheckAndSetPoll ARGS ((RlcCb *gCb,
143 PRIVATE Void kwAmmCreatePdu ARGS ((RlcCb *gCb,
146 RlcDlPduInfo *pduInfo,
149 PRIVATE Void kwAmmSndStaInd ARGS ((RlcCb *gCb,RlcDlRbCb *rbCb, KwRetx *retx));
151 PRIVATE Void kwGetNxtRetx ARGS ((RlcCb *gCb, KwRetx **retx));
153 PRIVATE Void kwConstructAmHdr ARGS ((KwAmHdr *amHdr,
158 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForAckSn ARGS ((RlcCb *gCb,
162 KwuDatCfmInfo **datCfm));
164 PRIVATE Void kwAmmDlMoveFrmTxtoRetxBuffer ARGS ((RlcCb *gCb,
169 PRIVATE Void kwAmmDlCheckIsSDUDelivered ARGS((RlcCb *gCb,
172 KwuDatCfmInfo **datCfm));
174 PRIVATE Void kwAmmAddPduToRetxLst ARGS((KwAmDl *amDl,
177 PRIVATE Void kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer ARGS(
182 RlcDlPduInfo *pduInfo
185 PRIVATE Void kwAmmDlHndlStatus4SduByteSegInTxBuf ARGS(
189 KwNackInfo *nackSnInfo,
191 KwuDatCfmInfo **datCfm
194 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForNackSn ARGS(
198 KwNackInfo *nackSnInfo,
200 KwuDatCfmInfo **datCfm
203 PRIVATE Void RlcDlAmmGetNackSnInfoFrmNackRangeIdx ARGS(
206 KwNackInfo *nackInfo,
208 KwNackInfo *nackSnInfo,
212 PRIVATE Void kwAmmDlUpdTxAndReTxBufForLessThanNackSn ARGS(
219 KwuDatCfmInfo **datCfm
221 /*****************************************************************************
223 AM Module contains the following funcitons:
227 - kwAmmDlAssembleCntrlInfo
230 - kwAmmDlCheckAndSetPoll
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
255 PUBLIC Void kwAmmSendDStaRsp
262 PUBLIC Void kwAmmSendDStaRsp(gCb, rbCb, amDl)
268 S32 bo = kwAmmCalculateBo(amDl);
272 kwUtlSndDStaRsp(gCb, rbCb, bo, amDl->estHdrSz, amDl->cntrlBo ?TRUE:FALSE,amDl->cntrlBo);
279 * @brief Function to check if the pollSn is acked and stop the poll timer
281 * @param[in] gCb RLC instance control block
282 * @param[in] rbCb Radio Bearer control block
283 * @param[in] mAckSn The last received ACKSN. The base modulus value should
289 PRIVATE Void kwAmmDlCheckAndStopPollTmr
296 PRIVATE Void kwAmmDlCheckAndStopPollTmr(gCb, rbCb, mAckSn)
304 MODAMT(rbCb->m.amDl.pollSn, mPollSn, rbCb->m.amDl.txNextAck,rbCb->m.amDl.snModMask);
306 if (mPollSn <= mAckSn)
308 if (kwChkTmr(gCb, (PTR)rbCb, KW_EVT_AMDL_POLL_RETX_TMR))
310 kwStopTmr(gCb, (PTR)rbCb, KW_EVT_AMDL_POLL_RETX_TMR);
318 * @brief Function to set VT(A) and VT(MS). Calculates the VT(MS) from VT(A)
320 * @param[in,out] amDl AM downlink control block
321 * @param[in]sn Sequence number to be set as VT(A)
326 PRIVATE Void kwAmmDlSetTxNextAck
332 PRIVATE Void kwAmmDlSetTxNextAck(amDl, sn)
337 amDl->txNextAck = sn;
343 * @brief Function to process a successfully re-transmitted PDU/segment
346 * Checks if the SDU has been completely delivered or not. Removes the PDU
347 * from the re-transmission buffer
349 * @param[in] gCb RLC instance control block
350 * @param[in] rbCb Downlink Radio Bearer control block
351 * @param[in] retx The PDU/segment which was successfully re-transmitted
356 PRIVATE Void kwAmmDlProcessSuccessfulReTx
361 KwuDatCfmInfo **datCfm
364 PRIVATE Void kwAmmDlProcessSuccessfulReTx(gCb, rbCb, retx, datCfm)
368 KwuDatCfmInfo **datCfm;
371 kwAmmDlCheckIsSDUDelivered(gCb, rbCb, &(retx->sduMap), datCfm);
373 kwRemRetxPdu(gCb, rbCb, retx);
379 * @brief Handler to Move the PDU from txBuf to re-transmission buffer
382 * This function is used to move the PDU from the txBuf to re-transmit buffer
384 * @param[in]RlcCb *gCb RLC instance control block
385 * @param[in]KwAmDl *amDl AM Downlink Control Block
386 * @param[in]KwRetx **retx node in the reTx buffer to be moved to, allocated by
388 * @param[in]RlcDlPduInfo *pduInfo TX PDU which needs to be moved
395 PRIVATE Void kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer
400 RlcDlPduInfo *pduInfo
403 PRIVATE Void kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb, amDl, retx, pduInfo)
407 RlcDlPduInfo *pduInfo;
410 TRC2(kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer);
413 RLC_ALLOC_WC(gCb,*retx, sizeof(KwRetx));
415 #if (ERRCLASS & ERRCLS_ADD_RES)
418 RLOG0(L_FATAL, "Memory allocation failed");
421 #endif /* ERRCLASS & ERRCLS_RES */
423 (*retx)->seg = pduInfo->pdu;
424 (*retx)->segSz = pduInfo->pduSz;
425 /* MS_FIX for DL stall */
426 (*retx)->soEnd = (pduInfo->amHdr.so + pduInfo->pduSz - 1);
428 (*retx)->hdrSz = pduInfo->hdrSz;
429 (*retx)->retxCnt = 1;
430 (*retx)->yetToConst = 0;
431 (*retx)->pendingReTrans = TRUE;
433 /* initialize the list pointer to 0 instead of memset */
434 (*retx)->lstEnt.next = 0;
435 (*retx)->lstEnt.prev = 0;
436 /* copy the sdu maps */
437 KW_MEM_CPY(&((*retx)->sduMap),
441 KW_MEM_CPY(&((*retx)->amHdr), &pduInfo->amHdr, sizeof(KwAmHdr));
442 kwAmmAddPduToRetxLst(amDl, (*retx));
444 /* Update the BO appropriately */
445 amDl->retxBo += (*retx)->segSz;
446 amDl->estHdrSz += (*retx)->hdrSz;
448 gRlcStats.amRlcStats.numDLRetransPdus++;
451 } /*kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer */
454 * @brief Function to handle Status of Sdu byte segment for a nackSn
457 * This function is used to move the PDU from the txBuf to re-transmit buffer
459 * @param[in]RlcCb *gCb RLC instance control block
460 * @param[in]RlcDlRbCb *rbCb AM Downlink Control Block
461 * @param[in]KwNackInfo *nackSnInfo Nack Information of a NACK_SN
462 * @param[in]KwRetx **retx node in the reTx buffer to be moved to, allocated by
464 * @param[in]KwuDatCfmInfo **datCfm Ptr to datCfm
471 PRIVATE Void kwAmmDlHndlStatus4SduByteSegInTxBuf
475 KwNackInfo *nackSnInfo,
477 KwuDatCfmInfo ** datCfm
480 PRIVATE Void kwAmmDlHndlStatus4SduByteSegInTxBuf(gCb, rbCb, nackSnInfo, retx, datCfm)
484 KwNackInfo *nackSnInfo;
486 KwuDatCfmInfo **datCfm;
494 TRC2(kwAmmDlHndlStatus4SduByteSegInTxBuf)
496 txBuf = kwUtlGetTxBuf(AMDL.txBufLst, nackSnInfo->sn);
501 lnk = txBuf->pduLst.first;
504 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(lnk->node);
505 KwSn pduSoEnd = (pduInfo->amHdr.so + pduInfo->sduMap.sduSz - 1);
507 /* If So of Sdu byte segment(pduInfo/seg) is < status pdu
508 soStart that means it's ACKED*/
509 if(pduSoEnd < nackSnInfo->soStart)
511 kwAmmDlCheckIsSDUDelivered(gCb,
517 else if (pduSoEnd <= nackSnInfo->soEnd)
519 /* Move Sdu byte segment from TX buf to retx buf*/
520 kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb,
531 /* Delete node from the txBuf Pdu lst */
532 cmLListDelFrm(&txBuf->pduLst, lnk);
533 RLC_FREE_WC(gCb, pduInfo, sizeof(RlcDlPduInfo));
536 if(!txBuf->pduLst.count)
538 /*No more Sdu byte segment are left. Hence delete txBuf*/
539 kwUtlDelTxBuf(AMDL.txBufLst, txBuf,gCb);
546 * @brief Function to handle Status of Sdu byte segment for a nackSn
549 * This function is used to move the PDU from the txBuf to re-transmit buffer
551 * @param[in]RlcCb *gCb RLC instance control block
552 * @param[in]RlcDlRbCb *rbCb AM Downlink Control Block
553 * @param[in]KwNackInfo *nackSnInfo Nack Information of a NACK_SN
554 * @param[in]KwRetx **retx node in the reTx buffer to be moved to, allocated by
556 * @param[in]KwuDatCfmInfo **datCfm Ptr to datCfm
562 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForNackSn
566 KwNackInfo *nackSnInfo,
568 KwuDatCfmInfo **datCfm
571 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, nackSnInfo, retxNode, datCfm)
575 KwNackInfo *nackSnInfo;
577 KwuDatCfmInfo **datCfm;
584 TRC2(kwAmmDlUpdateTxAndReTxBufForNackSn)
586 /* Now process the NACK_SN received. Now the NACK_SN is */
587 /* either the first element of RETX or is in TX array */
588 /* To remove the remaining acks from the pdu byte segments */
590 /* if the NACK_SN is in the transmit buffer, move it to the re-
592 txBuf = kwUtlGetTxBuf(AMDL.txBufLst, nackSnInfo->sn);
595 if(nackSnInfo->isSegment)
597 /* Go through all the AMD PDUs of a particular SN
598 and check if segment is ACKED if yes then mark succesfully sent,
599 if segment is NACKed then move it to to retx lst */
600 kwAmmDlHndlStatus4SduByteSegInTxBuf(gCb, rbCb, nackSnInfo, &retx, datCfm);
604 /*e2= 0 and e3= 0: Move complete PDU from TX buf to retx buf*/
605 kwAmmDlMoveFrmTxtoRetxBuffer(gCb,
611 #if (ERRCLASS & ERRCLS_ADD_RES)
615 (*retxNode) = retx->lstEnt.next;
621 /* process the pdus/segments in the re-transmit buffer with
625 retx = (KwRetx *)((*retxNode)->node);
626 if (retx->amHdr.sn != nackSnInfo->sn)
630 if ((nackSnInfo->isSegment) &&
631 ((retx->soEnd < nackSnInfo->soStart) /*|| (retx->amHdr.so > soEnd)*/))
633 RLOG_ARG3(L_DEBUG, DBG_RBID, rbCb->rlcId.rbId,
634 "kwHndlStaRsp: Handle ACK for byte segment, Its "
635 "sn = %d UEID:%d CELLID:%d",
639 RLOG_ARG4(L_DEBUG, DBG_RBID, rbCb->rlcId.rbId,
640 "soStart and soEnd = %d, %d, UEID:%d CELLID:%d",
641 retx->amHdr.so, retx->soEnd,
645 (*retxNode) = (*retxNode)->next;
646 kwAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
648 else if((!nackSnInfo->isSegment) || (retx->soEnd <= nackSnInfo->soEnd))
650 /* This case covers the NACKED segments and also the case */
651 /* when there are segments and the entire SN is nacked. */
652 /* This case also covers the case of nonsegmented retx PDU*/
654 (*retxNode) = (*retxNode)->next;
655 /* Mark the retx PDU we found for further retransmission */
656 kwAmmDlMarkPduForReTx(gCb, rbCb, retx);
660 /* If we are here that means this segment and segments after this are ACKed*/
663 } /* end of retxNode while loop*/
668 * @brief Function to get nack Sn information from nackRange index
671 * This function is used to get nack Sn information from nackRange index
673 * @param[in]KwAmDl *amDl,
674 * @param[in]KwUdxStaPdu *StaPdu,
675 * @param[in]KwNackInfo *nackSnInfo,
676 * @param[in]KwRetx *retx;
684 PRIVATE Void RlcDlAmmGetNackSnInfoFrmNackRangeIdx
687 KwNackInfo *nackInfo,
689 KwNackInfo *nackSnInfo,
693 PRIVATE Void RlcDlAmmGetNackSnInfoFrmNackRangeIdx(amDl, nackInfo, retxNode, nackSnInfo, idx)
696 KwNackInfo *nackInfo;
698 KwNackInfo *nackSnInfo;
707 TRC2(RlcDlAmmGetNackSnInfoFrmNackRangeIdx)
709 nackSnInfo->isSegment = FALSE;
711 if((!nackInfo->isSegment) || (!idx && nackSnInfo->nackRange && (!nackInfo->soStart)))
713 nackSnInfo->soStart = 0;
714 nackSnInfo->soEnd = 0;
717 txBuf = kwUtlGetTxBuf(amDl->txBufLst, nackSnInfo->sn);
720 node = txBuf->pduLst.first;
723 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(node->node);
724 U16 pduSoEnd = pduInfo->amHdr.so + pduInfo->sduMap.sduSz - 1;
725 if((!idx) && (pduInfo->amHdr.so == nackInfo->soStart))
727 nackSnInfo->isSegment = TRUE;
728 nackSnInfo->soStart = pduInfo->amHdr.so;
729 nackSnInfo->soEnd = pduSoEnd;
732 else if((idx == nackSnInfo->nackRange - 1) && \
733 (pduSoEnd == nackInfo->soEnd))
735 nackSnInfo->isSegment = TRUE;
736 nackSnInfo->soStart = pduInfo->amHdr.so;
737 nackSnInfo->soEnd = pduSoEnd;
743 if(!nackSnInfo->isSegment)
747 retx = (KwRetx *)(retxNode->node);
748 if(retx->amHdr.sn != nackSnInfo->sn)
752 if((!idx) && (retx->amHdr.so == nackInfo->soStart))
754 nackSnInfo->isSegment = TRUE;
755 nackSnInfo->soStart = retx->amHdr.so;
756 nackSnInfo->soEnd = retx->soEnd;
759 else if((idx == nackSnInfo->nackRange - 1) && \
760 (retx->soEnd == nackInfo->soEnd))
762 nackSnInfo->isSegment = TRUE;
763 nackSnInfo->soStart = retx->amHdr.so;
764 nackSnInfo->soEnd = retx->soEnd;
767 retxNode = retxNode->next;
773 * @brief Function to update transmission buffers and send confimations to
774 * PDCP on the reception of Status PDU
777 * First processes the NACKs received
778 * -# Removes the pdus which are acked by each of the NACK SN from the
779 * transmission and re-transmission buffer
780 * -# If NACKed SN in in the transmisson buffer, moves it to re-transmission
782 * -# Removes PDU segments of the NACKed SN which have been successfully
783 * received by the other end. For the un-successful ones, marks them for
785 * -# When PDUs/segments are removed from the buffer, indicates to upper
786 * layer if the SDU is completely delivered
787 * -# Removes the PDUs/segments which are acked by the ACK_SN but not by the
790 * @param[in] gCb RLC Instance control block
791 * @param[in] rbCb Downlink Radio Bearer control block
792 * @param[in] pStaPdu The decoded Status Pdu
797 PUBLIC Void kwAmmDlHndlStatusPdu
804 PUBLIC Void kwAmmDlHndlStatusPdu(gCb, rbCb, pStaPdu)
807 KwUdxStaPdu *pStaPdu;
813 KwuDatCfmInfo* datCfm;
817 TRC2(kwAmmDlHndlStatusPdu)
820 kwuSap = gCb->u.dlCb->kwuDlSap + KW_UI_PDCP;
821 /* store the re-transmission bo, to check if it changes due to the
822 processing of the status pdu */
823 oldRetxBo = AMDL.retxBo;
825 /* Allocate memory for datCfm Info */
826 RLC_SHRABL_STATIC_BUF_ALLOC(kwuSap->pst.region, kwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
828 #if (ERRCLASS & ERRCLS_ADD_RES)
831 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
832 "Memory allocation failed UEID:%d CELLID:%d",
835 RLC_SHRABL_STATIC_BUF_FREE(kwuSap->pst.region, kwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
838 #endif /* ERRCLASS & ERRCLS_RES */
840 datCfm->numSduIds = 0;
841 datCfm->rlcId = rbCb->rlcId;
843 MODAMT(pStaPdu->ackSn, mAckSn, AMDL.txNextAck,AMDL.snModMask);
844 MODAMT(AMDL.txNext,mTxNext, AMDL.txNextAck,AMDL.snModMask);
848 RLOG_ARG4(L_WARNING,DBG_RBID, rbCb->rlcId.rbId,
849 "Invalid ACK SN = %d received. Current Vta =%d"
855 /* RLC_SHRABL_STATIC_BUF_ALLOC(kwuSap->pst.region, kwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo)); */
856 RLC_SHRABL_STATIC_BUF_FREE(kwuSap->pst.region, kwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
860 /* Venki - stopping the poll retx timer */
861 /*Stop PollRetx Tmr */
862 kwAmmDlCheckAndStopPollTmr(gCb, rbCb, mAckSn);
864 /* Set the first node in retx list to retxNode */
865 retxNode = AMDL.retxLst.first;
867 /* If NACK exists in control PDU */
868 if (pStaPdu->nackCnt)
871 KwNackInfo nackSnInfo;
874 KwSn transWinStartSn = AMDL.txNextAck; /*used to track the SN from which
875 to start processing the transmission
879 /* if any NACKs then txNextAck should be equal to the first NACK_SN*/
880 txNextAck = pStaPdu->nackInfo[0].sn;
882 kwStatusNcnt += pStaPdu->nackCnt;
885 while (idx < pStaPdu->nackCnt)
887 nackSnInfo.isSegment = pStaPdu->nackInfo[idx].isSegment;
888 nackSnInfo.nackRange = pStaPdu->nackInfo[idx].nackRange;
889 nackSnInfo.sn = pStaPdu->nackInfo[idx].sn;
891 RLOG_ARG3(L_DEBUG,DBG_RBID, rbCb->rlcId.rbId,
892 "kwHndlStaRsp: NACK SN = %d UEID:%d CELLID:%d",
897 nackSnInfo.soStart = pStaPdu->nackInfo[idx].soStart;
898 nackSnInfo.soEnd = pStaPdu->nackInfo[idx].soEnd;
900 /* e2 is used as a boolean indicating presence of SOStart or SOEnd */
902 sn = transWinStartSn;
904 /* move transWinStartSn to nackSnInfo.sn + 1, as the pdu's before that
905 will be removed from the buffer */
906 transWinStartSn = (nackSnInfo.sn + (nackSnInfo.nackRange ?\
907 (nackSnInfo.nackRange - 1) : 0) + 1) & AMDL.snModMask;
909 /* Clear the acked SNs from the retx list */
910 MODAMT(nackSnInfo.sn, mNackSn, AMDL.txNextAck,AMDL.snModMask);
912 if ((mNackSn > mAckSn) || (mNackSn >= mTxNext))
914 /* Erroneous NACK_SN, we should raise an error towards L3 */
915 RLOG_ARG2(L_ERROR,DBG_RBID, rbCb->rlcId.rbId,
916 "Status Pdu is not correct UEID:%d CELLID:%d",
919 RLC_SHRABL_STATIC_BUF_FREE(kwuSap->pst.region, kwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
923 /* clear all the SNs < NACK_SN from re-transmission list */
924 kwAmmDlUpdTxAndReTxBufForLessThanNackSn(gCb, rbCb, sn, mNackSn,
927 if(!nackSnInfo.nackRange)
929 kwAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, &nackSnInfo, &retxNode, &datCfm);
930 gRlcStats.amRlcStats.numRlcAmCellNackRx++;
935 /* Update issegment, soStart, soEnd ,sn in nackSnInfo and handle
939 RlcDlAmmGetNackSnInfoFrmNackRangeIdx(&AMDL, &pStaPdu->nackInfo[idx],
940 retxNode, &nackSnInfo, idx1);
942 kwAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, &nackSnInfo,
944 nackSnInfo.sn = ((nackSnInfo.sn + 1) & (AMDL.snModMask));
945 gRlcStats.amRlcStats.numRlcAmCellNackRx++;
947 }while((++idx1) < (nackSnInfo.nackRange));
951 } /* End of nackCnt while loop */
953 /* Remove the PDUs with are further acked by the ACK_SN after taking
954 care of all the NACK_SN related acknowledgments*/
955 kwAmmDlUpdateTxAndReTxBufForAckSn(gCb,rbCb, mAckSn, retxNode, &datCfm);
957 /* Update txNextAck */
958 kwAmmDlSetTxNextAck(&AMDL,txNextAck);
964 RLOG_ARG2(L_UNUSED,DBG_RBID, rbCb->rlcId.rbId,
965 "kwHndlStaRsp: Received All ACKS UEID:%d CELLID:%d",
969 /* For the remaining ACKs after last nackSn */
970 kwAmmDlUpdateTxAndReTxBufForAckSn(gCb,rbCb, mAckSn, retxNode, &datCfm);
972 /* update txNextAck */
973 kwAmmDlSetTxNextAck(&AMDL, pStaPdu->ackSn);
976 if(datCfm->numSduIds != 0)
978 if(datCfm->numSduIds > 1024)
980 RLOG_ARG4(L_DEBUG,DBG_RBID,datCfm->rlcId.rbId,
981 "Sending [%lu] SDU Cfms to PDCP & [%lu] lost for"
984 datCfm->numSduIds-1024,
987 datCfm->numSduIds = 1024;
989 kwSduSndCnt += datCfm->numSduIds;
990 /* Sap control block */
991 KwUiKwuDatCfm(&kwuSap->pst, kwuSap->suId, datCfm);
995 RLC_SHRABL_STATIC_BUF_FREE(kwuSap->pst.region, kwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
998 /* Fix for memory corruption */
999 KW_LLIST_FIRST_RETX(AMDL.retxLst, AMDL.nxtRetx);
1000 /* BO update, if retransmission BO has changed. AMDL.retxBo would have
1001 canged inside the above called functions */
1002 if (oldRetxBo != AMDL.retxBo)
1004 kwAmmSendDStaRsp(gCb, rbCb, &AMDL);
1011 * @brief Function to calculate the current buffer occupancy
1014 * Function to calculate the current bo depending on the control,
1015 * re-transmit, transmit bo's and the state of the transmit window.
1016 * If the transmit window is stalled, then the transmit bo is not
1017 * taken into account
1019 * @param[in] amDl AM mode donwlink control block
1025 PUBLIC S32 kwAmmCalculateBo
1030 PUBLIC S32 kwAmmCalculateBo(amDl)
1036 /* Make sure non of the bo's are negative */
1042 if (amDl->cntrlBo < 0)
1047 if (amDl->retxBo < 0)
1052 bo = amDl->cntrlBo + amDl->retxBo;
1054 /* if window is not stalled then add the transmit bo also */
1055 if (! KW_AM_IS_TRANS_WIN_STALLED(amDl))
1065 * @brief Handler to queue the SDUs received from PDCP
1068 * This function is invoked by UIM to queue the SDU received from PDCP in the
1069 * SDU queue of the corresponding RbCb. It also updates the BO and report the
1071 * - Allocate memory for and assign received buffer to the SDU
1072 * - Add SDU in the sduQ of KwAmDl
1073 * - Calculate bo with the buffer received
1074 * - Accumulate bo with retransmission bo and control pdu's bo if available
1075 * - Estimate the header size for the bo; Fill in StaRspInfo and send it
1078 * @param[in] gCb RLC Instance control block
1079 * @param[in] rbCb RB control block
1080 * @param[in] mBuf Sdu to be queued
1081 * @param[in] datReq Ptr to the datReq sent from PDCP
1087 PUBLIC Void kwAmmQSdu
1092 KwuDatReqInfo *datReq
1095 PUBLIC Void kwAmmQSdu(gCb, rbCb, mBuf, datReq)
1099 KwuDatReqInfo *datReq;
1113 RLC_ALLOC_WC(gCb,sdu, sizeof(KwSdu));
1115 #if (ERRCLASS & ERRCLS_ADD_RES)
1118 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1119 "Memory allocation failed UEID:%d CELLID:%d",
1121 rbCb->rlcId.cellId);
1124 #endif /* ERRCLASS & ERRCLS_RES */
1126 KW_UPD_L2_DL_TOT_SDU_STS(gCb,rbCb);
1127 /* Discard new changes starts */
1128 kwUtlGetCurrTime(&sdu->arrTime);
1129 /* Discard new changes ends */
1130 /* Assign values to sdu */
1131 SFndLenMsg(mBuf, &sdu->sduSz);
1134 sdu->actSz = sdu->sduSz;
1135 sdu->mode.am.sduId = datReq->sduId;
1136 /* initialize values for AM mode to 0 */
1137 sdu->mode.am.rcvdSz = 0;
1138 sdu->mode.am.isSegmented = 0;
1139 #ifndef RGL_SPECIFIC_CHANGES
1142 extern U32 dlrate_kwu;
1143 dlrate_kwu += sdu->sduSz;
1147 /* Update nxtTx to point to the added sdu if this is the first SDU in the
1149 if (AMDL.nxtTx == NULLP)
1151 RLOG_ARG2(L_UNUSED,DBG_RBID, rbCb->rlcId.rbId,
1152 "kwAmmQSdu: Received SDU will be transmitted next"
1153 "UEID:%d CELLID:%d",
1155 rbCb->rlcId.cellId);
1159 /* Add sdu to the sdu list */
1160 cmLListAdd2Tail(&AMDL.sduQ, &sdu->lstEnt);
1161 sdu->lstEnt.node = (PTR)sdu;
1165 if (rbCb->ueCb->tenbStats)
1167 if (AMDL.sduQ.count > rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxPktsInSduQ)
1169 rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxPktsInSduQ = AMDL.sduQ.count;
1171 kwWinSz = KW_AM_TRANS_WIN_SIZE(&AMDL);
1172 if (kwWinSz > rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxWindowSz)
1174 rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxWindowSz = kwWinSz;
1180 /* Update BO and estimate header size for the current BO */
1181 AMDL.bo = AMDL.bo + sdu->sduSz;
1182 if(AMDL.snLen == KW_AM_CFG_12BIT_SN_LEN)
1190 #ifdef LTE_L2_MEAS_RLC
1191 /* Update numActUe if it is not active */
1192 if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_ACT_UE) &&
1193 (rbCb->ueCb->numActRb[rbCb->qci] == 0))
1195 rbCb->ueCb->numActRb[rbCb->qci]++;
1196 gCb.kwL2Cb.numActUe[rbCb->qci]++;
1200 if(!rlcDlUtlIsReestInProgress(rbCb))
1202 kwAmmSendDStaRsp(gCb, rbCb, &AMDL);
1210 * @brief Private handler to construct control PDU
1213 * This function sets the pduSz correctly after eliminating the fixed
1214 * header sizes and the MAC header size. It copies the already prepared
1215 * STATUS PDU to the data to be sent to MAC.
1217 * @param[in] gCb RLC instance control block
1218 * @param[in] rbCb Downlink RB control block
1219 * @param[in] kwdatReq DatReq to be sent to MAC
1225 PRIVATE Void kwAmmDlAssembleCntrlInfo
1232 PRIVATE Void kwAmmDlAssembleCntrlInfo(gCb, rbCb, kwDatReq)
1238 KwUdxDlSapCb *sapCb;
1241 TRC2(kwAmmDlAssembleCntrlInfo)
1243 macHdrEstmt = (rbCb->m.amDl.cntrlBo < 256) ?
1244 KW_MAC_HDR_SZ2 : KW_MAC_HDR_SZ3;
1245 /* Eliminate fixed hdr size (14bits including ACK_SN) */
1246 if (kwDatReq->pduSz >= (KW_CNTRL_PDU_FIXED_HDRSZ + macHdrEstmt))
1248 /* Check the TB size whether it is sufficcient enough to fit the
1249 status Pdu into it otherwise make arrangement such that it can fit
1250 into in a way of possible NACks*/
1251 /* ccpu00135743 : fix for MAC Hdr size calc */
1252 kwDatReq->pduSz -= macHdrEstmt;
1254 /* Create the status Pdu with the required NACKs */
1255 kwAmmCreateStatusPdu(gCb,rbCb,kwDatReq);
1257 sapCb = KW_GET_DL_SAPCB(gCb, rbCb);
1258 rlcDlUdxStaProhTmrStart(&(gCb->u.dlCb->udxDlSap->pst),
1259 sapCb->suId, &(rbCb->rlcId));
1261 /* Update number of pdus in pduInfo */
1262 kwDatReq->pduInfo.mBuf[kwDatReq->pduInfo.numPdu] = AMDL.mBuf;
1263 kwDatReq->pduInfo.numPdu++;
1264 gRlcStats.amRlcStats.numDLStaPduSent++;
1266 RLC_FREE_SHRABL_BUF(gCb->u.dlCb->udxDlSap->pst.region,
1267 gCb->u.dlCb->udxDlSap->pst.pool,
1269 sizeof(KwUdxDlStaPdu));
1271 AMDL.pStaPdu = NULLP;
1273 gRlcStats.amRlcStats.numDLStaPduSent++;
1280 * @brief Handler to form the PDUs with the size indicated by MAC
1283 * This function is invoked by UTL with the PDU size indicated by
1284 * MAC (after eliminating MAC header size). It assembles control
1285 * Info / data (New SDUs / Retx PDUs), check if polling needs to be
1286 * set for the data PDU and returns PDU(s) and updated BO with
1287 * estimated header size to be sent to MAC.
1289 * - Check if the control BO is available and call kwAssembleCntrlInfo
1290 * to assemble control Information
1291 * - Check if the pdu size is available to form PDUs from retransmission
1292 * buffer and call kwResegRetxPdus
1293 * - Check if the pdu size is available and assemble SDUs from sduQ
1294 * if exist, using kwAssembleSdus
1295 * - PDU Info and bo are filled in and then sent to MAC from the
1298 * @param[in] gCb RLC instance control block
1299 * @param[in] rbCb RB control block
1300 * @param[in] kwdatReq DatReq to be sent to MAC
1301 * @param[in] fillCtrlPdu Indicates whether cntrl PDU to be filled or not
1307 PUBLIC Void kwAmmProcessSdus
1315 PUBLIC Void kwAmmProcessSdus(gCb, rbCb, kwDatReq,fillCtrlPdu)
1322 TRC2(kwAmmProcessSdus)
1325 /* Assemble control information. fillCtrlPdu parameter check is added for CA
1326 * It is used to force cntrl Pdu scheduling on PCell. for Non CA case this
1327 * flag will always be TRUE. In CA case, for PCELL it is TRUE and for SCEll
1330 if ((AMDL.cntrlBo != 0)
1336 kwDatReq->boRep.staPduPrsnt = TRUE;
1337 kwDatReq->boRep.staPduBo = AMDL.cntrlBo;
1339 if (AMDL.pStaPdu != NULLP)
1341 kwAmmDlAssembleCntrlInfo (gCb, rbCb, kwDatReq);
1345 RLOG_ARG2(L_ERROR, DBG_RBID, rbCb->rlcId.rbId,
1346 "Miscomputation of control Bo. UEID:%d CELLID:%d",
1348 rbCb->rlcId.cellId);
1353 /* Retransmit PDUs /portions of PDUs available in retxLst */
1354 if ((kwDatReq->pduSz > 0) && (AMDL.nxtRetx != NULLP))
1356 kwResegRetxPdus (gCb,rbCb, kwDatReq);
1359 /* Assemble SDUs to form new PDUs */
1360 if ((kwDatReq->pduSz > 0) && (AMDL.nxtTx != 0))
1362 kwAssembleSdus(gCb,rbCb, kwDatReq);
1365 if (AMDL.nxtRetx != NULLP)
1367 kwDatReq->boRep.oldestSduArrTime = AMDL.nxtRetx->sduMap.sdu->arrTime;
1369 else if (AMDL.nxtTx != NULLP)
1371 kwDatReq->boRep.oldestSduArrTime = AMDL.nxtTx->arrTime;
1374 kwDatReq->boRep.bo = kwAmmCalculateBo(&AMDL);
1375 kwDatReq->boRep.staPduBo = AMDL.cntrlBo;
1377 /* Hdr estimation is moved to kwAmmCreatePDu */
1378 kwDatReq->boRep.estHdrSz = AMDL.estHdrSz;
1380 if(kwDatReq->pduSz > 0)
1382 gRlcStats.amRlcStats.numDLBytesUnused += kwDatReq->pduSz;
1388 * @brief Private handler split a PDU/segment into two
1391 * Its a private function called by kwResegRetxPdu to split a segment
1392 * or a retransmit PDU into two segments splitting at the passed size.
1393 * This function is called only for those PDUs that dont have any LIs.
1395 * @param[in] gCb RLC instance control block
1396 * @param[in] rbCb RB control block
1397 * @param[in,out] crnt The PDU to be split, first part of split pdu remians
1399 * @param[out] next The second part of the split pdu
1400 * @param[in] size The size witin crnt, at which to split
1406 PRIVATE Void kwSplitPdu
1415 PRIVATE Void kwSplitPdu(gCb, rbCb, crnt, next, size)
1424 KwAmDl *amDl = &AMDL;
1427 /* Set the SN for the new segment */
1428 next->amHdr.sn = crnt->amHdr.sn;
1430 /* Set the protocol specific fields appropriately */
1431 si = crnt->amHdr.si;
1432 crnt->amHdr.si = si | KW_SI_FIRST_SEG;
1433 next->amHdr.si = si | KW_SI_LAST_SEG;
1437 /* Update seg size */
1438 next->segSz = crnt->segSz - size;
1441 /* Set the SO fields appropriately */
1442 /* MS_FIX for DL stall */
1443 next->soEnd = crnt->soEnd;
1445 /* Set the SO fields appropriately */
1446 /* SO of next will be after the end of current */
1447 next->amHdr.so = crnt->amHdr.so + crnt->segSz;
1448 /* SO End of current will be one less than the start of next */
1449 crnt->soEnd = next->amHdr.so - 1;
1451 /* intialize the other fields in the amHdr of next to 0 */
1455 /* This macro is called for No LI case - one SDU */
1456 /* Update the size of SDU in each node's sduMap */
1457 next->sduMap.sdu = crnt->sduMap.sdu;
1458 crnt->sduMap.sduSz = crnt->segSz;
1459 next->sduMap.sduSz = next->segSz;
1461 /* Segment the payload into two parts based on the size passed */
1462 SSegMsg(crnt->seg, size, &next->seg);
1463 next->retxCnt = crnt->retxCnt;
1464 next->yetToConst = TRUE;
1465 next->pendingReTrans = crnt->pendingReTrans;
1467 /* Compute the header size and update the BO appropriately */
1468 if(amDl->snLen == KW_AM_CFG_12BIT_SN_LEN)
1470 next->hdrSz = KW_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1471 if(crnt->amHdr.si == KW_SI_FIRST_SEG)
1473 crnt->hdrSz = KW_AM_SEG_12BIT_SN_WITHOUT_SO_HDRSZ;
1477 crnt->hdrSz = KW_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1482 next->hdrSz = KW_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1483 if(crnt->amHdr.si == KW_SI_FIRST_SEG)
1485 crnt->hdrSz = KW_AM_SEG_18BIT_SN_WITHOUT_SO_HDRSZ;
1489 crnt->hdrSz = KW_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1493 /* Add the next to the retx list */
1494 AMDL.retxLst.crnt = &crnt->lstEnt;
1495 CM_LLIST_INS_AFT_CRNT(AMDL.retxLst, next);
1496 AMDL.nxtRetx = next;
1497 amDl->estHdrSz += next->hdrSz;
1503 * @brief Private handler to retransmit PDUs or PDU segments
1506 * Its a private function called by kwProcessSdus, to create the
1507 * PDUs / its segments from the retransmission buffer available in RbCb.
1509 * - Eliminate the fixed header size and MAC header size while
1510 * forming PDUs/segments
1511 * - While pdusize is available and retxBuf has data (pdu or portion
1512 * of pdu) to be sent, form the pdu as it is if it matches with the
1513 * pdusize else segment the PDUs/portion of PDUs
1514 * - Call kwAmmDlCheckAndSetPoll function to check and set the poll bit as
1516 * - Concatenate data and header info and fill pduInfo
1517 * - Update retxCnt and send indication to PDCP if it reaches maxRetx
1520 * @param[in] gCb RLC instance control block
1521 * @param[in] rbCb RB control block
1522 * @param[in] kwdatReq DatReq to be sent to MAC
1528 PRIVATE Void kwResegRetxPdus
1535 PRIVATE Void kwResegRetxPdus(gCb, rbCb, kwDatReq)
1543 U8 hdr[KW_MAX_HDRSZ];
1549 KwL2MeasTb *l2MeasTb;
1554 TRC2(kwResegRetxPdus)
1559 /* TODO : This shoould be taken care in new Trasmissions */
1560 /* This lchInfo should be retrieved there */
1561 l2MeasTb = kwUtlGetCurMeasTb(gCb, rbCb);
1562 if (l2MeasTb == NULLP)
1566 /* TODO : This lcid needs to be searched in case of normal Tx */
1567 /* In retx here, its fine as this will be higher priority */
1568 lchInfo = &l2MeasTb->lchInfo[l2MeasTb->numLchInfo];
1569 if (l2MeasTb->numLchInfo >= KW_MAX_ACTV_DRB)
1573 l2MeasTb->numLchInfo++;
1574 lchInfo->lcId = rbCb->lch.lChId;
1575 lchInfo->numSdus = 0;
1578 while ((kwDatReq->pduSz > 0) && (amDl->nxtRetx != NULLP)&&
1579 (kwDatReq->pduInfo.numPdu < KW_MAX_PDU))
1583 retx = amDl->nxtRetx;
1584 /* kw003.201 : Add header size to seg size to determine if the */
1585 /* the segment can be completed within the allocation */
1586 /* kw003.201 - Eliminate MAC Header Size based on bites needed */
1587 tmpSz = KW_MIN((retx->segSz + retx->hdrSz), kwDatReq->pduSz);
1588 pduSz = (retx->segSz + retx->hdrSz);
1589 /* 5GNR_RLC: length field in 5GNR MAC Hdr is 8/16 btis*/
1590 kwDatReq->pduSz -= (tmpSz < 255) ? KW_MAC_HDR_SZ2 : KW_MAC_HDR_SZ3;
1592 /* kw003.201 - We should have at least one more than basic header */
1593 if (kwDatReq->pduSz <= retx->hdrSz)
1597 kwGetNxtRetx(gCb, &(amDl->nxtRetx));
1599 /* Send retx buf without segmentation */
1600 if (kwDatReq->pduSz >= pduSz)
1604 RLOG_ARG2(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
1605 "kwResegRetxPdus: Send retx buf without segmentation "
1606 "UEID:%d CELLID:%d",
1608 rbCb->rlcId.cellId);
1610 if (retx->yetToConst)
1612 /* Construct hdr with the available hdr values */
1613 kwConstructAmHdr(&retx->amHdr, hdr, amDl->snLen, &idx);
1614 /* Add header to the pdu/segment */
1615 SAddPreMsgMultInOrder(hdr, idx + 1, retx->seg);
1616 retx->yetToConst = FALSE;
1619 /* kw003.201 - Check if poll bit needs to be set. Retx size does */
1620 /* not affect the poll bit so it is being passed as zero */
1621 pollBit = kwAmmDlCheckAndSetPoll(gCb,rbCb, FALSE, 0);
1622 KW_UPD_POLL_BIT(gCb, retx, pollBit);
1624 kwDatReq->pduSz -= pduSz;
1625 AMDL.estHdrSz -= retx->hdrSz;
1628 if (rbCb->rlcId.rbType == CM_LTE_DRB)
1631 for (sduIdx = lchInfo->numSdus ;
1632 ((numSdus < retx->numSdu) && (sduIdx < KW_L2MEAS_SDUIDX)) ;
1633 sduIdx++, numSdus++)
1635 lchInfo->sduInfo[sduIdx].arvlTime = retx->sduMap[numSdus].sdu->arrTime;
1636 lchInfo->sduInfo[sduIdx].isRetxPdu = TRUE; /* TODO : for later use */
1638 lchInfo->numSdus += numSdus;
1646 /* Segment this pdu / portion of pdu. Insert this segment into */
1647 /* retxLst and update offset */
1648 RLOG_ARG2(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
1649 "kwResegRetxPdus: Segment retx buf UEID:%d CELLID:%d",
1651 rbCb->rlcId.cellId);
1653 /* Eliminate fixed header size if the pdu is segmented for the */
1655 if(amDl->snLen == KW_AM_CFG_12BIT_SN_LEN)
1657 if(retx->amHdr.si < KW_SI_LAST_SEG)
1659 kwDatReq->pduSz -= KW_AM_SEG_12BIT_SN_WITHOUT_SO_HDRSZ;
1663 kwDatReq->pduSz -= KW_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1668 if(retx->amHdr.si < KW_SI_LAST_SEG)
1670 kwDatReq->pduSz -= KW_AM_SEG_18BIT_SN_WITHOUT_SO_HDRSZ;
1674 kwDatReq->pduSz -= KW_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1677 if (kwDatReq->pduSz <= 0)
1682 /* Allocate memory for tracking a new segment */
1683 RLC_ALLOC_WC(gCb,tNode, sizeof(KwRetx));
1684 #if (ERRCLASS & ERRCLS_ADD_RES)
1687 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1688 "Memory allocation failed UEID:%d CELLID:%d",
1690 rbCb->rlcId.cellId);
1693 #endif /* ERRCLASS & ERRCLS_RES */
1695 /* initialize the list pointer to 0 instead of memset */
1696 tNode->lstEnt.next = 0;
1697 tNode->lstEnt.prev = 0;
1699 /* Segment header and data */
1700 KW_AM_RMV_HDR(gCb, rbCb, retx);
1702 /* kw003.201 - Split the payload and update other fields */
1703 kwSplitPdu(gCb,rbCb, retx, tNode, kwDatReq->pduSz);
1708 sduIdx = lchInfo->numSdus;
1709 for (numSdus = 0, sduIdx = lchInfo->numSdus;
1710 ((numSdus < retx->numSdu) && (sduIdx < KW_L2MEAS_SDUIDX));
1711 numSdus++, sduIdx++)
1713 lchInfo->sduInfo[sduIdx].arvlTime =
1714 retx->sduMap[numSdus].sdu->arrTime;
1715 lchInfo->sduInfo[sduIdx].isRetxPdu = TRUE;
1717 lchInfo->numSdus = sduIdx;
1718 if ((retx->amHdr.lsf == 0) && (lchInfo->numSdus > 0))
1723 /* Construct hdr with the available hdr values */
1724 kwConstructAmHdr(&retx->amHdr, hdr, amDl->snLen, &idx);
1725 SAddPreMsgMultInOrder(hdr, idx + 1, retx->seg);
1727 retx->hdrSz = idx + 1;
1729 /* Poll bit need not be set for this seg, since its second */
1730 /* half remains in retxLst */
1731 KW_UPD_POLL_BIT(gCb, retx, FALSE);
1732 retx->yetToConst = FALSE;
1733 kwDatReq->pduSz = 0;
1736 kwCpyMsg(gCb,retx->seg, &pdu);
1738 /* Update pduInfo */
1739 kwDatReq->pduInfo.mBuf[kwDatReq->pduInfo.numPdu] = pdu;
1740 kwDatReq->pduInfo.numPdu++;
1741 /* kw005.201 ccpu00117318, updating the statistics */
1742 gCb->genSts.pdusRetx += 1;
1743 gRlcStats.amRlcStats.numRlcAmCellRetxPdu++;
1744 retx->soEnd = retx->amHdr.so + retx->segSz - 1;
1745 retx->pendingReTrans = FALSE;
1746 amDl->retxBo -= retx->segSz;
1749 RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
1750 "kwResegRetxPdus: retxBo after resegmentation = %ld"
1751 "UEID:%d CELLID:%d",
1754 rbCb->rlcId.cellId);
1756 RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
1757 "kwResegRetxPdus: retxBo after resegmentation = %d "
1758 "UEID:%d CELLID:%d",
1761 rbCb->rlcId.cellId);
1769 * @brief Private handler to assemble SDUs to form new data PDU(s)
1772 * Its a private function called by kwProcessSdus, to create the new data
1773 * PDUs from the SDU queue of RbCb.
1775 * - While pdusize is available, segment/concatenate SDUs or else if it
1776 * matches the pdu size form PDUs accordingly.
1777 * - RLC header and MAC header size are eliminated while forming the PDUs
1778 * - Call kwAmmDlCheckAndSetPoll function to check and set the poll bit
1780 * - Concatenate data and header info and fill pduInfo
1782 * @param[in] rbCb RB control block
1783 * @param[in] kwdatReq DatReq to be sent to MAC
1789 PRIVATE Void kwAssembleSdus
1796 PRIVATE Void kwAssembleSdus (gCb, rbCb, kwDatReq)
1802 Buffer *pdu = NULLP;
1803 MsgLen macGrntSz = kwDatReq->pduSz;
1804 KwAmDl *amDl = &AMDL;
1805 KwSdu *sdu = amDl->nxtTx;
1807 Bool nxtTxUpd = FALSE;
1808 KwuDiscSduInfo *discSduInfo = NULLP;
1809 KwKwuSapCb* kwuSap = gCb->u.dlCb->kwuDlSap + KW_UI_PDCP;
1811 KwContSduLst contSduLst; /*Contained sduLst */
1812 S32 dataVol = amDl->bo;
1813 U32 *totMacGrant = &kwDatReq->totMacGrant;
1814 KwL2MeasDlIpTh *dlIpThPut = &rbCb->l2MeasIpThruput.dlIpTh;
1815 U8 *sduIdx = &dlIpThPut->lastSduIdx;
1817 Bool isSduSegmented;
1820 KwlchInfo *dstLchInfo;
1825 KwL2MeasTb *l2MeasTb;
1827 /* Discard new changes starts */
1831 KwTx *txBuf = NULLP;
1832 /* Discard new changes ends */
1833 VOLATILE U32 startTime = 0;
1837 KwAmHdr *amHdr = NULLP;
1838 RlcDlPduInfo *pduInfo = NULLP;
1840 TRC2(kwAssembleSdus)
1844 contSduLst.numSdus = 0;
1845 contSduLst.lcId = rbCb->lch.lChId;
1847 lchInfo.lcId = rbCb->lch.lChId;
1848 lchInfo.numSdus = 0;
1850 /* Discard new changes starts */
1851 /* Allocate memory for discSdu Info */
1852 RLC_SHRABL_STATIC_BUF_ALLOC(kwuSap->pst.region,
1855 sizeof(KwuDiscSduInfo));
1857 #if (ERRCLASS & ERRCLS_ADD_RES)
1858 if (discSduInfo == NULLP)
1860 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1861 "Memory allocation failed UEID:%d CELLID:%d",
1863 rbCb->rlcId.cellId);
1866 #endif /* ERRCLASS & ERRCLS_RES */
1868 discSduInfo->numSduIds = 0;
1869 discSduInfo->rlcId = rbCb->rlcId;
1871 kwUtlGetCurrTime(&curTime);
1872 amDl->sduQ.crnt = &sdu->lstEnt;
1873 /* Eliminate fixed header size */
1874 /*5GNR: value of KW_AM_PDU_FIXED_HDRSZ will be 2 or 3 depending on SN Size*/
1875 if(amDl->snLen == KW_AM_CFG_12BIT_SN_LEN)
1877 fixedHdrSz = KW_AM_PDU_12BIT_SN_HDRSZ;
1881 fixedHdrSz = KW_AM_PDU_18BIT_SN_HDRSZ;
1884 while ((macGrntSz > fixedHdrSz) && (sdu != NULLP) &&
1885 (kwDatReq->pduInfo.numPdu < KW_MAX_PDU) &&
1886 (numNewPdu < KW_MAX_NEW_DL_PDU))
1889 isSduSegmented = sdu->mode.am.isSegmented;
1891 /* Discard new changes starts */
1892 if ((sdu->mode.am.isSegmented == FALSE) && (rbCb->discTmrInt > 0) && \
1893 (rbCb->rlcId.rbType == CM_LTE_DRB))
1895 //leftAmSdus[rbCb->qci]--;
1896 timeDiff = KW_TIME_DIFF(curTime,sdu->arrTime);
1897 if (timeDiff > rbCb->discTmrInt)
1901 SStartTask(&startTime, PID_RLC_AMM_DISC_SDUS);
1903 KW_UPD_L2_DL_DISC_SDU_STS(gCb,rbCb);
1904 /* TODO need to send disc cfm to pdcp */
1906 /* Update bo for boReport */
1907 amDl->bo -= sdu->sduSz;
1909 /* Get next sdu for assembly */
1910 nxtNode = sdu->lstEnt.next;
1912 /* store the info for sending it to PDCP */
1913 if(discSduInfo->numSduIds > 500)
1915 RLOG_ARG2(L_ERROR,DBG_RBID, rbCb->rlcId.rbId,
1916 "This is a big error, we shouldn't be here"
1917 "UEID:%d CELLID:%d",
1919 rbCb->rlcId.cellId);
1923 discSduInfo->sduIds[discSduInfo->numSduIds] = sdu->mode.am.sduId;
1924 discSduInfo->numSduIds++;
1926 cmLListDelFrm(&amDl->sduQ, &sdu->lstEnt);
1928 kwUtlAddSduToBeFreedQueue(gCb, sdu);
1929 kwUtlRaiseDlCleanupEvent(gCb);
1931 /* We need to restore the crnt in the linked list which
1932 * would have become NULL in the DelFrm above */
1933 amDl->sduQ.crnt = nxtNode;
1936 sdu = (KwSdu*)nxtNode->node;
1941 SStopTask(startTime, PID_RLC_AMM_DISC_SDUS);
1950 /** kw003.201 - Check for window stall when you are
1951 * creating a new PDU
1953 if (KW_AM_IS_TRANS_WIN_STALLED(amDl))
1956 printf("\n Window stalled \n");
1957 gRlcStats.amRlcStats.numRlcAmCellWinStall++;
1962 hdrEstmt = fixedHdrSz;
1964 if (sdu->mode.am.isSegmented)
1966 /* Adding two byte for SO */
1969 /* Eliminate MAC header */
1970 /* ccpu00135743 : Fix for MAC Hdr size calculation */
1971 /*5GNR: value of mac hdr length field changed to 8/16bits */
1972 pduSz = KW_MIN(macGrntSz, (sdu->sduSz + hdrEstmt));
1973 hdrEstmt += (pduSz < 255) ? KW_MAC_HDR_SZ2 : KW_MAC_HDR_SZ3;
1975 macGrntSz -= hdrEstmt;
1976 /* kw005.201 Check for PDU Size is large enough.
1977 * Fix for ccpu00118973
1984 /* Dont create new txBuf for segmented SDU */
1985 if (!sdu->mode.am.isSegmented)
1988 RLC_ALLOC_WC(gCb,txBuf, sizeof(KwTx));
1990 cmLListInit(&txBuf->pduLst);
1992 #if (ERRCLASS & ERRCLS_ADD_RES)
1996 SRegInfoShow(gCb->init.region, &avblMem);
1997 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1998 "Memory allocation failed UEID:%d CELLID:%d",
2000 rbCb->rlcId.cellId);
2003 #endif /* ERRCLASS & ERRCLS_RES */
2005 kwUtlStoreTxBuf(amDl->txBufLst, txBuf, amDl->txNext);
2009 txBuf = kwUtlGetTxBuf(amDl->txBufLst, amDl->txNext);
2012 RLC_ALLOC_WC(gCb,pduInfo, sizeof(RlcDlPduInfo));
2013 #if (ERRCLASS & ERRCLS_ADD_RES)
2014 if (pduInfo == NULLP)
2017 SRegInfoShow(gCb->init.region, &avblMem);
2018 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
2019 "Memory allocation failed UEID:%d CELLID:%d",
2021 rbCb->rlcId.cellId);
2024 #endif /* ERRCLASS & ERRCLS_RES */
2026 /*Initialize DL segment structure */
2027 pduInfo->lstEnt.next = NULLP;
2028 pduInfo->lstEnt.prev = NULLP;
2029 pduInfo->lstEnt.node = NULLP;
2031 pduInfo->pdu = NULLP;
2032 pduInfo->amHdr.dc = 0;
2033 pduInfo->amHdr.p = 0;
2034 pduInfo->amHdr.si = 0;
2035 pduInfo->amHdr.so = 0;
2037 pduInfo->amHdr.sn = amDl->txNext;
2039 if (macGrntSz >= sdu->sduSz)
2043 /* Update Framing Info */
2044 if (sdu->mode.am.isSegmented)
2046 /*5GNR RLC: SN should be same for all segment of a SDU*/
2047 pduInfo->amHdr.sn = sdu->mode.am.sn;
2048 pduInfo->amHdr.si = KW_SI_LAST_SEG; /* binary 10 */
2049 pduInfo->amHdr.so = sdu->actSz - sdu->sduSz;
2050 sdu->mode.am.isSegmented = FALSE;
2053 gRlcStats.amRlcStats.numRlcAmCellSduTx++;
2054 //printf("\n 5GNRLOG: last segment of lcId %d SduId %u So %u macGrntSz %u sduActSz %u sdu->sduSz %u\n",
2055 // rbCb->lch.lChId, sdu->mode.am.sduId, pduInfo->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
2059 gRlcStats.amRlcStats.numRlcAmCellSduTx++;
2061 amHdr = &pduInfo->amHdr;
2062 /* Create PDU with hdr and data */
2063 kwAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
2065 //printf("\n Segmentation not required case: numPdu %d pdu %p \n",kwDatReq->pduInfo.numPdu, pdu);
2067 #ifdef LTE_L2_MEAS_RLC
2068 kwUtlUpdSduSnMap(rbCb, sdu, kwDatReq, TRUE);
2069 #endif /* LTE_L2_MEAS */
2071 /* kw005.201 ccpu00117318, updating the statistics */
2072 kwUtlIncrementKwuStsSduTx(gCb->u.dlCb->kwuDlSap + rbCb->kwuSapId);
2074 if(KW_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb))
2078 *sduIdx = dlIpThPut->lastSduIdx;
2082 KW_GETSDUIDX(*sduIdx);
2085 kwUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
2086 kwUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
2087 sdu->mode.am.sduId, newIdx);
2088 /* Update the arrival time for each SDU */
2090 if ( lchInfo.numSdus < KW_L2MEAS_SDUIDX)
2092 lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime;
2097 sduMap.sduSz = sdu->sduSz;
2102 * Allocate buffer for next PDU
2103 * Remove the segmented portion from SDUQ
2104 * Calculate the hdr with LI for SDU */
2106 Buffer *remSeg = NULLP;
2108 //printf("\n SDU segmentation case: numPdu %d pdu %p \n", kwDatReq->pduInfo.numPdu, pdu);
2110 if(KW_MEAS_IS_DL_IP_MEAS_ON_FOR_RB(gCb,rbCb) ||
2111 KW_MEAS_IS_DL_DELAY_MEAS_ON_FOR_RB(gCb,rbCb) ||
2112 KW_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb) )
2114 /* If actual size of the sdu is equal to msgLen
2115 * then it is first segment of the SDU */
2116 if(sdu->actSz == sdu->sduSz)
2118 KW_GETSDUIDX(*sduIdx);
2123 *sduIdx = dlIpThPut->lastSduIdx;
2125 kwUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
2126 kwUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
2127 sdu->mode.am.sduId, newIdx);
2128 if(KW_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb))
2130 /* If actual size of the sdu is equal to msgLen
2131 * then it is first segment of the SDU */
2132 if(sdu->actSz == sdu->sduSz)
2140 /* Segment the SDU to the size of the PDU and update header Info */
2141 SSegMsg(sdu->mBuf, macGrntSz, &remSeg);
2145 /* Update SI and SN */
2146 if (sdu->mode.am.isSegmented)
2148 /*5GNR RLC: SN should be same for all segment of a SDU.
2149 * Sdu was already segmented and segmenting again*/
2150 pduInfo->amHdr.sn = sdu->mode.am.sn;
2151 pduInfo->amHdr.si = KW_SI_MID_SEG; /* binary 11 */
2152 pduInfo->amHdr.so = sdu->actSz - sdu->sduSz;
2154 //printf("\n 5GNRLOG: mid segment of lcId %d SduId %u So %u macGrntSz %u sduActSz %u sdu->sduSz %u\n",
2155 // rbCb->lch.lChId, sdu->mode.am.sduId, txBuf->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
2159 /*5GNR RLC: This means it is the first*/
2160 pduInfo->amHdr.si = KW_SI_FIRST_SEG; /* binary 01 */
2161 /*5GNR_RLC: Store SN so that in sub-seqent SDU segments will use this SN*/
2162 sdu->mode.am.sn = pduInfo->amHdr.sn;
2163 pduInfo->amHdr.so = 0;
2165 //printf("\n 5GNRLOG: First segment of lcId %d SduId %u So %u macGrntSz %u sduActSz %u sdu->sduSz %u\n",
2166 // rbCb->lch.lChId, sdu->mode.am.sduId, txBuf->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
2169 amHdr = &pduInfo->amHdr;
2170 /* Create PDU with hdr and data */
2171 kwAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
2173 sdu->mode.am.isSegmented = TRUE;
2174 sdu->sduSz -= macGrntSz;
2175 sduMap.sduSz = macGrntSz;
2177 #ifdef LTE_L2_MEAS_RLC
2178 kwUtlUpdSduSnMap(rbCb, sdu, kwDatReq, FALSE);
2179 #endif /* LTE_L2_MEAS */
2185 /* Update bo for boReport */
2186 amDl->bo -= sduMap.sduSz;
2190 /* Update pduInfo */
2191 kwDatReq->pduInfo.mBuf[kwDatReq->pduInfo.numPdu] = pdu;
2192 kwDatReq->pduInfo.numPdu++;
2194 /* kw005.201 ccpu00117318, updating the statistics */
2195 gCb->genSts.pdusSent++;
2196 gRlcStats.amRlcStats.numRlcAmCellSduBytesTx = gRlcStats.amRlcStats.numRlcAmCellSduBytesTx + sduMap.sduSz;
2197 /* Update the RLC Tx buffer with the new PDU info */
2198 KW_MEM_CPY(&pduInfo->sduMap, &sduMap, sizeof(KwSduMap));
2201 macGrntSz -= sduMap.sduSz;
2202 /* Get next sdu for assembly */
2203 KW_LLIST_NEXT_SDU(amDl->sduQ, sdu);
2205 } /*End of pduSz loop */
2207 kwDatReq->pduSz = macGrntSz;
2208 /* Updating nxtTx to sdu in the Q */
2213 if(KW_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) &&
2214 (rbCb->rlcId.rbType == CM_LTE_DRB))
2218 l2MeasTb = kwUtlGetCurMeasTb(gCb, rbCb);
2219 kwUtlUpdateBurstSdus(gCb, rbCb, &contSduLst, dataVol, *totMacGrant);
2220 if ((lchInfo.numSdus != 0) && (l2MeasTb != NULLP))
2222 for (lchIdx = 0; ((lchIdx < l2MeasTb->numLchInfo)
2223 && (lchIdx < KW_MAX_ACTV_DRB )); lchIdx++)
2225 if (l2MeasTb->lchInfo[lchIdx].lcId == rbCb->lch.lChId)
2227 /* Lch Info already added in Retx procedure */
2231 if (lchIdx < KW_MAX_ACTV_DRB)
2233 if (lchIdx == l2MeasTb->numLchInfo)
2235 l2MeasTb->lchInfo[lchIdx].lcId = rbCb->lch.lChId;
2236 l2MeasTb->lchInfo[lchIdx].numSdus = 0;
2237 l2MeasTb->numLchInfo++;
2239 dstLchInfo = &l2MeasTb->lchInfo[lchIdx];
2240 currSduIdx = l2MeasTb->lchInfo[lchIdx].numSdus;
2241 while ((numSdus < lchInfo.numSdus) && (currSduIdx < KW_L2MEAS_SDUIDX))
2243 dstLchInfo->sduInfo[currSduIdx].arvlTime = lchInfo.sduInfo[numSdus].arvlTime;
2244 dstLchInfo->sduInfo[currSduIdx].isRetxPdu = FALSE;
2248 l2MeasTb->lchInfo[lchIdx].numSdus += numSdus;
2251 /* Fix Klock warning */
2252 if(l2MeasTb != NULLP)
2254 l2MeasTb->txSegSduCnt += segSduCnt;
2257 *totMacGrant -= (oldBo - amDl->bo);
2260 if(discSduInfo->numSduIds != 0)
2262 /* Sap control block */
2263 KwUiKwuDiscSduCfm(&kwuSap->pst, kwuSap->suId, discSduInfo);
2267 RLC_SHRABL_STATIC_BUF_FREE(kwuSap->pst.region, kwuSap->pst.pool, discSduInfo, sizeof(KwuDiscSduInfo));
2272 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
2273 "kwAssembleSdus: BO after assembly = %ld UEID:%d CELLID:%d",
2276 rbCb->rlcId.cellId);
2278 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
2279 "kwAssembleSdus: BO after assembly = %d UEID:%d CELLID:%d",
2282 rbCb->rlcId.cellId);
2289 * @brief Private handler to check if the poll bit needs to be set for data PDU
2292 * Its a private function called by kwProcessSdus, to checks if the
2293 * polling bit needs to be set for any RLC data PDU and updates the
2295 * - For the new PDUs, if the counters exceed the configured
2296 * pduWoPoll/byteWoPoll values, return poll bit.
2297 * - For the PDUs/portion of PDUs, if the SDU list / retxBuf is
2298 * empty, return poll bit.
2299 * - Update the pollPdu, pollByte counters and Poll_SN; start staProhTmr
2301 * @param[in] rCb RLC instance control block
2302 * @param[in] rbCb RB control block
2303 * @param[in] newPdu Flag to indicate if its a new AMD PDU.
2304 * @param[in] bufSz Length of the PDU
2307 * -# 1 - To set the poll bit
2308 * -# 0 - Poll bit is not set
2312 PRIVATE Bool kwAmmDlCheckAndSetPoll
2320 PRIVATE Bool kwAmmDlCheckAndSetPoll(gCb, rbCb, newPdu, bufSz)
2327 Bool pollBit = FALSE;
2328 KwAmDl *amDl = &(rbCb->m.amDl);
2330 TRC2(kwAmmDlCheckAndSetPoll)
2333 /* If it's a new PDU increment PDU without poll and bytes without poll
2334 and check if they cross the configured number of poll pdu and poll bytes*/
2338 /* Patch kw004.201 */
2339 amDl->byteWoPoll += bufSz;
2341 if (((amDl->pollPdu != -1) && (amDl->pduWoPoll >= amDl->pollPdu)) ||
2342 ((amDl->pollByte != -1) && (amDl->byteWoPoll >= amDl->pollByte)))
2348 /* Check if both tx/retx buffer are empty or if tx window is stalled */
2349 if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) ||
2350 KW_AM_IS_TRANS_WIN_STALLED(amDl))
2357 amDl->pduWoPoll = 0;
2358 amDl->byteWoPoll = 0;
2360 amDl->pollSn = (amDl->txNext - 1) & amDl->snModMask;
2362 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
2363 "kwAmmDlCheckAndSetPoll: Poll SN = %d UEID:%d CELLID:%d",
2366 rbCb->rlcId.cellId);
2368 /* kw005.201: Fix for poll retransmission timer.
2369 * Timer is stopped if it is already running and
2370 * then starting the timer. Fixes crs
2371 * ccpu00117216 and ccpu00118284 .
2373 if( TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMDL_POLL_RETX_TMR) )
2375 kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMDL_POLL_RETX_TMR);
2378 kwStartTmr(gCb,(PTR)rbCb, KW_EVT_AMDL_POLL_RETX_TMR);
2385 * @brief Private handler to create AMD PDU
2388 * This function constructs header and concatenate it with the data for
2389 * the PDU. It also updates the txBuf with the created PDU.
2391 * @param[in] gCB RLC instance control block
2392 * @param[in] rbCb Downlink RB control block
2393 * @param[in] amHdr AM header
2394 * @param[in] RlcDlPduInfo Pointer to PduInfo
2395 * @param[in] pdu PDU buffer
2401 PRIVATE Void kwAmmCreatePdu
2406 RlcDlPduInfo *pduInfo,
2410 PRIVATE Void kwAmmCreatePdu(gCb, rbCb, pduInfo, amHdr, pdu)
2414 RlcDlPduInfo *pduInfo;
2418 U8 hdr[KW_MAX_HDRSZ];
2422 KwAmDl *amDl = &(rbCb->m.amDl);
2424 TRC2(kwAmmCreatePdu)
2428 amHdr->sn = amDl->txNext;
2430 /*5GNR RLC: Increment txNext only if no segmentation of it is a last segment */
2431 if((!amHdr->si) || (amHdr->si == KW_SI_LAST_SEG))
2433 //printf("\n 5GNRLOG: no segment/last seg SDU with lcId %d Sn %u txNext %u So %u\n",
2434 // rbCb->lch.lChId, amHdr->sn, amDl->txNext, amHdr->so);
2435 amDl->txNext = (amDl->txNext + 1) & amDl->snModMask;
2438 /* Update hdr Info */
2439 SFndLenMsg(pdu, &pduSz);
2441 /* passing newPDU = TRUE*/
2442 amHdr->p = kwAmmDlCheckAndSetPoll(gCb,rbCb, TRUE, pduSz);
2444 /* Construct header with the available hdr Info, set isSegment to FALSE */
2445 kwConstructAmHdr(amHdr, hdr, amDl->snLen, &idx);
2447 /* Concatenate hdr and data */
2448 SAddPreMsgMultInOrder(hdr, idx+1, pdu);
2450 txBuf = kwUtlGetTxBuf(amDl->txBufLst, amHdr->sn);
2451 kwCpyMsg(gCb,pdu,&(pduInfo->pdu));
2452 pduInfo->pduSz = pduSz;
2453 pduInfo->hdrSz = idx+1;
2455 /*Update estHdrSz. deduct current hdrSz */
2456 amDl->estHdrSz -= pduInfo->hdrSz;
2457 /* Reestimate estHdrSz for mid and last seg */
2460 amDl->estHdrSz += ((amHdr->si == KW_SI_MID_SEG)? pduInfo->hdrSz : (pduInfo->hdrSz + 2));
2463 cmLListAdd2Tail(&txBuf->pduLst, &pduInfo->lstEnt);
2464 pduInfo->lstEnt.node = (PTR)pduInfo;
2466 gCb->genSts.bytesSent += pduSz;
2472 * @brief Private handler to remove the retx PDU from the rbCb
2475 * This function releases a retx PDU stored on DL portion of rbCb.
2476 * It also updates the BO if wtForAck flag is not set which implies
2477 * that it is not sent out yet.
2479 * @param[in] gCb RLC instance control block
2480 * @param[in] retx retransmit PDU to be removed
2481 * @param[in] rbCb Radio Bearer Control Block
2487 PRIVATE Void kwRemRetxPdu
2494 PRIVATE Void kwRemRetxPdu(gCb, rbCb, retx)
2502 cmLListDelFrm(&AMDL.retxLst, &retx->lstEnt);
2504 if( AMDL.retxLst.count == 0)
2506 AMDL.nxtRetx = NULLP;
2509 if(retx->pendingReTrans == TRUE)
2511 AMDL.retxBo -= retx->segSz;
2512 AMDL.estHdrSz -= retx->hdrSz;
2515 kwUtlAddReTxPduToBeFreedQueue(gCb, retx);
2516 kwUtlRaiseDlCleanupEvent(gCb);
2522 * @brief Private handler to mark a retx PDU for further retransmission
2525 * This function sets a retx PDU that has not been ACKed in the
2526 * received Status PDU for futher retransmission. If the retransmission
2527 * limit is reached, it releases the retx PDU and informs the higher
2528 * layers about the same.
2530 * @param[in] gCb RLC instance control block
2531 * @param[in] retx retransmit PDU to be removed
2532 * @param[in] rbCb Radio Bearer Control Block
2538 PRIVATE Void kwAmmDlMarkPduForReTx
2545 PRIVATE Void kwAmmDlMarkPduForReTx(*gCb, rbCb, retx)
2551 TRC2(kwAmmDlMarkPduForReTx)
2552 if (AMDL.maxReTxReached == TRUE)
2557 if(retx->pendingReTrans == FALSE)
2559 retx->pendingReTrans = TRUE;
2562 AMDL.retxBo += retx->segSz;
2563 AMDL.estHdrSz += retx->hdrSz;
2565 if (retx->retxCnt > AMDL.maxRetx)
2567 /* RLC_DL_MAX_RETX fix */
2568 /* Marking the RB stalled for DL scheduling. This is to avoid unnecessary */
2569 /* preparation of RLC PDUs and adding the same to Tx Buffer */
2570 /* This condition is to avoid sending StaIndication more than once */
2571 if (TRUE != rbCb->m.amDl.maxReTxReached)
2573 rbCb->m.amDl.maxReTxReached = TRUE;
2574 rbCb->m.amDl.bo = 0;
2575 rbCb->m.amDl.cntrlBo = 0;
2576 rbCb->m.amDl.retxBo = 0;
2577 /* Sending BO update to SCH */
2578 kwUtlSndDStaRsp(gCb, rbCb, 0,0,0,0);
2579 kwAmmSndStaInd(gCb, rbCb, retx);
2580 gRlcStats.amRlcStats.numDLMaxRetx++;
2583 kwRemRetxPdu(gCb,rbCb, retx);
2589 if (AMDL.nxtRetx == NULLP)
2591 AMDL.nxtRetx = retx;
2594 gRlcStats.amRlcStats.numDLRetransPdus++;
2602 * @brief Private handler to check if SDU is completely deliverd and
2603 * send higher layers data confirmation
2606 * This function sends higher layers data confirmation for SDUs which
2607 * have been successfully delivered to the peer RLC entity.
2609 * @param[in] gCb RLC instance control block
2610 * @param[in] rbCb Radio Bearer Control Block
2611 * @param[in] sduLst List of SDUs that were part of the PDU
2612 * @param[in] numSdu Number of SDUs in the list
2618 PRIVATE Void kwAmmDlCheckIsSDUDelivered
2623 KwuDatCfmInfo **datCfm
2626 PRIVATE Void kwAmmDlCheckIsSDUDelivered(gCb, rbCb, sduMap, datCfm)
2630 KwuDatCfmInfo **datCfm;
2635 TRC2(kwAmmDlCheckIsSDUDelivered)
2639 sdu->mode.am.rcvdSz += sduMap->sduSz;
2641 /* send a dat cfm if all the bytes of the sdu have been received */
2642 if (sdu->mode.am.rcvdSz == sdu->actSz)
2644 /* Send DatCfm for this sdu */
2645 if((*datCfm)->numSduIds < KWU_MAX_DAT_CFM)
2647 (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2651 /* This is an error that should never happen, we should resize
2652 * the #define to a larger value or check why we need to
2653 * send so many confirms in one go
2654 * Confrims to PDCP are being dropped in this case
2657 kwuSap = gCb->u.dlCb->kwuDlSap + KW_UI_PDCP;
2658 KwUiKwuDatCfm(&kwuSap->pst, kwuSap->suId, *datCfm);
2660 RLC_SHRABL_STATIC_BUF_ALLOC(kwuSap->pst.region, kwuSap->pst.pool, *datCfm, sizeof(KwuDatCfmInfo));
2662 #if (ERRCLASS & ERRCLS_ADD_RES)
2663 if (*datCfm == NULLP)
2665 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
2666 "Memory allocation failed UEID:%d CELLID:%d",
2668 rbCb->rlcId.cellId);
2671 #endif /* ERRCLASS & ERRCLS_RES */
2673 (*datCfm)->numSduIds = 0;
2674 (*datCfm)->rlcId = rbCb->rlcId;
2675 /* ccpu00135618: say total 1026 sduIds to copy the 1025 sduId after
2676 * new allocation of datCfm */
2677 (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2680 /* Remove SDU from the sduQ */
2681 cmLListDelFrm(&AMDL.sduQ, &sdu->lstEnt);
2682 kwUtlAddSduToBeFreedQueue(gCb, sdu);
2683 kwUtlRaiseDlCleanupEvent(gCb);
2690 * @brief Private handler to mark a PDU successful.
2693 * This function is called when we receive a STATUS pdu that marks
2694 * a PDU as successful. It releases the PDU from RLC entity and
2695 * informs PDCP of successful SDUs delivered as a result of this PDU.
2697 * @param[in] gCb RLC instance control block
2698 * @param[in] rbCb Radio Bearer Control Block
2699 * @param[in] sn SN that is successfully delivered to the peer
2705 PRIVATE Void kwAmmDlProcessSuccessfulTxPdu
2710 KwuDatCfmInfo **datCfm
2713 PRIVATE Void kwAmmDlProcessSuccessfulTxPdu(gCb, rbCb, sn, datCfm)
2717 KwuDatCfmInfo **datCfm;
2720 TRC2(kwAmmDlProcessSuccessfulTxPdu)
2723 KwTx *txBuf = kwUtlGetTxBuf(AMDL.txBufLst, sn);
2729 pduNode = txBuf->pduLst.first;
2732 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(pduNode->node);
2733 kwAmmDlCheckIsSDUDelivered(gCb,
2737 pduNode = pduNode->next;
2740 kwUtlAddTxPduToBeFreedQueue(gCb, txBuf);
2741 kwUtlRaiseDlCleanupEvent(gCb);
2742 /* so that it is not processed again */
2743 kwUtlRemovTxBuf(AMDL.txBufLst, txBuf, gCb);
2749 * @brief Handler to send Status Indication to PDCP
2752 * This function is used to send status indication to PDCP when the
2753 * maximum retransmission threshold value is reached for a PDU.
2755 * @param[in] gCb RLC instance control block
2756 * @param[in] rbCb RB control block
2757 * @param[in] retx The PDU/segment that failed max re-transmissions
2763 PRIVATE Void kwAmmSndStaInd
2770 PRIVATE Void kwAmmSndStaInd(gCb, rbCb, retx)
2776 KwuStaIndInfo *staInd;
2779 TRC2(kwAmmSndStaInd);
2782 /* Sap control block */
2783 kwuSap = gCb->u.dlCb->kwuDlSap + KW_UI_PDCP;
2785 /* Allocate memory for staInd Info */
2786 RLC_SHRABL_STATIC_BUF_ALLOC(kwuSap->pst.region, kwuSap->pst.pool, staInd, sizeof(KwuStaIndInfo));
2788 #if (ERRCLASS & ERRCLS_ADD_RES)
2789 if (staInd == NULLP)
2791 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
2792 "Memory allocation failed UEID:%d CELLID:%d",
2794 rbCb->rlcId.cellId);
2797 #endif /* ERRCLASS & ERRCLS_RES */
2799 /* Fill staInd Info */
2800 KW_MEM_CPY(&staInd->rlcId, &rbCb->rlcId, sizeof(CmLteRlcId));
2803 staInd->sduId[0] = retx->sduMap.sdu->mode.am.sduId;
2807 KwUiKwuStaInd(&kwuSap->pst, kwuSap->suId, staInd);
2808 #endif /* KW_PDCP */
2814 * @brief Handler to get the next node to be retransmitted from retxLst
2817 * This function is used to get the next node to be retransmitted
2820 * @param[in] gCb RLC instance control block
2821 * @param[in] retx The PDU/segment after which to find a node to be
2828 PRIVATE Void kwGetNxtRetx
2834 PRIVATE Void kwGetNxtRetx(gCb, retx)
2845 tNode = &((*retx)->lstEnt);
2846 tNode = tNode->next;
2850 *retx = (KwRetx *)tNode->node;
2857 }while((*retx)->pendingReTrans == FALSE);
2863 * @brief Handler to process the re-establishment request received from UIM
2865 * @param[in] gCb RLC instance control block
2866 * @param[in] rlcId Identity of the RB in the UE/Cell for which
2867 * re-establishment is to be done
2868 * @param[in] rbCb Downlink RB control block (rbCb is freed in this
2875 PUBLIC Void kwAmmDlReEstablish
2882 PUBLIC Void kwAmmDlReEstablish(gCb, rlcId, rbCb)
2888 /* create a new AM DL RB, reset it and replace in the UeCb*/
2893 RLC_ALLOC(gCb, resetRb, sizeof(RlcDlRbCb));
2895 /* ccpu00135170 Removing KLOCK warning */
2896 if(resetRb == NULLP)
2901 KW_MEM_CPY(resetRb, rbCb, sizeof(RlcDlRbCb));
2902 RLC_MEM_SET(&resetRb->m.amDl, 0 , sizeof(KwAmDl));
2904 /* AGHOSH changes start */
2905 /* restore the old AM values */
2906 newAmDl = &resetRb->m.amDl;
2907 oldAmDl = &rbCb->m.amDl;
2909 newAmDl->pollPdu = oldAmDl->pollPdu;
2910 newAmDl->pollByte = oldAmDl->pollByte;
2911 newAmDl->maxRetx = oldAmDl->maxRetx;
2912 newAmDl->snLen = oldAmDl->snLen;
2913 newAmDl->snModMask = oldAmDl->snModMask;
2914 newAmDl->pollRetxTmrInt = oldAmDl->pollRetxTmrInt;
2915 rbCb->boUnRprtdCnt = (U32)0;
2916 rbCb->lastRprtdBoToMac = (U32)0;
2917 cmInitTimers(&(resetRb->m.amDl.pollRetxTmr), 1);
2918 /* AGHOSH changes end */
2920 if (ROK != kwDbmFetchDlUeCb(gCb,rlcId.ueId, rlcId.cellId, &ueCb))
2922 RLOG_ARG2(L_ERROR,DBG_CELLID, rlcId.cellId,
2923 "UeId [%d]: UeCb not found RBID;%d",
2929 if(rlcId.rbType == CM_LTE_SRB)
2931 ueCb->srbCb[rlcId.rbId] = resetRb;
2935 ueCb->drbCb[rlcId.rbId] = resetRb;
2937 /* update into the logical channel array also */
2938 ueCb->lCh[rbCb->lch.lChId - 1].dlRbCb = resetRb;
2940 if((resetRb->rlcId.rbType == CM_LTE_SRB)
2941 &&(resetRb->rlcId.rbId == 1))
2943 /* To stop the traffic on SRB2 and other DRBs*/
2944 rlcDlUtlSetReestInProgressForAllRBs(gCb, ueCb);
2948 rlcDlUtlSetReestInProgressForRB(gCb, resetRb);
2951 /* allocate the TX array again */
2955 resetRb->m.amDl.txBufLst,
2956 (KW_TX_BUF_BIN_SIZE * sizeof(CmLListCp)));
2957 for(hashIndex = 0; hashIndex < KW_TX_BUF_BIN_SIZE; hashIndex++)
2959 cmLListInit(&(resetRb->m.amDl.txBufLst[hashIndex]));
2962 /* send the old rb of deletion */
2963 kwAmmFreeDlRbCb(gCb,rbCb);
2966 /* TODO: for now we are re-settting the re-establishment flag here
2967 this needs to be fixed
2968 There should be a proper intreface to resume the RBs */
2969 if(rlcId.rbType == CM_LTE_SRB)
2971 rlcDlUtlResetReestInProgress(ueCb->srbCb[rlcId.rbId]);
2975 rlcDlUtlResetReestInProgress(ueCb->drbCb[rlcId.rbId]);
2982 * @brief Handler to discard a SDU.
2985 * This function is used to discard a SDU after receiving
2986 * the Discard Request from UIM. The SDU is discarded if its
2987 * available and is not mapped to any PDU yet.
2989 * @param[in] gCb RLC instance control block
2990 * @param[in] rbCb RB control block
2991 * @param[in] sduId Sdu ID of the SDU to be discarded
2994 * -# ROK In case of successful discard
2995 * -# RFAILED In case the SDU is not found or already mapped
2998 PUBLIC S16 kwAmmDiscSdu
3005 PUBLIC S16 kwAmmDiscSdu(gCb, rbCb, sduId)
3016 * @brief Handler for Poll retransmit timer expiry
3019 * This function is used to handle events upon expiry of Poll
3022 * @param[in] gCb RLC instance control block
3023 * @param[in] rbCb Downlink RB control block
3028 PUBLIC Void kwAmmPollRetxTmrExp
3034 PUBLIC Void kwAmmPollRetxTmrExp(gCb, rbCb)
3040 KwAmDl *amDl = &(rbCb->m.amDl);
3043 TRC2(kwAmmPollRetxTmrExp);
3046 /* kw003.201 - Correcting the logic for determmining whether to do */
3047 /* any transmission of PDU. As per the spec section */
3048 /* 5.2.2.3, if there is any to transmit or retransmit, */
3049 /* do nothing. Else, pick up the VT(S) -1 for retx */
3050 /* We have nothing to transmit if window is stalled or */
3051 /* there are no SDUs to be transmitted or if there are */
3052 /* PDUs to be retransmitted. */
3053 if(CM_LTE_SRB == rbCb->rlcId.rbType)
3055 gRlcStats.amRlcStats.numDLPollTimerExpiresSrb++;
3059 gRlcStats.amRlcStats.numDLPollTimerExpiresDrb++;
3062 if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) ||
3063 KW_AM_IS_TRANS_WIN_STALLED(amDl))
3065 sn = (amDl->txNext - 1) & amDl->snModMask;
3066 txBuf = kwUtlGetTxBuf(amDl->txBufLst, sn);
3070 kwAmmDlMoveFrmTxtoRetxBuffer(gCb,amDl, &retx, sn);
3072 if (AMDL.nxtRetx == NULLP)
3074 AMDL.nxtRetx = retx;
3077 kwAmmSendDStaRsp(gCb, rbCb, &AMDL);
3080 /* Get the last node in retxLst */
3081 KW_LLIST_LAST_RETX(amDl->retxLst, retx);
3083 /* Unset wtForAck flag for the NACK PDUs */
3086 kwAmmDlMarkPduForReTx(gCb, rbCb, retx);
3087 kwAmmSendDStaRsp(gCb, rbCb, &AMDL);
3095 * @brief Handler to update Acks for the remaining PDUs after the last accessed
3099 * This function is used to handle ACKs for the PDUs remaining after the
3100 * last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and
3101 * sends DatCfm to PDCP for the same.
3103 * @param[in] gCb RLC instance control block
3104 * @param[in] rbCb Downlink Radio Bearer control block
3105 * @param[in] mAckSn The ACK SN after doing the base modulus
3106 * @param[in] rextNode Next node in the re-transmission buffer
3113 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForAckSn
3119 KwuDatCfmInfo **datCfm
3122 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForAckSn(gCb, rbCb, mAckSn, retxNode, datCfm)
3127 KwuDatCfmInfo **datCfm;
3135 TRC2(kwAmmDlUpdateTxAndReTxBufForAckSn);
3137 /* Remove pdus/segs from retxLst */
3140 retx = (KwRetx *)(retxNode->node);
3141 retxNode = retxNode->next;
3142 MODAMT(retx->amHdr.sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3145 kwAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
3149 /* For the remaining; pdus not acknowldeged by the NACK_SN but being
3150 acknowledged by the ACK_SN*/
3151 /* start from the starting of the transmission window and remove till just
3153 mSn = 0; /* same as MODAMT(AMDL.txNextAck, mSn, AMDL.txNextAck);*/
3154 sn = AMDL.txNextAck;
3157 txBuf = kwUtlGetTxBuf(AMDL.txBufLst, sn);
3160 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
3161 "kwAmmDlUpdateTxAndReTxBufForAckSn: ACK for PDU "
3162 "with sn = %ld UEID:%ld CELLID:%ld",
3165 rbCb->rlcId.cellId);
3167 kwAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
3170 sn = (sn + 1) & AMDL.snModMask;
3171 MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3178 * @brief Handler to update Acks for the remaining PDUs after the last accessed
3182 * This function is used to handle ACKs for the PDUs remaining after the
3183 * last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and
3184 * sends DatCfm to PDCP for the same.
3186 * @param[in] gCb RLC instance control block
3187 * @param[in] rbCb Downlink Radio Bearer control block
3188 * @param[in] mAckSn The ACK SN after doing the base modulus
3189 * @param[in] rextNode Next node in the re-transmission buffer
3195 PRIVATE Void kwAmmDlUpdTxAndReTxBufForLessThanNackSn
3202 KwuDatCfmInfo **datCfm
3205 PRIVATE Void kwAmmDlUpdTxAndReTxBufForLessThanNackSn(gCb, rbCb, sn, mNackSn, retxNode, datCfm)
3211 KwuDatCfmInfo **datCfm;
3218 TRC2(kwAmmDlUpdTxAndReTxBufForLessThanNackSn);
3222 retx = (KwRetx *)((*retxNode)->node);
3223 MODAMT(retx->amHdr.sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3226 (*retxNode) = (*retxNode)->next;
3227 kwAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
3235 /* Remove all pdus with SN < NACK_SN from the transmission buffer */
3236 MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3237 while (mSn < mNackSn)
3239 /* this if check seems redundant,why should mSn ever be mTxSn
3240 (which actually is VT(A) */
3241 txBuf = kwUtlGetTxBuf(AMDL.txBufLst, sn);
3242 if ((txBuf != NULLP))
3244 RLOG_ARG3(L_DEBUG,DBG_RBID, rbCb->rlcId.rbId,
3245 "kwHndlStaRsp: Handle ACK (sn = %d) UEID:%d CELLID:%d",
3248 rbCb->rlcId.cellId);
3250 /* Remove pdus from txBuf */
3251 kwAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
3254 sn = (sn + 1) & AMDL.snModMask;
3255 MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3263 * @brief Handler to form construct AM header
3266 * This function is used to construct am header with the available header
3269 * @param[in] gCb RLC instance control block
3270 * @param[in] amHdr AM Header
3271 * @param[in] isSeg Check for Segmentation of PDU
3272 * @param[in] hdr Header field
3273 * @param[in] idx Index
3279 PRIVATE Void kwConstructAmHdr
3287 PRIVATE Void kwConstructAmHdr(amHdr, hdr, snLen, idx)
3294 TRC2(kwConstructAmHdr);
3297 hdr[0] = KW_DATA_BITMASK;
3299 hdr[0] = hdr[0] | (amHdr->p << 6);
3300 hdr[0] = hdr[0] | ((amHdr->si & 0x3) << 4);
3301 if(snLen == KW_AM_CFG_12BIT_SN_LEN)
3303 hdr[0] = hdr[0] | (U8)((amHdr->sn & 0xF00) >> 8);
3304 hdr[1] = (U8)(amHdr->sn & 0x0FF);
3309 hdr[0] = hdr[0] | (U8)((amHdr->sn & 0x30000) >> 16);
3310 hdr[1] = (U8)((amHdr->sn & 0xFF00) >> 8);
3312 hdr[2] = (U8)(amHdr->sn & 0xFF);
3316 if ((amHdr->si == KW_SI_MID_SEG) || (amHdr->si == KW_SI_LAST_SEG))
3319 hdr[(*idx)] = (U8)((amHdr->so & 0xFF00)>> 8);
3321 hdr[(*idx)] = (U8)(amHdr->so & 0xFF);
3328 * @brief This function adds a retx PDU to list of retx PDUs
3331 * kw003.201 - Poll expiry may cause an SN to be added to retx
3332 * out of sequence and hence all additions to retx
3333 * must validate that they are added in sequence
3335 * @param[in] amDl AM Downlink Control Block
3336 * @param[in] retx Retransmit PDU
3342 PRIVATE Void kwAmmAddPduToRetxLst
3348 PRIVATE Void kwAmmAddPduToRetxLst(amDl, retx)
3358 TRC2(kwAmmAddPduToRetxLst);
3360 node = amDl->retxLst.last;
3361 MODAMT(retx->amHdr.sn, retxMSn, amDl->txNextAck,amDl->snModMask);
3362 while(node != NULLP)
3364 tRetx = (KwRetx *)(node->node);
3365 MODAMT(tRetx->amHdr.sn, tMSn, amDl->txNextAck,amDl->snModMask);
3377 amDl->retxLst.crnt = node;
3378 cmLListInsAfterCrnt(&amDl->retxLst, &retx->lstEnt);
3379 retx->lstEnt.node = (PTR)retx;
3383 amDl->retxLst.crnt = amDl->retxLst.first;
3384 cmLListInsCrnt(&amDl->retxLst, &retx->lstEnt);
3385 retx->lstEnt.node = (PTR)retx;
3388 if (amDl->nxtRetx == NULLP)
3390 amDl->nxtRetx = retx;
3397 * @brief Handler to Move the PDU from txBuf to re-transmission buffer
3400 * This function is used to move the PDU from the txBuf to re-transmit buffer
3402 * @param[in] gCb RLC instance control block
3403 * @param[in] amDl AM Downlink Control Block
3404 * @param[in] retx node in the reTx buffer to be moved to, allocated by
3406 * @param[in] sn SN in the tx buffer which needs to be moved
3413 PRIVATE Void kwAmmDlMoveFrmTxtoRetxBuffer
3421 PRIVATE Void kwAmmDlMoveFrmTxtoRetxBuffer(gCb, amDl, retx, sn)
3428 KwTx* txBuf = kwUtlGetTxBuf(amDl->txBufLst, sn);
3429 TRC2(kwAmmDlMoveFrmTxtoRetxBuffer);
3435 while(txBuf->pduLst.first)
3437 RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(txBuf->pduLst.first->node);
3438 RLC_ALLOC_WC(gCb,*retx, sizeof(KwRetx));
3440 #if (ERRCLASS & ERRCLS_ADD_RES)
3443 RLOG0(L_FATAL, "Memory allocation failed");
3446 #endif /* ERRCLASS & ERRCLS_RES */
3448 /* Move Sdu byte segment from TX buf to retx buf*/
3449 kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb,
3454 /* Delete node from the txBuf Pdu lst */
3455 cmLListDelFrm(&txBuf->pduLst, txBuf->pduLst.first);
3456 RLC_FREE_WC(gCb, pduInfo, sizeof(RlcDlPduInfo));
3458 /* Remove PDU from txBuf */
3459 kwUtlDelTxBuf(amDl->txBufLst, txBuf,gCb);
3468 * function to free/release the Acknowledged mode RBCB buffers
3471 * This primitive Frees the Acknowledged Mode RbCb transmission Buffer,
3472 * retransmission Buffer and reciption Buffers
3474 * @param [in] gCb - RLC instance control block
3475 * @param [in] rbCb - Downlink RB Control Block
3480 PUBLIC Void kwAmmFreeDlRbCb
3486 PUBLIC Void kwAmmFreeDlRbCb(gCb,rbCb)
3491 /* stop the re-transmission timer */
3492 if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMDL_POLL_RETX_TMR))
3494 kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMDL_POLL_RETX_TMR);
3497 /* store the entire Rb pointer */
3498 rbCb->rlsLnk.node = (PTR)rbCb;
3499 cmLListAdd2Tail(&gCb->u.dlCb->toBeFreed.rbLst, &rbCb->rlsLnk);
3502 cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.amDl.sduQ));
3504 kwUtlRaiseDlCleanupEvent(gCb);
3510 * @brief Handler to create STATUS Pdu
3513 * This function is used to create status pdu
3515 * @param[in] gCb RLC instance control block
3516 * @param[in] rbCb Downlink RB control block
3517 * @param[in] kwDatReq The data to be passed to MAC
3523 PRIVATE Void kwAmmCreateStatusPdu
3530 PRIVATE Void kwAmmCreateStatusPdu(gCb, rbCb, kwDatReq)
3536 KwSn sn; /* sequence number */
3537 KwSn ack_sn; /* Ack sequence number */
3538 Buffer *mBuf; /* control pdu buffer */
3539 MsgLen cntrlPduSz; /* control pdu size */
3540 U8 cntrlPdu[KW_MAX_CNTRL_FIELDS]; /* control pdu to be added to mBuf */
3541 KwUdxDlStaPdu *pStaPdu;
3542 U16 bytesToEncode = 0; /* bytes required to encode the STATUS PDU */
3545 KwNackInfo *kwNackInfo;
3548 TRC2(kwAmmCreateStatusPdu)
3551 pStaPdu = AMDL.pStaPdu;
3560 /* ACK SN Field will be set in the end based on available Grant */
3562 encIdx = bytesToEncode = 3; /* Num Octets before NACK SN info encoding*/
3564 ack_sn = pStaPdu->ackSn;
3566 if (rbCb->m.amDl.snLen == KW_AM_CFG_12BIT_SN_LEN)
3569 /* If alteast one NACK SN Info then set the E1 field */
3570 if (pStaPdu->nackCount)
3580 for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3582 sn = pStaPdu->nackInfo[nkCnt].sn;
3584 kwNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3586 bytesToEncode += 2; /* 2 Octets for NACK SN */
3588 /* Check if E2 : isSegment is set */
3589 if (kwNackInfo->isSegment)
3591 bytesToEncode += 4; /* 4 Octets: SOstart, SOend */
3594 /* Check if E3 : nackRange is set */
3595 if (kwNackInfo->nackRange)
3597 bytesToEncode += 1; /* 1 Octet: NACK range */
3600 /* Check if this NACK info can be accomodated in the Grant */
3601 if( kwDatReq->pduSz >= bytesToEncode)
3603 /* If there is a NACK SN before this then set its
3607 /* NACKSN E1 E2 E3 R */
3608 cntrlPdu[prevEncIdx + 1] |= 0x8;
3611 /* 12 BIT Nack SN encode */
3612 cntrlPdu[encIdx] = (sn & 0xFF0) >> 4;
3615 cntrlPdu[encIdx + 1] = (sn & 0xF) << 4;
3617 if (kwNackInfo->isSegment)
3620 cntrlPdu[encIdx + 1] |= 0x4;
3623 /* Add soStart and soEnd */
3625 cntrlPdu[encIdx + 2] = (kwNackInfo->soStart) >> 8;
3626 cntrlPdu[encIdx + 3] = kwNackInfo->soStart & 0xFF;
3629 cntrlPdu[encIdx + 4] = (kwNackInfo->soEnd) >> 8;
3630 cntrlPdu[encIdx + 5] = kwNackInfo->soEnd & 0xFF;
3633 if (kwNackInfo->nackRange)
3636 cntrlPdu[encIdx + 1] |= 0x2;
3637 if(kwNackInfo->isSegment)
3639 cntrlPdu[encIdx + 6] = kwNackInfo->nackRange;
3643 cntrlPdu[encIdx + 2] = kwNackInfo->nackRange;
3647 gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3649 /* Set ACK SN now */
3652 ack_sn = kwNackInfo->sn;
3654 /* Not even one nack can be accomodated */
3663 prevEncIdx = encIdx;
3664 encIdx = bytesToEncode;
3666 }/* Loop is done for the NackCount */
3671 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
3672 "kwAssembleCntrlInfo: ACK PDU's SN = %d"
3673 "UEID:%d CELLID:%d",
3676 rbCb->rlcId.cellId);
3678 cntrlPdu[0] |= (ack_sn & 0xF00)>> 8;
3679 cntrlPdu[1] = (U8)ack_sn;
3683 else if (rbCb->m.amDl.snLen == KW_AM_CFG_18BIT_SN_LEN)
3685 /* If alteast one NACK SN Info then set the E1 field */
3686 if (pStaPdu->nackCount)
3696 for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3698 sn = pStaPdu->nackInfo[nkCnt].sn;
3700 kwNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3702 bytesToEncode += 3; /* 3 Octets for NACK SN */
3704 /* Check if E2 : isSegment is set */
3705 if (kwNackInfo->isSegment)
3707 bytesToEncode += 4; /* 4 Octets: SOstart, SOend */
3710 /* Check if E3 : nackRange is set */
3711 if (kwNackInfo->nackRange)
3713 bytesToEncode += 1; /* 1 Octet: NACK range */
3716 /* Check if this NACK info can be accomodated in the Grant */
3717 if( kwDatReq->pduSz >= bytesToEncode)
3719 /* If there is a NACK SN before this then set its
3723 /* NACKSN E1 E2 E3 R R R */
3724 cntrlPdu[prevEncIdx + 2] |= 0x20;
3727 /* 18 BIT Nack SN encode */
3728 cntrlPdu[encIdx] = (U8)((sn & 0x3FC00) >> 10);
3731 cntrlPdu[encIdx + 1] = (U8)((sn & 0x3FC) >> 2);
3734 cntrlPdu[encIdx + 2] = (U8)((sn & 0x3)<< 6);
3736 if (kwNackInfo->isSegment)
3738 /* NACKSN E1 E2 E3 R R R */
3740 cntrlPdu[encIdx + 2] |= 0x10;
3743 /* Add soStart and soEnd */
3745 cntrlPdu[encIdx + 3] = (kwNackInfo->soStart) >> 8;
3746 cntrlPdu[encIdx + 4] = (U8)kwNackInfo->soStart;
3749 cntrlPdu[encIdx + 5] = (kwNackInfo->soEnd) >> 8;
3750 cntrlPdu[encIdx + 6] = (U8)(kwNackInfo->soEnd);
3753 if (kwNackInfo->nackRange)
3755 /* NACKSN E1 E2 E3 R R R */
3757 cntrlPdu[encIdx + 2] |= 0x08;
3759 if (kwNackInfo->isSegment)
3761 cntrlPdu[encIdx + 7] = kwNackInfo->nackRange;
3765 cntrlPdu[encIdx + 3] = kwNackInfo->nackRange;
3769 gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3771 /* Set ACK SN now */
3774 ack_sn = kwNackInfo->sn;
3776 /* Not even one nack can be accomodated */
3779 cntrlPdu[2] &= 0xFD;
3785 prevEncIdx = encIdx;
3786 encIdx = bytesToEncode;
3788 }/* Loop is done for the NackCount */
3793 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
3794 "kwAssembleCntrlInfo: ACK PDU's SN = %d"
3795 "UEID:%d CELLID:%d",
3798 rbCb->rlcId.cellId);
3801 cntrlPdu[0] |= (ack_sn & 0x3C000) >> 14;
3802 cntrlPdu[1] = (ack_sn & 0x3FC0) >> 6;
3803 cntrlPdu[2] |= (ack_sn & 0x3F)<< 2;
3810 RLOG_ARG3(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
3811 "kwAssembleCntrlInfo:Conf SN LEN %d is INVALID !!!! UEID:%d CELLID:%d",
3814 rbCb->rlcId.cellId);
3819 SGetMsg(KW_GET_MEM_REGION(gCb), KW_GET_MEM_POOL(gCb),&mBuf);
3821 mBuf = (Buffer *)kwAmmStaPduList[kwAmmStaPduListCnt++];
3823 if(kwAmmStaPduListCnt > 511)
3824 kwAmmStaPduListCnt = 0;
3827 cntrlPduSz = encIdx;
3828 SAddPstMsgMult (cntrlPdu, cntrlPduSz, mBuf);
3830 kwDatReq->pduSz -= cntrlPduSz;
3831 /* Add mBuf to AMDL.mBuf */
3837 #ifdef RLC_STA_PROC_IN_MAC/* RLC Status PDU Processing */
3839 S16 kwProcDlStatusPdu(Pst *udxPst,SuId suId,
3840 CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu);
3843 PRIVATE Void rgAmmExtractElmnt
3850 PRIVATE Void rgAmmExtractElmnt(gCb, pdu, hdrInfo)
3857 U8 pLen = hdrInfo->pLen;
3858 U8 len = (U8)hdrInfo->len;
3866 TRC2(kwAmmExtractElmnt);
3872 SRemPreMsg(&hdr, pdu);
3878 val = tHdr >> (KW_BYTE_LEN - (len));
3882 else /*if (len > 8) */
3886 val = val >> (KW_BYTE_LEN - fLen);
3887 val = val << (len - fLen);
3889 SRemPreMsg(&hdr, pdu);
3893 hdr = hdr >> (KW_BYTE_LEN - rLen);
3896 pLen = (KW_BYTE_LEN - rLen);
3900 rLen = rLen - KW_BYTE_LEN;
3902 tVal = tVal << rLen;
3905 SRemPreMsg(&hdr, pdu);
3907 hdr = hdr >> (KW_BYTE_LEN - rLen);
3910 pLen = (KW_BYTE_LEN - rLen);
3914 hdrInfo->pLen = pLen;
3925 PRIVATE Void rgAmmUlHndlStatusPdu
3935 PRIVATE Void rgAmmUlHndlStatusPdu(udxPst,suId,gCb, rbCb, cntrlPdu, fByte)
3946 KwUdxStaPdu *pStaPdu;
3947 U8 e3; /* NACK RANGE : 5GNR */
3950 U32 resrvdBitsAckSn;
3951 U32 resrvdBitsNackSn;
3954 TRC2(rgAmmUlHndlStatusPdu)
3956 KWDBGP_BRIEF(gCb, "rgAmmUlHndlStatusPdu(rbCb, cntrlPdu, fByte) \n");
3958 KW_MEM_ZERO(&hdrInfo, sizeof(KwExtHdr));
3960 /* Extract the Control PDU */
3961 hdrInfo.hdr = (*fByte << 1);
3964 /* D/C has been shifted in the calling function */
3965 if (hdrInfo.hdr & 0xE0)
3967 KWDBGP_ERROR(gCb, "rgAmmUlHndlStatusPdu: Reserved value for CPT received \n");
3971 RLC_ALLOC_SHRABL_BUF(udxPst->region,
3974 sizeof(KwUdxStaPdu));
3976 #if (ERRCLASS & ERRCLS_ADD_RES)
3977 /* Memory allocation failure can not be expected */
3984 if (rbCb->m.amDl.snLen == KW_AM_CFG_12BIT_SN_LEN)
3987 resrvdBitsAckSn = KW_STA_PDU_R_BITS_ACKSN_12BITS;
3988 resrvdBitsNackSn = KW_STA_PDU_R_BITS_NACKSN_12BITS;
3990 else if (rbCb->m.amDl.snLen == KW_AM_CFG_18BIT_SN_LEN)
3993 resrvdBitsAckSn = KW_STA_PDU_R_BITS_ACKSN_18BITS;
3994 resrvdBitsNackSn = KW_STA_PDU_R_BITS_NACKSN_18BITS;
3999 resrvdBitsAckSn = 0;
4000 resrvdBitsAckSn = 0;
4003 pStaPdu->nackCnt = 0;
4005 hdrInfo.hdr = hdrInfo.hdr << KW_CPT_LEN;
4008 hdrInfo.len = KW_SN_LEN;
4009 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4010 pStaPdu->ackSn = hdrInfo.val;
4012 /* Check if NACK Exists */
4013 hdrInfo.len = KW_E1_LEN;
4014 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4015 e1 = (U8)hdrInfo.val;
4016 KWDBGP_DETAIL(gCb, "rgAmmUlHndlStatusPdu: ACK SN = %d \n", pStaPdu->ackSn);
4018 /* Extract the Reserved Bits after ACK SN field */
4019 hdrInfo.len = resrvdBitsAckSn;
4020 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4023 /* If NACK exists in control PDU */
4024 /* For ACKs and NACKs */
4025 while (e1 && (pStaPdu->nackCnt < KW_MAX_NACK_CNT))
4027 hdrInfo.len = snLen;
4028 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4029 pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
4031 hdrInfo.len = KW_E1_LEN;
4032 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4033 e1 = (U8)hdrInfo.val;
4036 /* hdrInfo.len = KW_E1_LEN; --> previusly stored value (for e1) is
4038 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4039 /* e2 = (U8) hdrInfo.val;*/
4041 /* Store e2 value */
4042 pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (U8) hdrInfo.val;
4044 /* Extract e3 : 5GNR */
4045 /* hdrInfo.len = KW_E1_LEN; --> previusly stored value (for e1) is
4047 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4048 e3 = (U8) hdrInfo.val;
4050 /* Extract Reserved Bits after NACK SN */
4051 hdrInfo.len = resrvdBitsNackSn;
4052 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4054 /* Test for resegmentation */
4055 if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
4057 hdrInfo.len = KW_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
4058 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4059 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
4061 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4062 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = hdrInfo.val;
4065 "rgAmmUlHndlStatusPdu: soStart and soEnd = %d %d \n",
4066 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
4067 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd);
4072 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
4073 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = 0;
4076 /* NACK RANGE Field is SET */
4079 /* Extract NACK range field */
4080 hdrInfo.len = KW_NACK_RANGE_LEN;
4081 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4082 snRange = (U8)hdrInfo.val;
4084 pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
4090 gRlcStats.amRlcStats.numULStaPduRcvd++;
4091 gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
4093 /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
4094 to the last NACK SN + 1 and discard the original ACK_SN*/
4095 if(pStaPdu->nackCnt == KW_MAX_NACK_CNT)
4097 pStaPdu->ackSn = (pStaPdu->nackInfo[KW_MAX_NACK_CNT-1].sn + 1) & amDl->snModMask;
4101 /* Parse & send Status PDU to RLC-DL */
4102 //rlcUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
4103 rlcUlUdxStaUpdReq(udxPst, suId, &rbCb->rlcId, pStaPdu);
4108 PUBLIC S16 kwProcDlStatusPdu(Pst *udxPst,SuId suId,
4109 CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu)
4111 RlcDlRbCb *rbCb = NULLP;
4112 RlcDlUeCb *ueCb = NULLP;
4115 S16 retVal = RFAILED;
4117 Pst dlRlcPst = *udxPst;
4119 gCb = RLC_GET_RLCCB(1); /* DL RLC instance */
4121 if( ROK != kwDbmFetchDlUeCb(gCb,rnti,cellId,&(ueCb)))
4123 printf("\n RLC UECb Not found...\n");
4128 rbCb = ueCb->lCh[lcId - 1].dlRbCb;
4130 /* Skip if mode is not AM */
4131 if((rbCb == NULLP) || (rbCb->mode != CM_LTE_MODE_AM))
4136 if(ROK != SExamMsg((Data *)(&fByte),
4139 printf("\n Failure in Rlc Hdr SExamMsg\n");
4143 if(KW_CNTRL_PDU == ((fByte & KW_DC_POS) >> KW_DC_SHT))
4145 SRemPreMsg(&temp, rlcSdu);
4146 dlRlcPst.selector = 1;/* LWLC*/
4147 rgAmmUlHndlStatusPdu(&dlRlcPst,suId,gCb, rbCb, rlcSdu, &fByte);
4161 /********************************************************************30**
4164 **********************************************************************/