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 "envopt.h" /* environment options */
43 #include "envdep.h" /* environment dependent */
44 #include "envind.h" /* environment independent */
46 #include "gen.h" /* general */
47 #include "ssi.h" /* system services */
48 #include "cm5.h" /* common timer defines */
49 #include "cm_tkns.h" /* common tokens defines */
50 #include "cm_mblk.h" /* common memory allocation library defines */
51 #include "cm_llist.h" /* common link list defines */
52 #include "cm_hash.h" /* common hash list defines */
53 #include "cm_lte.h" /* common LTE defines */
54 #include "lkw.h" /* LKW defines */
55 #include "ckw.h" /* CKW defines */
56 #include "kwu.h" /* KWU defines */
57 #include "rgu.h" /* RGU defines */
58 #include "kw_err.h" /* Err defines */
59 #include "kw_env.h" /* RLC environment options */
61 #include "kw.h" /* RLC defines */
66 /* extern (.x) include files */
67 #include "gen.x" /* general */
68 #include "ssi.x" /* system services */
69 #include "cm5.x" /* common timer library */
70 #include "cm_tkns.x" /* common tokens */
71 #include "cm_mblk.x" /* common memory allocation */
72 #include "cm_llist.x" /* common link list */
73 #include "cm_hash.x" /* common hash list */
74 #include "cm_lte.x" /* common LTE includes */
75 #include "cm_lib.x" /* common memory allocation library */
76 #include "lkw.x" /* LKW */
77 #include "ckw.x" /* CKW */
78 #include "kwu.x" /* KWU */
79 #include "rgu.x" /* RGU */
87 extern U32 kwAmmStaPduList[512];
88 U32 kwAmmStaPduListCnt = 0;
93 @brief RLC Acknowledged Mode Downlink Module
95 #define KW_MODULE (KW_DBGMASK_AM | KW_DBGMASK_DL)
97 U32 kwStatusPduCnt, kwStatusAckCnt, kwStatusNcnt, kwSduSndCnt;
103 /* forward references */
104 EXTERN Void kwAmmDlHndlStatusPdu ARGS ((KwCb *gCb,
106 KwUdxStaPdu *pStaPdu));
108 /* public variable declarations */
110 /* This structure holds all the global structs we need. */
112 /* private variable declarations */
114 #define KW_AM_RMV_HDR(_gCb, _rbCb, _retx) do { \
115 if ((_retx)->yetToConst == FALSE) \
118 SSegMsg((_retx)->seg, (_retx)->hdrSz, &_pduInfo); \
119 KW_FREE_BUF((_retx)->seg); \
120 (_retx)->seg = _pduInfo; \
122 (_rbCb)->m.amDl.estHdrSz -= retx->hdrSz;\
125 /* private function declarations */
127 PRIVATE Void kwResegRetxPdus ARGS ((KwCb *gCb,
129 KwDatReq *kwDatReq));
131 PRIVATE Void kwRemRetxPdu ARGS ((KwCb *gCb,
135 PRIVATE Void kwAmmCreateStatusPdu ARGS ((KwCb *gCb,
137 KwDatReq *kwDatReq));
139 PRIVATE Void kwAmmDlMarkPduForReTx ARGS ((KwCb *gCb,
143 PRIVATE Void kwAmmDlProcessSuccessfulTxPdu ARGS((KwCb *gCb,
146 KwuDatCfmInfo **datCfm));
148 PRIVATE Void kwAmmDlSetTxNextAck ARGS((KwAmDl *amDl, KwSn sn));
150 PRIVATE Void kwAmmDlCheckAndStopPollTmr ARGS((KwCb *gCb,
154 PRIVATE Void kwAssembleSdus ARGS ((KwCb *gCb,
156 KwDatReq *kwDatReq));
158 PRIVATE Bool kwAmmDlCheckAndSetPoll ARGS ((KwCb *gCb,
163 PRIVATE Void kwAmmCreatePdu ARGS ((KwCb *gCb,
166 KwDlPduInfo *pduInfo,
169 PRIVATE Void kwAmmSndStaInd ARGS ((KwCb *gCb,KwDlRbCb *rbCb, KwRetx *retx));
171 PRIVATE Void kwGetNxtRetx ARGS ((KwCb *gCb, KwRetx **retx));
173 PRIVATE Void kwConstructAmHdr ARGS ((KwAmHdr *amHdr,
178 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForAckSn ARGS ((KwCb *gCb,
182 KwuDatCfmInfo **datCfm));
184 PRIVATE Void kwAmmDlMoveFrmTxtoRetxBuffer ARGS ((KwCb *gCb,
189 PRIVATE Void kwAmmDlCheckIsSDUDelivered ARGS((KwCb *gCb,
192 KwuDatCfmInfo **datCfm));
194 PRIVATE Void kwAmmAddPduToRetxLst ARGS((KwAmDl *amDl,
197 PRIVATE Void kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer ARGS(
205 PRIVATE Void kwAmmDlHndlStatus4SduByteSegInTxBuf ARGS(
209 KwNackInfo *nackSnInfo,
211 KwuDatCfmInfo **datCfm
214 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForNackSn ARGS(
218 KwNackInfo *nackSnInfo,
220 KwuDatCfmInfo **datCfm
223 PRIVATE Void KwDlAmmGetNackSnInfoFrmNackRangeIdx ARGS(
226 KwNackInfo *nackInfo,
228 KwNackInfo *nackSnInfo,
232 PRIVATE Void kwAmmDlUpdTxAndReTxBufForLessThanNackSn ARGS(
239 KwuDatCfmInfo **datCfm
241 /*****************************************************************************
243 AM Module contains the following funcitons:
247 - kwAmmDlAssembleCntrlInfo
250 - kwAmmDlCheckAndSetPoll
256 *******************************************************************************/
257 /** @addtogroup ammode */
261 * @brief Function to send a Status Response to MAC for a dedicated logical
265 * Function calculates the current bo and send a Status response for the
266 * dedicated logical channel if the bo is non zero
268 * @param[in] gCb RLC instance control block
269 * @param[in] rbCb Radio Bearer control block
270 * @param[in] amDl AM downlink control block
275 PUBLIC Void kwAmmSendDStaRsp
282 PUBLIC Void kwAmmSendDStaRsp(gCb, rbCb, amDl)
288 S32 bo = kwAmmCalculateBo(amDl);
292 kwUtlSndDStaRsp(gCb, rbCb, bo, amDl->estHdrSz, amDl->cntrlBo ?TRUE:FALSE,amDl->cntrlBo);
299 * @brief Function to check if the pollSn is acked and stop the poll timer
301 * @param[in] gCb RLC instance control block
302 * @param[in] rbCb Radio Bearer control block
303 * @param[in] mAckSn The last received ACKSN. The base modulus value should
309 PRIVATE Void kwAmmDlCheckAndStopPollTmr
316 PRIVATE Void kwAmmDlCheckAndStopPollTmr(gCb, rbCb, mAckSn)
324 MODAMT(rbCb->m.amDl.pollSn, mPollSn, rbCb->m.amDl.txNextAck,rbCb->m.amDl.snModMask);
326 if (mPollSn <= mAckSn)
328 if (kwChkTmr(gCb, (PTR)rbCb, KW_EVT_AMDL_POLL_RETX_TMR))
330 kwStopTmr(gCb, (PTR)rbCb, KW_EVT_AMDL_POLL_RETX_TMR);
338 * @brief Function to set VT(A) and VT(MS). Calculates the VT(MS) from VT(A)
340 * @param[in,out] amDl AM downlink control block
341 * @param[in]sn Sequence number to be set as VT(A)
346 PRIVATE Void kwAmmDlSetTxNextAck
352 PRIVATE Void kwAmmDlSetTxNextAck(amDl, sn)
357 amDl->txNextAck = sn;
363 * @brief Function to process a successfully re-transmitted PDU/segment
366 * Checks if the SDU has been completely delivered or not. Removes the PDU
367 * from the re-transmission buffer
369 * @param[in] gCb RLC instance control block
370 * @param[in] rbCb Downlink Radio Bearer control block
371 * @param[in] retx The PDU/segment which was successfully re-transmitted
376 PRIVATE Void kwAmmDlProcessSuccessfulReTx
381 KwuDatCfmInfo **datCfm
384 PRIVATE Void kwAmmDlProcessSuccessfulReTx(gCb, rbCb, retx, datCfm)
388 KwuDatCfmInfo **datCfm;
391 kwAmmDlCheckIsSDUDelivered(gCb, rbCb, &(retx->sduMap), datCfm);
393 kwRemRetxPdu(gCb, rbCb, retx);
399 * @brief Handler to Move the PDU from txBuf to re-transmission buffer
402 * This function is used to move the PDU from the txBuf to re-transmit buffer
404 * @param[in]KwCb *gCb RLC instance control block
405 * @param[in]KwAmDl *amDl AM Downlink Control Block
406 * @param[in]KwRetx **retx node in the reTx buffer to be moved to, allocated by
408 * @param[in]KwDlPduInfo *pduInfo TX PDU which needs to be moved
415 PRIVATE Void kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer
423 PRIVATE Void kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb, amDl, retx, pduInfo)
427 KwDlPduInfo *pduInfo;
430 TRC2(kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer);
433 KW_ALLOC_WC(gCb,*retx, sizeof(KwRetx));
435 #if (ERRCLASS & ERRCLS_ADD_RES)
438 RLOG0(L_FATAL, "Memory allocation failed");
441 #endif /* ERRCLASS & ERRCLS_RES */
443 (*retx)->seg = pduInfo->pdu;
444 (*retx)->segSz = pduInfo->pduSz;
445 /* MS_FIX for DL stall */
446 (*retx)->soEnd = (pduInfo->amHdr.so + pduInfo->pduSz - 1);
448 (*retx)->hdrSz = pduInfo->hdrSz;
449 (*retx)->retxCnt = 1;
450 (*retx)->yetToConst = 0;
451 (*retx)->pendingReTrans = TRUE;
453 /* initialize the list pointer to 0 instead of memset */
454 (*retx)->lstEnt.next = 0;
455 (*retx)->lstEnt.prev = 0;
456 /* copy the sdu maps */
457 KW_MEM_CPY(&((*retx)->sduMap),
461 KW_MEM_CPY(&((*retx)->amHdr), &pduInfo->amHdr, sizeof(KwAmHdr));
462 kwAmmAddPduToRetxLst(amDl, (*retx));
464 /* Update the BO appropriately */
465 amDl->retxBo += (*retx)->segSz;
466 amDl->estHdrSz += (*retx)->hdrSz;
468 gRlcStats.amRlcStats.numDLRetransPdus++;
471 } /*kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer */
474 * @brief Function to handle Status of Sdu byte segment for a nackSn
477 * This function is used to move the PDU from the txBuf to re-transmit buffer
479 * @param[in]KwCb *gCb RLC instance control block
480 * @param[in]KwDlRbCb *rbCb AM Downlink Control Block
481 * @param[in]KwNackInfo *nackSnInfo Nack Information of a NACK_SN
482 * @param[in]KwRetx **retx node in the reTx buffer to be moved to, allocated by
484 * @param[in]KwuDatCfmInfo **datCfm Ptr to datCfm
491 PRIVATE Void kwAmmDlHndlStatus4SduByteSegInTxBuf
495 KwNackInfo *nackSnInfo,
497 KwuDatCfmInfo ** datCfm
500 PRIVATE Void kwAmmDlHndlStatus4SduByteSegInTxBuf(gCb, rbCb, nackSnInfo, retx, datCfm)
504 KwNackInfo *nackSnInfo;
506 KwuDatCfmInfo **datCfm;
514 TRC2(kwAmmDlHndlStatus4SduByteSegInTxBuf)
516 txBuf = kwUtlGetTxBuf(AMDL.txBufLst, nackSnInfo->sn);
521 lnk = txBuf->pduLst.first;
524 KwDlPduInfo *pduInfo = (KwDlPduInfo *)(lnk->node);
525 KwSn pduSoEnd = (pduInfo->amHdr.so + pduInfo->sduMap.sduSz - 1);
527 /* If So of Sdu byte segment(pduInfo/seg) is < status pdu
528 soStart that means it's ACKED*/
529 if(pduSoEnd < nackSnInfo->soStart)
531 kwAmmDlCheckIsSDUDelivered(gCb,
537 else if (pduSoEnd <= nackSnInfo->soEnd)
539 /* Move Sdu byte segment from TX buf to retx buf*/
540 kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb,
551 /* Delete node from the txBuf Pdu lst */
552 cmLListDelFrm(&txBuf->pduLst, lnk);
553 KW_FREE_WC(gCb, pduInfo, sizeof(KwDlPduInfo));
556 if(!txBuf->pduLst.count)
558 /*No more Sdu byte segment are left. Hence delete txBuf*/
559 kwUtlDelTxBuf(AMDL.txBufLst, txBuf,gCb);
566 * @brief Function to handle Status of Sdu byte segment for a nackSn
569 * This function is used to move the PDU from the txBuf to re-transmit buffer
571 * @param[in]KwCb *gCb RLC instance control block
572 * @param[in]KwDlRbCb *rbCb AM Downlink Control Block
573 * @param[in]KwNackInfo *nackSnInfo Nack Information of a NACK_SN
574 * @param[in]KwRetx **retx node in the reTx buffer to be moved to, allocated by
576 * @param[in]KwuDatCfmInfo **datCfm Ptr to datCfm
582 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForNackSn
586 KwNackInfo *nackSnInfo,
588 KwuDatCfmInfo **datCfm
591 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, nackSnInfo, retxNode, datCfm)
595 KwNackInfo *nackSnInfo;
597 KwuDatCfmInfo **datCfm;
604 TRC2(kwAmmDlUpdateTxAndReTxBufForNackSn)
606 /* Now process the NACK_SN received. Now the NACK_SN is */
607 /* either the first element of RETX or is in TX array */
608 /* To remove the remaining acks from the pdu byte segments */
610 /* if the NACK_SN is in the transmit buffer, move it to the re-
612 txBuf = kwUtlGetTxBuf(AMDL.txBufLst, nackSnInfo->sn);
615 if(nackSnInfo->isSegment)
617 /* Go through all the AMD PDUs of a particular SN
618 and check if segment is ACKED if yes then mark succesfully sent,
619 if segment is NACKed then move it to to retx lst */
620 kwAmmDlHndlStatus4SduByteSegInTxBuf(gCb, rbCb, nackSnInfo, &retx, datCfm);
624 /*e2= 0 and e3= 0: Move complete PDU from TX buf to retx buf*/
625 kwAmmDlMoveFrmTxtoRetxBuffer(gCb,
631 #if (ERRCLASS & ERRCLS_ADD_RES)
635 (*retxNode) = retx->lstEnt.next;
641 /* process the pdus/segments in the re-transmit buffer with
645 retx = (KwRetx *)((*retxNode)->node);
646 if (retx->amHdr.sn != nackSnInfo->sn)
650 if ((nackSnInfo->isSegment) &&
651 ((retx->soEnd < nackSnInfo->soStart) /*|| (retx->amHdr.so > soEnd)*/))
653 RLOG_ARG3(L_DEBUG, DBG_RBID, rbCb->rlcId.rbId,
654 "kwHndlStaRsp: Handle ACK for byte segment, Its "
655 "sn = %d UEID:%d CELLID:%d",
659 RLOG_ARG4(L_DEBUG, DBG_RBID, rbCb->rlcId.rbId,
660 "soStart and soEnd = %d, %d, UEID:%d CELLID:%d",
661 retx->amHdr.so, retx->soEnd,
665 (*retxNode) = (*retxNode)->next;
666 kwAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
668 else if((!nackSnInfo->isSegment) || (retx->soEnd <= nackSnInfo->soEnd))
670 /* This case covers the NACKED segments and also the case */
671 /* when there are segments and the entire SN is nacked. */
672 /* This case also covers the case of nonsegmented retx PDU*/
674 (*retxNode) = (*retxNode)->next;
675 /* Mark the retx PDU we found for further retransmission */
676 kwAmmDlMarkPduForReTx(gCb, rbCb, retx);
680 /* If we are here that means this segment and segments after this are ACKed*/
683 } /* end of retxNode while loop*/
688 * @brief Function to get nack Sn information from nackRange index
691 * This function is used to get nack Sn information from nackRange index
693 * @param[in]KwAmDl *amDl,
694 * @param[in]KwUdxStaPdu *StaPdu,
695 * @param[in]KwNackInfo *nackSnInfo,
696 * @param[in]KwRetx *retx;
704 PRIVATE Void KwDlAmmGetNackSnInfoFrmNackRangeIdx
707 KwNackInfo *nackInfo,
709 KwNackInfo *nackSnInfo,
713 PRIVATE Void KwDlAmmGetNackSnInfoFrmNackRangeIdx(amDl, nackInfo, retxNode, nackSnInfo, idx)
716 KwNackInfo *nackInfo;
718 KwNackInfo *nackSnInfo;
727 TRC2(KwDlAmmGetNackSnInfoFrmNackRangeIdx)
729 nackSnInfo->isSegment = FALSE;
731 if((!nackInfo->isSegment) || (!idx && nackSnInfo->nackRange && (!nackInfo->soStart)))
733 nackSnInfo->soStart = 0;
734 nackSnInfo->soEnd = 0;
737 txBuf = kwUtlGetTxBuf(amDl->txBufLst, nackSnInfo->sn);
740 node = txBuf->pduLst.first;
743 KwDlPduInfo *pduInfo = (KwDlPduInfo *)(node->node);
744 U16 pduSoEnd = pduInfo->amHdr.so + pduInfo->sduMap.sduSz - 1;
745 if((!idx) && (pduInfo->amHdr.so == nackInfo->soStart))
747 nackSnInfo->isSegment = TRUE;
748 nackSnInfo->soStart = pduInfo->amHdr.so;
749 nackSnInfo->soEnd = pduSoEnd;
752 else if((idx == nackSnInfo->nackRange - 1) && \
753 (pduSoEnd == nackInfo->soEnd))
755 nackSnInfo->isSegment = TRUE;
756 nackSnInfo->soStart = pduInfo->amHdr.so;
757 nackSnInfo->soEnd = pduSoEnd;
763 if(!nackSnInfo->isSegment)
767 retx = (KwRetx *)(retxNode->node);
768 if(retx->amHdr.sn != nackSnInfo->sn)
772 if((!idx) && (retx->amHdr.so == nackInfo->soStart))
774 nackSnInfo->isSegment = TRUE;
775 nackSnInfo->soStart = retx->amHdr.so;
776 nackSnInfo->soEnd = retx->soEnd;
779 else if((idx == nackSnInfo->nackRange - 1) && \
780 (retx->soEnd == nackInfo->soEnd))
782 nackSnInfo->isSegment = TRUE;
783 nackSnInfo->soStart = retx->amHdr.so;
784 nackSnInfo->soEnd = retx->soEnd;
787 retxNode = retxNode->next;
793 * @brief Function to update transmission buffers and send confimations to
794 * PDCP on the reception of Status PDU
797 * First processes the NACKs received
798 * -# Removes the pdus which are acked by each of the NACK SN from the
799 * transmission and re-transmission buffer
800 * -# If NACKed SN in in the transmisson buffer, moves it to re-transmission
802 * -# Removes PDU segments of the NACKed SN which have been successfully
803 * received by the other end. For the un-successful ones, marks them for
805 * -# When PDUs/segments are removed from the buffer, indicates to upper
806 * layer if the SDU is completely delivered
807 * -# Removes the PDUs/segments which are acked by the ACK_SN but not by the
810 * @param[in] gCb RLC Instance control block
811 * @param[in] rbCb Downlink Radio Bearer control block
812 * @param[in] pStaPdu The decoded Status Pdu
817 PUBLIC Void kwAmmDlHndlStatusPdu
824 PUBLIC Void kwAmmDlHndlStatusPdu(gCb, rbCb, pStaPdu)
827 KwUdxStaPdu *pStaPdu;
833 KwuDatCfmInfo* datCfm;
837 TRC2(kwAmmDlHndlStatusPdu)
840 kwuSap = gCb->u.dlCb->kwuDlSap + KW_UI_PDCP;
841 /* store the re-transmission bo, to check if it changes due to the
842 processing of the status pdu */
843 oldRetxBo = AMDL.retxBo;
845 /* Allocate memory for datCfm Info */
846 KW_SHRABL_STATIC_BUF_ALLOC(kwuSap->pst.region, kwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
848 #if (ERRCLASS & ERRCLS_ADD_RES)
851 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
852 "Memory allocation failed UEID:%d CELLID:%d",
855 KW_SHRABL_STATIC_BUF_FREE(kwuSap->pst.region, kwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
858 #endif /* ERRCLASS & ERRCLS_RES */
860 datCfm->numSduIds = 0;
861 datCfm->rlcId = rbCb->rlcId;
863 MODAMT(pStaPdu->ackSn, mAckSn, AMDL.txNextAck,AMDL.snModMask);
864 MODAMT(AMDL.txNext,mTxNext, AMDL.txNextAck,AMDL.snModMask);
868 RLOG_ARG4(L_WARNING,DBG_RBID, rbCb->rlcId.rbId,
869 "Invalid ACK SN = %d received. Current Vta =%d"
875 /* KW_SHRABL_STATIC_BUF_ALLOC(kwuSap->pst.region, kwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo)); */
876 KW_SHRABL_STATIC_BUF_FREE(kwuSap->pst.region, kwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
880 /* Venki - stopping the poll retx timer */
881 /*Stop PollRetx Tmr */
882 kwAmmDlCheckAndStopPollTmr(gCb, rbCb, mAckSn);
884 /* Set the first node in retx list to retxNode */
885 retxNode = AMDL.retxLst.first;
887 /* If NACK exists in control PDU */
888 if (pStaPdu->nackCnt)
891 KwNackInfo nackSnInfo;
894 KwSn transWinStartSn = AMDL.txNextAck; /*used to track the SN from which
895 to start processing the transmission
899 /* if any NACKs then txNextAck should be equal to the first NACK_SN*/
900 txNextAck = pStaPdu->nackInfo[0].sn;
902 kwStatusNcnt += pStaPdu->nackCnt;
905 while (idx < pStaPdu->nackCnt)
907 nackSnInfo.isSegment = pStaPdu->nackInfo[idx].isSegment;
908 nackSnInfo.nackRange = pStaPdu->nackInfo[idx].nackRange;
909 nackSnInfo.sn = pStaPdu->nackInfo[idx].sn;
911 RLOG_ARG3(L_DEBUG,DBG_RBID, rbCb->rlcId.rbId,
912 "kwHndlStaRsp: NACK SN = %d UEID:%d CELLID:%d",
917 nackSnInfo.soStart = pStaPdu->nackInfo[idx].soStart;
918 nackSnInfo.soEnd = pStaPdu->nackInfo[idx].soEnd;
920 /* e2 is used as a boolean indicating presence of SOStart or SOEnd */
922 sn = transWinStartSn;
924 /* move transWinStartSn to nackSnInfo.sn + 1, as the pdu's before that
925 will be removed from the buffer */
926 transWinStartSn = (nackSnInfo.sn + (nackSnInfo.nackRange ?\
927 (nackSnInfo.nackRange - 1) : 0) + 1) & AMDL.snModMask;
929 /* Clear the acked SNs from the retx list */
930 MODAMT(nackSnInfo.sn, mNackSn, AMDL.txNextAck,AMDL.snModMask);
932 if ((mNackSn > mAckSn) || (mNackSn >= mTxNext))
934 /* Erroneous NACK_SN, we should raise an error towards L3 */
935 RLOG_ARG2(L_ERROR,DBG_RBID, rbCb->rlcId.rbId,
936 "Status Pdu is not correct UEID:%d CELLID:%d",
939 KW_SHRABL_STATIC_BUF_FREE(kwuSap->pst.region, kwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
943 /* clear all the SNs < NACK_SN from re-transmission list */
944 kwAmmDlUpdTxAndReTxBufForLessThanNackSn(gCb, rbCb, sn, mNackSn,
947 if(!nackSnInfo.nackRange)
949 kwAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, &nackSnInfo, &retxNode, &datCfm);
950 gRlcStats.amRlcStats.numRlcAmCellNackRx++;
955 /* Update issegment, soStart, soEnd ,sn in nackSnInfo and handle
959 KwDlAmmGetNackSnInfoFrmNackRangeIdx(&AMDL, &pStaPdu->nackInfo[idx],
960 retxNode, &nackSnInfo, idx1);
962 kwAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, &nackSnInfo,
964 nackSnInfo.sn = ((nackSnInfo.sn + 1) & (AMDL.snModMask));
965 gRlcStats.amRlcStats.numRlcAmCellNackRx++;
967 }while((++idx1) < (nackSnInfo.nackRange));
971 } /* End of nackCnt while loop */
973 /* Remove the PDUs with are further acked by the ACK_SN after taking
974 care of all the NACK_SN related acknowledgments*/
975 kwAmmDlUpdateTxAndReTxBufForAckSn(gCb,rbCb, mAckSn, retxNode, &datCfm);
977 /* Update txNextAck */
978 kwAmmDlSetTxNextAck(&AMDL,txNextAck);
984 RLOG_ARG2(L_UNUSED,DBG_RBID, rbCb->rlcId.rbId,
985 "kwHndlStaRsp: Received All ACKS UEID:%d CELLID:%d",
989 /* For the remaining ACKs after last nackSn */
990 kwAmmDlUpdateTxAndReTxBufForAckSn(gCb,rbCb, mAckSn, retxNode, &datCfm);
992 /* update txNextAck */
993 kwAmmDlSetTxNextAck(&AMDL, pStaPdu->ackSn);
996 if(datCfm->numSduIds != 0)
998 if(datCfm->numSduIds > 1024)
1000 RLOG_ARG4(L_DEBUG,DBG_RBID,datCfm->rlcId.rbId,
1001 "Sending [%lu] SDU Cfms to PDCP & [%lu] lost for"
1002 "UEID:%d CELLID:%d",
1004 datCfm->numSduIds-1024,
1006 rbCb->rlcId.cellId);
1007 datCfm->numSduIds = 1024;
1009 kwSduSndCnt += datCfm->numSduIds;
1010 /* Sap control block */
1011 KwUiKwuDatCfm(&kwuSap->pst, kwuSap->suId, datCfm);
1015 KW_SHRABL_STATIC_BUF_FREE(kwuSap->pst.region, kwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
1018 /* Fix for memory corruption */
1019 KW_LLIST_FIRST_RETX(AMDL.retxLst, AMDL.nxtRetx);
1020 /* BO update, if retransmission BO has changed. AMDL.retxBo would have
1021 canged inside the above called functions */
1022 if (oldRetxBo != AMDL.retxBo)
1024 kwAmmSendDStaRsp(gCb, rbCb, &AMDL);
1031 * @brief Function to calculate the current buffer occupancy
1034 * Function to calculate the current bo depending on the control,
1035 * re-transmit, transmit bo's and the state of the transmit window.
1036 * If the transmit window is stalled, then the transmit bo is not
1037 * taken into account
1039 * @param[in] amDl AM mode donwlink control block
1045 PUBLIC S32 kwAmmCalculateBo
1050 PUBLIC S32 kwAmmCalculateBo(amDl)
1056 /* Make sure non of the bo's are negative */
1062 if (amDl->cntrlBo < 0)
1067 if (amDl->retxBo < 0)
1072 bo = amDl->cntrlBo + amDl->retxBo;
1074 /* if window is not stalled then add the transmit bo also */
1075 if (! KW_AM_IS_TRANS_WIN_STALLED(amDl))
1085 * @brief Handler to queue the SDUs received from PDCP
1088 * This function is invoked by UIM to queue the SDU received from PDCP in the
1089 * SDU queue of the corresponding RbCb. It also updates the BO and report the
1091 * - Allocate memory for and assign received buffer to the SDU
1092 * - Add SDU in the sduQ of KwAmDl
1093 * - Calculate bo with the buffer received
1094 * - Accumulate bo with retransmission bo and control pdu's bo if available
1095 * - Estimate the header size for the bo; Fill in StaRspInfo and send it
1098 * @param[in] gCb RLC Instance control block
1099 * @param[in] rbCb RB control block
1100 * @param[in] mBuf Sdu to be queued
1101 * @param[in] datReq Ptr to the datReq sent from PDCP
1107 PUBLIC Void kwAmmQSdu
1112 KwuDatReqInfo *datReq
1115 PUBLIC Void kwAmmQSdu(gCb, rbCb, mBuf, datReq)
1119 KwuDatReqInfo *datReq;
1133 KW_ALLOC_WC(gCb,sdu, sizeof(KwSdu));
1135 #if (ERRCLASS & ERRCLS_ADD_RES)
1138 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1139 "Memory allocation failed UEID:%d CELLID:%d",
1141 rbCb->rlcId.cellId);
1144 #endif /* ERRCLASS & ERRCLS_RES */
1146 KW_UPD_L2_DL_TOT_SDU_STS(gCb,rbCb);
1147 /* Discard new changes starts */
1148 kwUtlGetCurrTime(&sdu->arrTime);
1149 /* Discard new changes ends */
1150 /* Assign values to sdu */
1151 SFndLenMsg(mBuf, &sdu->sduSz);
1154 sdu->actSz = sdu->sduSz;
1155 sdu->mode.am.sduId = datReq->sduId;
1156 /* initialize values for AM mode to 0 */
1157 sdu->mode.am.rcvdSz = 0;
1158 sdu->mode.am.isSegmented = 0;
1159 #ifndef RGL_SPECIFIC_CHANGES
1162 extern U32 dlrate_kwu;
1163 dlrate_kwu += sdu->sduSz;
1167 /* Update nxtTx to point to the added sdu if this is the first SDU in the
1169 if (AMDL.nxtTx == NULLP)
1171 RLOG_ARG2(L_UNUSED,DBG_RBID, rbCb->rlcId.rbId,
1172 "kwAmmQSdu: Received SDU will be transmitted next"
1173 "UEID:%d CELLID:%d",
1175 rbCb->rlcId.cellId);
1179 /* Add sdu to the sdu list */
1180 cmLListAdd2Tail(&AMDL.sduQ, &sdu->lstEnt);
1181 sdu->lstEnt.node = (PTR)sdu;
1185 if (rbCb->ueCb->tenbStats)
1187 if (AMDL.sduQ.count > rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxPktsInSduQ)
1189 rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxPktsInSduQ = AMDL.sduQ.count;
1191 kwWinSz = KW_AM_TRANS_WIN_SIZE(&AMDL);
1192 if (kwWinSz > rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxWindowSz)
1194 rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxWindowSz = kwWinSz;
1200 /* Update BO and estimate header size for the current BO */
1201 AMDL.bo = AMDL.bo + sdu->sduSz;
1202 if(AMDL.snLen == KW_AM_CFG_12BIT_SN_LEN)
1210 #ifdef LTE_L2_MEAS_RLC
1211 /* Update numActUe if it is not active */
1212 if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_ACT_UE) &&
1213 (rbCb->ueCb->numActRb[rbCb->qci] == 0))
1215 rbCb->ueCb->numActRb[rbCb->qci]++;
1216 gCb.kwL2Cb.numActUe[rbCb->qci]++;
1220 if(!kwDlUtlIsReestInProgress(rbCb))
1222 kwAmmSendDStaRsp(gCb, rbCb, &AMDL);
1230 * @brief Private handler to construct control PDU
1233 * This function sets the pduSz correctly after eliminating the fixed
1234 * header sizes and the MAC header size. It copies the already prepared
1235 * STATUS PDU to the data to be sent to MAC.
1237 * @param[in] gCb RLC instance control block
1238 * @param[in] rbCb Downlink RB control block
1239 * @param[in] kwdatReq DatReq to be sent to MAC
1245 PRIVATE Void kwAmmDlAssembleCntrlInfo
1252 PRIVATE Void kwAmmDlAssembleCntrlInfo(gCb, rbCb, kwDatReq)
1258 KwUdxDlSapCb *sapCb;
1261 TRC2(kwAmmDlAssembleCntrlInfo)
1263 macHdrEstmt = (rbCb->m.amDl.cntrlBo < 256) ?
1264 KW_MAC_HDR_SZ2 : KW_MAC_HDR_SZ3;
1265 /* Eliminate fixed hdr size (14bits including ACK_SN) */
1266 if (kwDatReq->pduSz >= (KW_CNTRL_PDU_FIXED_HDRSZ + macHdrEstmt))
1268 /* Check the TB size whether it is sufficcient enough to fit the
1269 status Pdu into it otherwise make arrangement such that it can fit
1270 into in a way of possible NACks*/
1271 /* ccpu00135743 : fix for MAC Hdr size calc */
1272 kwDatReq->pduSz -= macHdrEstmt;
1274 /* Create the status Pdu with the required NACKs */
1275 kwAmmCreateStatusPdu(gCb,rbCb,kwDatReq);
1277 sapCb = KW_GET_DL_SAPCB(gCb, rbCb);
1278 KwDlUdxStaProhTmrStart(&(gCb->u.dlCb->udxDlSap->pst),
1279 sapCb->suId, &(rbCb->rlcId));
1281 /* Update number of pdus in pduInfo */
1282 kwDatReq->pduInfo.mBuf[kwDatReq->pduInfo.numPdu] = AMDL.mBuf;
1283 kwDatReq->pduInfo.numPdu++;
1284 gRlcStats.amRlcStats.numDLStaPduSent++;
1286 KW_FREE_SHRABL_BUF(gCb->u.dlCb->udxDlSap->pst.region,
1287 gCb->u.dlCb->udxDlSap->pst.pool,
1289 sizeof(KwUdxDlStaPdu));
1291 AMDL.pStaPdu = NULLP;
1293 gRlcStats.amRlcStats.numDLStaPduSent++;
1300 * @brief Handler to form the PDUs with the size indicated by MAC
1303 * This function is invoked by UTL with the PDU size indicated by
1304 * MAC (after eliminating MAC header size). It assembles control
1305 * Info / data (New SDUs / Retx PDUs), check if polling needs to be
1306 * set for the data PDU and returns PDU(s) and updated BO with
1307 * estimated header size to be sent to MAC.
1309 * - Check if the control BO is available and call kwAssembleCntrlInfo
1310 * to assemble control Information
1311 * - Check if the pdu size is available to form PDUs from retransmission
1312 * buffer and call kwResegRetxPdus
1313 * - Check if the pdu size is available and assemble SDUs from sduQ
1314 * if exist, using kwAssembleSdus
1315 * - PDU Info and bo are filled in and then sent to MAC from the
1318 * @param[in] gCb RLC instance control block
1319 * @param[in] rbCb RB control block
1320 * @param[in] kwdatReq DatReq to be sent to MAC
1321 * @param[in] fillCtrlPdu Indicates whether cntrl PDU to be filled or not
1327 PUBLIC Void kwAmmProcessSdus
1335 PUBLIC Void kwAmmProcessSdus(gCb, rbCb, kwDatReq,fillCtrlPdu)
1342 TRC2(kwAmmProcessSdus)
1345 /* Assemble control information. fillCtrlPdu parameter check is added for CA
1346 * It is used to force cntrl Pdu scheduling on PCell. for Non CA case this
1347 * flag will always be TRUE. In CA case, for PCELL it is TRUE and for SCEll
1350 if ((AMDL.cntrlBo != 0)
1356 kwDatReq->boRep.staPduPrsnt = TRUE;
1357 kwDatReq->boRep.staPduBo = AMDL.cntrlBo;
1359 if (AMDL.pStaPdu != NULLP)
1361 kwAmmDlAssembleCntrlInfo (gCb, rbCb, kwDatReq);
1365 RLOG_ARG2(L_ERROR, DBG_RBID, rbCb->rlcId.rbId,
1366 "Miscomputation of control Bo. UEID:%d CELLID:%d",
1368 rbCb->rlcId.cellId);
1373 /* Retransmit PDUs /portions of PDUs available in retxLst */
1374 if ((kwDatReq->pduSz > 0) && (AMDL.nxtRetx != NULLP))
1376 kwResegRetxPdus (gCb,rbCb, kwDatReq);
1379 /* Assemble SDUs to form new PDUs */
1380 if ((kwDatReq->pduSz > 0) && (AMDL.nxtTx != 0))
1382 kwAssembleSdus(gCb,rbCb, kwDatReq);
1385 if (AMDL.nxtRetx != NULLP)
1387 kwDatReq->boRep.oldestSduArrTime = AMDL.nxtRetx->sduMap.sdu->arrTime;
1389 else if (AMDL.nxtTx != NULLP)
1391 kwDatReq->boRep.oldestSduArrTime = AMDL.nxtTx->arrTime;
1394 kwDatReq->boRep.bo = kwAmmCalculateBo(&AMDL);
1395 kwDatReq->boRep.staPduBo = AMDL.cntrlBo;
1397 /* Hdr estimation is moved to kwAmmCreatePDu */
1398 kwDatReq->boRep.estHdrSz = AMDL.estHdrSz;
1400 if(kwDatReq->pduSz > 0)
1402 gRlcStats.amRlcStats.numDLBytesUnused += kwDatReq->pduSz;
1408 * @brief Private handler split a PDU/segment into two
1411 * Its a private function called by kwResegRetxPdu to split a segment
1412 * or a retransmit PDU into two segments splitting at the passed size.
1413 * This function is called only for those PDUs that dont have any LIs.
1415 * @param[in] gCb RLC instance control block
1416 * @param[in] rbCb RB control block
1417 * @param[in,out] crnt The PDU to be split, first part of split pdu remians
1419 * @param[out] next The second part of the split pdu
1420 * @param[in] size The size witin crnt, at which to split
1426 PRIVATE Void kwSplitPdu
1435 PRIVATE Void kwSplitPdu(gCb, rbCb, crnt, next, size)
1444 KwAmDl *amDl = &AMDL;
1447 /* Set the SN for the new segment */
1448 next->amHdr.sn = crnt->amHdr.sn;
1450 /* Set the protocol specific fields appropriately */
1451 si = crnt->amHdr.si;
1452 crnt->amHdr.si = si | KW_SI_FIRST_SEG;
1453 next->amHdr.si = si | KW_SI_LAST_SEG;
1457 /* Update seg size */
1458 next->segSz = crnt->segSz - size;
1461 /* Set the SO fields appropriately */
1462 /* MS_FIX for DL stall */
1463 next->soEnd = crnt->soEnd;
1465 /* Set the SO fields appropriately */
1466 /* SO of next will be after the end of current */
1467 next->amHdr.so = crnt->amHdr.so + crnt->segSz;
1468 /* SO End of current will be one less than the start of next */
1469 crnt->soEnd = next->amHdr.so - 1;
1471 /* intialize the other fields in the amHdr of next to 0 */
1475 /* This macro is called for No LI case - one SDU */
1476 /* Update the size of SDU in each node's sduMap */
1477 next->sduMap.sdu = crnt->sduMap.sdu;
1478 crnt->sduMap.sduSz = crnt->segSz;
1479 next->sduMap.sduSz = next->segSz;
1481 /* Segment the payload into two parts based on the size passed */
1482 SSegMsg(crnt->seg, size, &next->seg);
1483 next->retxCnt = crnt->retxCnt;
1484 next->yetToConst = TRUE;
1485 next->pendingReTrans = crnt->pendingReTrans;
1487 /* Compute the header size and update the BO appropriately */
1488 if(amDl->snLen == KW_AM_CFG_12BIT_SN_LEN)
1490 next->hdrSz = KW_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1491 if(crnt->amHdr.si == KW_SI_FIRST_SEG)
1493 crnt->hdrSz = KW_AM_SEG_12BIT_SN_WITHOUT_SO_HDRSZ;
1497 crnt->hdrSz = KW_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1502 next->hdrSz = KW_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1503 if(crnt->amHdr.si == KW_SI_FIRST_SEG)
1505 crnt->hdrSz = KW_AM_SEG_18BIT_SN_WITHOUT_SO_HDRSZ;
1509 crnt->hdrSz = KW_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1513 /* Add the next to the retx list */
1514 AMDL.retxLst.crnt = &crnt->lstEnt;
1515 CM_LLIST_INS_AFT_CRNT(AMDL.retxLst, next);
1516 AMDL.nxtRetx = next;
1517 amDl->estHdrSz += next->hdrSz;
1523 * @brief Private handler to retransmit PDUs or PDU segments
1526 * Its a private function called by kwProcessSdus, to create the
1527 * PDUs / its segments from the retransmission buffer available in RbCb.
1529 * - Eliminate the fixed header size and MAC header size while
1530 * forming PDUs/segments
1531 * - While pdusize is available and retxBuf has data (pdu or portion
1532 * of pdu) to be sent, form the pdu as it is if it matches with the
1533 * pdusize else segment the PDUs/portion of PDUs
1534 * - Call kwAmmDlCheckAndSetPoll function to check and set the poll bit as
1536 * - Concatenate data and header info and fill pduInfo
1537 * - Update retxCnt and send indication to PDCP if it reaches maxRetx
1540 * @param[in] gCb RLC instance control block
1541 * @param[in] rbCb RB control block
1542 * @param[in] kwdatReq DatReq to be sent to MAC
1548 PRIVATE Void kwResegRetxPdus
1555 PRIVATE Void kwResegRetxPdus(gCb, rbCb, kwDatReq)
1563 U8 hdr[KW_MAX_HDRSZ];
1569 KwL2MeasTb *l2MeasTb;
1574 TRC2(kwResegRetxPdus)
1579 /* TODO : This shoould be taken care in new Trasmissions */
1580 /* This lchInfo should be retrieved there */
1581 l2MeasTb = kwUtlGetCurMeasTb(gCb, rbCb);
1582 if (l2MeasTb == NULLP)
1586 /* TODO : This lcid needs to be searched in case of normal Tx */
1587 /* In retx here, its fine as this will be higher priority */
1588 lchInfo = &l2MeasTb->lchInfo[l2MeasTb->numLchInfo];
1589 if (l2MeasTb->numLchInfo >= KW_MAX_ACTV_DRB)
1593 l2MeasTb->numLchInfo++;
1594 lchInfo->lcId = rbCb->lch.lChId;
1595 lchInfo->numSdus = 0;
1598 while ((kwDatReq->pduSz > 0) && (amDl->nxtRetx != NULLP)&&
1599 (kwDatReq->pduInfo.numPdu < KW_MAX_PDU))
1603 retx = amDl->nxtRetx;
1604 /* kw003.201 : Add header size to seg size to determine if the */
1605 /* the segment can be completed within the allocation */
1606 /* kw003.201 - Eliminate MAC Header Size based on bites needed */
1607 tmpSz = KW_MIN((retx->segSz + retx->hdrSz), kwDatReq->pduSz);
1608 pduSz = (retx->segSz + retx->hdrSz);
1609 /* 5GNR_RLC: length field in 5GNR MAC Hdr is 8/16 btis*/
1610 kwDatReq->pduSz -= (tmpSz < 255) ? KW_MAC_HDR_SZ2 : KW_MAC_HDR_SZ3;
1612 /* kw003.201 - We should have at least one more than basic header */
1613 if (kwDatReq->pduSz <= retx->hdrSz)
1617 kwGetNxtRetx(gCb, &(amDl->nxtRetx));
1619 /* Send retx buf without segmentation */
1620 if (kwDatReq->pduSz >= pduSz)
1624 RLOG_ARG2(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
1625 "kwResegRetxPdus: Send retx buf without segmentation "
1626 "UEID:%d CELLID:%d",
1628 rbCb->rlcId.cellId);
1630 if (retx->yetToConst)
1632 /* Construct hdr with the available hdr values */
1633 kwConstructAmHdr(&retx->amHdr, hdr, amDl->snLen, &idx);
1634 /* Add header to the pdu/segment */
1635 SAddPreMsgMultInOrder(hdr, idx + 1, retx->seg);
1636 retx->yetToConst = FALSE;
1639 /* kw003.201 - Check if poll bit needs to be set. Retx size does */
1640 /* not affect the poll bit so it is being passed as zero */
1641 pollBit = kwAmmDlCheckAndSetPoll(gCb,rbCb, FALSE, 0);
1642 KW_UPD_POLL_BIT(gCb, retx, pollBit);
1644 kwDatReq->pduSz -= pduSz;
1645 AMDL.estHdrSz -= retx->hdrSz;
1648 if (rbCb->rlcId.rbType == CM_LTE_DRB)
1651 for (sduIdx = lchInfo->numSdus ;
1652 ((numSdus < retx->numSdu) && (sduIdx < KW_L2MEAS_SDUIDX)) ;
1653 sduIdx++, numSdus++)
1655 lchInfo->sduInfo[sduIdx].arvlTime = retx->sduMap[numSdus].sdu->arrTime;
1656 lchInfo->sduInfo[sduIdx].isRetxPdu = TRUE; /* TODO : for later use */
1658 lchInfo->numSdus += numSdus;
1666 /* Segment this pdu / portion of pdu. Insert this segment into */
1667 /* retxLst and update offset */
1668 RLOG_ARG2(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
1669 "kwResegRetxPdus: Segment retx buf UEID:%d CELLID:%d",
1671 rbCb->rlcId.cellId);
1673 /* Eliminate fixed header size if the pdu is segmented for the */
1675 if(amDl->snLen == KW_AM_CFG_12BIT_SN_LEN)
1677 if(retx->amHdr.si < KW_SI_LAST_SEG)
1679 kwDatReq->pduSz -= KW_AM_SEG_12BIT_SN_WITHOUT_SO_HDRSZ;
1683 kwDatReq->pduSz -= KW_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1688 if(retx->amHdr.si < KW_SI_LAST_SEG)
1690 kwDatReq->pduSz -= KW_AM_SEG_18BIT_SN_WITHOUT_SO_HDRSZ;
1694 kwDatReq->pduSz -= KW_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1697 if (kwDatReq->pduSz <= 0)
1702 /* Allocate memory for tracking a new segment */
1703 KW_ALLOC_WC(gCb,tNode, sizeof(KwRetx));
1704 #if (ERRCLASS & ERRCLS_ADD_RES)
1707 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1708 "Memory allocation failed UEID:%d CELLID:%d",
1710 rbCb->rlcId.cellId);
1713 #endif /* ERRCLASS & ERRCLS_RES */
1715 /* initialize the list pointer to 0 instead of memset */
1716 tNode->lstEnt.next = 0;
1717 tNode->lstEnt.prev = 0;
1719 /* Segment header and data */
1720 KW_AM_RMV_HDR(gCb, rbCb, retx);
1722 /* kw003.201 - Split the payload and update other fields */
1723 kwSplitPdu(gCb,rbCb, retx, tNode, kwDatReq->pduSz);
1728 sduIdx = lchInfo->numSdus;
1729 for (numSdus = 0, sduIdx = lchInfo->numSdus;
1730 ((numSdus < retx->numSdu) && (sduIdx < KW_L2MEAS_SDUIDX));
1731 numSdus++, sduIdx++)
1733 lchInfo->sduInfo[sduIdx].arvlTime =
1734 retx->sduMap[numSdus].sdu->arrTime;
1735 lchInfo->sduInfo[sduIdx].isRetxPdu = TRUE;
1737 lchInfo->numSdus = sduIdx;
1738 if ((retx->amHdr.lsf == 0) && (lchInfo->numSdus > 0))
1743 /* Construct hdr with the available hdr values */
1744 kwConstructAmHdr(&retx->amHdr, hdr, amDl->snLen, &idx);
1745 SAddPreMsgMultInOrder(hdr, idx + 1, retx->seg);
1747 retx->hdrSz = idx + 1;
1749 /* Poll bit need not be set for this seg, since its second */
1750 /* half remains in retxLst */
1751 KW_UPD_POLL_BIT(gCb, retx, FALSE);
1752 retx->yetToConst = FALSE;
1753 kwDatReq->pduSz = 0;
1756 kwCpyMsg(gCb,retx->seg, &pdu);
1758 /* Update pduInfo */
1759 kwDatReq->pduInfo.mBuf[kwDatReq->pduInfo.numPdu] = pdu;
1760 kwDatReq->pduInfo.numPdu++;
1761 /* kw005.201 ccpu00117318, updating the statistics */
1762 gCb->genSts.pdusRetx += 1;
1763 gRlcStats.amRlcStats.numRlcAmCellRetxPdu++;
1764 retx->soEnd = retx->amHdr.so + retx->segSz - 1;
1765 retx->pendingReTrans = FALSE;
1766 amDl->retxBo -= retx->segSz;
1769 RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
1770 "kwResegRetxPdus: retxBo after resegmentation = %ld"
1771 "UEID:%d CELLID:%d",
1774 rbCb->rlcId.cellId);
1776 RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
1777 "kwResegRetxPdus: retxBo after resegmentation = %d "
1778 "UEID:%d CELLID:%d",
1781 rbCb->rlcId.cellId);
1789 * @brief Private handler to assemble SDUs to form new data PDU(s)
1792 * Its a private function called by kwProcessSdus, to create the new data
1793 * PDUs from the SDU queue of RbCb.
1795 * - While pdusize is available, segment/concatenate SDUs or else if it
1796 * matches the pdu size form PDUs accordingly.
1797 * - RLC header and MAC header size are eliminated while forming the PDUs
1798 * - Call kwAmmDlCheckAndSetPoll function to check and set the poll bit
1800 * - Concatenate data and header info and fill pduInfo
1802 * @param[in] rbCb RB control block
1803 * @param[in] kwdatReq DatReq to be sent to MAC
1809 PRIVATE Void kwAssembleSdus
1816 PRIVATE Void kwAssembleSdus (gCb, rbCb, kwDatReq)
1822 Buffer *pdu = NULLP;
1823 MsgLen macGrntSz = kwDatReq->pduSz;
1824 KwAmDl *amDl = &AMDL;
1825 KwSdu *sdu = amDl->nxtTx;
1827 Bool nxtTxUpd = FALSE;
1828 KwuDiscSduInfo *discSduInfo = NULLP;
1829 KwKwuSapCb* kwuSap = gCb->u.dlCb->kwuDlSap + KW_UI_PDCP;
1831 KwContSduLst contSduLst; /*Contained sduLst */
1832 S32 dataVol = amDl->bo;
1833 U32 *totMacGrant = &kwDatReq->totMacGrant;
1834 KwL2MeasDlIpTh *dlIpThPut = &rbCb->l2MeasIpThruput.dlIpTh;
1835 U8 *sduIdx = &dlIpThPut->lastSduIdx;
1837 Bool isSduSegmented;
1840 KwlchInfo *dstLchInfo;
1845 KwL2MeasTb *l2MeasTb;
1847 /* Discard new changes starts */
1851 KwTx *txBuf = NULLP;
1852 /* Discard new changes ends */
1853 VOLATILE U32 startTime = 0;
1857 KwAmHdr *amHdr = NULLP;
1858 KwDlPduInfo *pduInfo = NULLP;
1860 TRC2(kwAssembleSdus)
1864 contSduLst.numSdus = 0;
1865 contSduLst.lcId = rbCb->lch.lChId;
1867 lchInfo.lcId = rbCb->lch.lChId;
1868 lchInfo.numSdus = 0;
1870 /* Discard new changes starts */
1871 /* Allocate memory for discSdu Info */
1872 KW_SHRABL_STATIC_BUF_ALLOC(kwuSap->pst.region,
1875 sizeof(KwuDiscSduInfo));
1877 #if (ERRCLASS & ERRCLS_ADD_RES)
1878 if (discSduInfo == NULLP)
1880 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1881 "Memory allocation failed UEID:%d CELLID:%d",
1883 rbCb->rlcId.cellId);
1886 #endif /* ERRCLASS & ERRCLS_RES */
1888 discSduInfo->numSduIds = 0;
1889 discSduInfo->rlcId = rbCb->rlcId;
1891 kwUtlGetCurrTime(&curTime);
1892 amDl->sduQ.crnt = &sdu->lstEnt;
1893 /* Eliminate fixed header size */
1894 /*5GNR: value of KW_AM_PDU_FIXED_HDRSZ will be 2 or 3 depending on SN Size*/
1895 if(amDl->snLen == KW_AM_CFG_12BIT_SN_LEN)
1897 fixedHdrSz = KW_AM_PDU_12BIT_SN_HDRSZ;
1901 fixedHdrSz = KW_AM_PDU_18BIT_SN_HDRSZ;
1904 while ((macGrntSz > fixedHdrSz) && (sdu != NULLP) &&
1905 (kwDatReq->pduInfo.numPdu < KW_MAX_PDU) &&
1906 (numNewPdu < KW_MAX_NEW_DL_PDU))
1909 isSduSegmented = sdu->mode.am.isSegmented;
1911 /* Discard new changes starts */
1912 if ((sdu->mode.am.isSegmented == FALSE) && (rbCb->discTmrInt > 0) && \
1913 (rbCb->rlcId.rbType == CM_LTE_DRB))
1915 //leftAmSdus[rbCb->qci]--;
1916 timeDiff = KW_TIME_DIFF(curTime,sdu->arrTime);
1917 if (timeDiff > rbCb->discTmrInt)
1921 SStartTask(&startTime, PID_RLC_AMM_DISC_SDUS);
1923 KW_UPD_L2_DL_DISC_SDU_STS(gCb,rbCb);
1924 /* TODO need to send disc cfm to pdcp */
1926 /* Update bo for boReport */
1927 amDl->bo -= sdu->sduSz;
1929 /* Get next sdu for assembly */
1930 nxtNode = sdu->lstEnt.next;
1932 /* store the info for sending it to PDCP */
1933 if(discSduInfo->numSduIds > 500)
1935 RLOG_ARG2(L_ERROR,DBG_RBID, rbCb->rlcId.rbId,
1936 "This is a big error, we shouldn't be here"
1937 "UEID:%d CELLID:%d",
1939 rbCb->rlcId.cellId);
1943 discSduInfo->sduIds[discSduInfo->numSduIds] = sdu->mode.am.sduId;
1944 discSduInfo->numSduIds++;
1946 cmLListDelFrm(&amDl->sduQ, &sdu->lstEnt);
1948 kwUtlAddSduToBeFreedQueue(gCb, sdu);
1949 kwUtlRaiseDlCleanupEvent(gCb);
1951 /* We need to restore the crnt in the linked list which
1952 * would have become NULL in the DelFrm above */
1953 amDl->sduQ.crnt = nxtNode;
1956 sdu = (KwSdu*)nxtNode->node;
1961 SStopTask(startTime, PID_RLC_AMM_DISC_SDUS);
1970 /** kw003.201 - Check for window stall when you are
1971 * creating a new PDU
1973 if (KW_AM_IS_TRANS_WIN_STALLED(amDl))
1976 printf("\n Window stalled \n");
1977 gRlcStats.amRlcStats.numRlcAmCellWinStall++;
1982 hdrEstmt = fixedHdrSz;
1984 if (sdu->mode.am.isSegmented)
1986 /* Adding two byte for SO */
1989 /* Eliminate MAC header */
1990 /* ccpu00135743 : Fix for MAC Hdr size calculation */
1991 /*5GNR: value of mac hdr length field changed to 8/16bits */
1992 pduSz = KW_MIN(macGrntSz, (sdu->sduSz + hdrEstmt));
1993 hdrEstmt += (pduSz < 255) ? KW_MAC_HDR_SZ2 : KW_MAC_HDR_SZ3;
1995 macGrntSz -= hdrEstmt;
1996 /* kw005.201 Check for PDU Size is large enough.
1997 * Fix for ccpu00118973
2004 /* Dont create new txBuf for segmented SDU */
2005 if (!sdu->mode.am.isSegmented)
2008 KW_ALLOC_WC(gCb,txBuf, sizeof(KwTx));
2010 cmLListInit(&txBuf->pduLst);
2012 #if (ERRCLASS & ERRCLS_ADD_RES)
2016 SRegInfoShow(gCb->init.region, &avblMem);
2017 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
2018 "Memory allocation failed UEID:%d CELLID:%d",
2020 rbCb->rlcId.cellId);
2023 #endif /* ERRCLASS & ERRCLS_RES */
2025 kwUtlStoreTxBuf(amDl->txBufLst, txBuf, amDl->txNext);
2029 txBuf = kwUtlGetTxBuf(amDl->txBufLst, amDl->txNext);
2032 KW_ALLOC_WC(gCb,pduInfo, sizeof(KwDlPduInfo));
2033 #if (ERRCLASS & ERRCLS_ADD_RES)
2034 if (pduInfo == NULLP)
2037 SRegInfoShow(gCb->init.region, &avblMem);
2038 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
2039 "Memory allocation failed UEID:%d CELLID:%d",
2041 rbCb->rlcId.cellId);
2044 #endif /* ERRCLASS & ERRCLS_RES */
2046 /*Initialize DL segment structure */
2047 pduInfo->lstEnt.next = NULLP;
2048 pduInfo->lstEnt.prev = NULLP;
2049 pduInfo->lstEnt.node = NULLP;
2051 pduInfo->pdu = NULLP;
2052 pduInfo->amHdr.dc = 0;
2053 pduInfo->amHdr.p = 0;
2054 pduInfo->amHdr.si = 0;
2055 pduInfo->amHdr.so = 0;
2057 pduInfo->amHdr.sn = amDl->txNext;
2059 if (macGrntSz >= sdu->sduSz)
2063 /* Update Framing Info */
2064 if (sdu->mode.am.isSegmented)
2066 /*5GNR RLC: SN should be same for all segment of a SDU*/
2067 pduInfo->amHdr.sn = sdu->mode.am.sn;
2068 pduInfo->amHdr.si = KW_SI_LAST_SEG; /* binary 10 */
2069 pduInfo->amHdr.so = sdu->actSz - sdu->sduSz;
2070 sdu->mode.am.isSegmented = FALSE;
2073 gRlcStats.amRlcStats.numRlcAmCellSduTx++;
2074 //printf("\n 5GNRLOG: last segment of lcId %d SduId %u So %u macGrntSz %u sduActSz %u sdu->sduSz %u\n",
2075 // rbCb->lch.lChId, sdu->mode.am.sduId, pduInfo->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
2079 gRlcStats.amRlcStats.numRlcAmCellSduTx++;
2081 amHdr = &pduInfo->amHdr;
2082 /* Create PDU with hdr and data */
2083 kwAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
2085 //printf("\n Segmentation not required case: numPdu %d pdu %p \n",kwDatReq->pduInfo.numPdu, pdu);
2087 #ifdef LTE_L2_MEAS_RLC
2088 kwUtlUpdSduSnMap(rbCb, sdu, kwDatReq, TRUE);
2089 #endif /* LTE_L2_MEAS */
2091 /* kw005.201 ccpu00117318, updating the statistics */
2092 kwUtlIncrementKwuStsSduTx(gCb->u.dlCb->kwuDlSap + rbCb->kwuSapId);
2094 if(KW_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb))
2098 *sduIdx = dlIpThPut->lastSduIdx;
2102 KW_GETSDUIDX(*sduIdx);
2105 kwUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
2106 kwUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
2107 sdu->mode.am.sduId, newIdx);
2108 /* Update the arrival time for each SDU */
2110 if ( lchInfo.numSdus < KW_L2MEAS_SDUIDX)
2112 lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime;
2117 sduMap.sduSz = sdu->sduSz;
2122 * Allocate buffer for next PDU
2123 * Remove the segmented portion from SDUQ
2124 * Calculate the hdr with LI for SDU */
2126 Buffer *remSeg = NULLP;
2128 //printf("\n SDU segmentation case: numPdu %d pdu %p \n", kwDatReq->pduInfo.numPdu, pdu);
2130 if(KW_MEAS_IS_DL_IP_MEAS_ON_FOR_RB(gCb,rbCb) ||
2131 KW_MEAS_IS_DL_DELAY_MEAS_ON_FOR_RB(gCb,rbCb) ||
2132 KW_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb) )
2134 /* If actual size of the sdu is equal to msgLen
2135 * then it is first segment of the SDU */
2136 if(sdu->actSz == sdu->sduSz)
2138 KW_GETSDUIDX(*sduIdx);
2143 *sduIdx = dlIpThPut->lastSduIdx;
2145 kwUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
2146 kwUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
2147 sdu->mode.am.sduId, newIdx);
2148 if(KW_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb))
2150 /* If actual size of the sdu is equal to msgLen
2151 * then it is first segment of the SDU */
2152 if(sdu->actSz == sdu->sduSz)
2160 /* Segment the SDU to the size of the PDU and update header Info */
2161 SSegMsg(sdu->mBuf, macGrntSz, &remSeg);
2165 /* Update SI and SN */
2166 if (sdu->mode.am.isSegmented)
2168 /*5GNR RLC: SN should be same for all segment of a SDU.
2169 * Sdu was already segmented and segmenting again*/
2170 pduInfo->amHdr.sn = sdu->mode.am.sn;
2171 pduInfo->amHdr.si = KW_SI_MID_SEG; /* binary 11 */
2172 pduInfo->amHdr.so = sdu->actSz - sdu->sduSz;
2174 //printf("\n 5GNRLOG: mid segment of lcId %d SduId %u So %u macGrntSz %u sduActSz %u sdu->sduSz %u\n",
2175 // rbCb->lch.lChId, sdu->mode.am.sduId, txBuf->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
2179 /*5GNR RLC: This means it is the first*/
2180 pduInfo->amHdr.si = KW_SI_FIRST_SEG; /* binary 01 */
2181 /*5GNR_RLC: Store SN so that in sub-seqent SDU segments will use this SN*/
2182 sdu->mode.am.sn = pduInfo->amHdr.sn;
2183 pduInfo->amHdr.so = 0;
2185 //printf("\n 5GNRLOG: First segment of lcId %d SduId %u So %u macGrntSz %u sduActSz %u sdu->sduSz %u\n",
2186 // rbCb->lch.lChId, sdu->mode.am.sduId, txBuf->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
2189 amHdr = &pduInfo->amHdr;
2190 /* Create PDU with hdr and data */
2191 kwAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
2193 sdu->mode.am.isSegmented = TRUE;
2194 sdu->sduSz -= macGrntSz;
2195 sduMap.sduSz = macGrntSz;
2197 #ifdef LTE_L2_MEAS_RLC
2198 kwUtlUpdSduSnMap(rbCb, sdu, kwDatReq, FALSE);
2199 #endif /* LTE_L2_MEAS */
2205 /* Update bo for boReport */
2206 amDl->bo -= sduMap.sduSz;
2210 /* Update pduInfo */
2211 kwDatReq->pduInfo.mBuf[kwDatReq->pduInfo.numPdu] = pdu;
2212 kwDatReq->pduInfo.numPdu++;
2214 /* kw005.201 ccpu00117318, updating the statistics */
2215 gCb->genSts.pdusSent++;
2216 gRlcStats.amRlcStats.numRlcAmCellSduBytesTx = gRlcStats.amRlcStats.numRlcAmCellSduBytesTx + sduMap.sduSz;
2217 /* Update the RLC Tx buffer with the new PDU info */
2218 KW_MEM_CPY(&pduInfo->sduMap, &sduMap, sizeof(KwSduMap));
2221 macGrntSz -= sduMap.sduSz;
2222 /* Get next sdu for assembly */
2223 KW_LLIST_NEXT_SDU(amDl->sduQ, sdu);
2225 } /*End of pduSz loop */
2227 kwDatReq->pduSz = macGrntSz;
2228 /* Updating nxtTx to sdu in the Q */
2233 if(KW_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) &&
2234 (rbCb->rlcId.rbType == CM_LTE_DRB))
2238 l2MeasTb = kwUtlGetCurMeasTb(gCb, rbCb);
2239 kwUtlUpdateBurstSdus(gCb, rbCb, &contSduLst, dataVol, *totMacGrant);
2240 if ((lchInfo.numSdus != 0) && (l2MeasTb != NULLP))
2242 for (lchIdx = 0; ((lchIdx < l2MeasTb->numLchInfo)
2243 && (lchIdx < KW_MAX_ACTV_DRB )); lchIdx++)
2245 if (l2MeasTb->lchInfo[lchIdx].lcId == rbCb->lch.lChId)
2247 /* Lch Info already added in Retx procedure */
2251 if (lchIdx < KW_MAX_ACTV_DRB)
2253 if (lchIdx == l2MeasTb->numLchInfo)
2255 l2MeasTb->lchInfo[lchIdx].lcId = rbCb->lch.lChId;
2256 l2MeasTb->lchInfo[lchIdx].numSdus = 0;
2257 l2MeasTb->numLchInfo++;
2259 dstLchInfo = &l2MeasTb->lchInfo[lchIdx];
2260 currSduIdx = l2MeasTb->lchInfo[lchIdx].numSdus;
2261 while ((numSdus < lchInfo.numSdus) && (currSduIdx < KW_L2MEAS_SDUIDX))
2263 dstLchInfo->sduInfo[currSduIdx].arvlTime = lchInfo.sduInfo[numSdus].arvlTime;
2264 dstLchInfo->sduInfo[currSduIdx].isRetxPdu = FALSE;
2268 l2MeasTb->lchInfo[lchIdx].numSdus += numSdus;
2271 /* Fix Klock warning */
2272 if(l2MeasTb != NULLP)
2274 l2MeasTb->txSegSduCnt += segSduCnt;
2277 *totMacGrant -= (oldBo - amDl->bo);
2280 if(discSduInfo->numSduIds != 0)
2282 /* Sap control block */
2283 KwUiKwuDiscSduCfm(&kwuSap->pst, kwuSap->suId, discSduInfo);
2287 KW_SHRABL_STATIC_BUF_FREE(kwuSap->pst.region, kwuSap->pst.pool, discSduInfo, sizeof(KwuDiscSduInfo));
2292 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
2293 "kwAssembleSdus: BO after assembly = %ld UEID:%d CELLID:%d",
2296 rbCb->rlcId.cellId);
2298 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
2299 "kwAssembleSdus: BO after assembly = %d UEID:%d CELLID:%d",
2302 rbCb->rlcId.cellId);
2309 * @brief Private handler to check if the poll bit needs to be set for data PDU
2312 * Its a private function called by kwProcessSdus, to checks if the
2313 * polling bit needs to be set for any RLC data PDU and updates the
2315 * - For the new PDUs, if the counters exceed the configured
2316 * pduWoPoll/byteWoPoll values, return poll bit.
2317 * - For the PDUs/portion of PDUs, if the SDU list / retxBuf is
2318 * empty, return poll bit.
2319 * - Update the pollPdu, pollByte counters and Poll_SN; start staProhTmr
2321 * @param[in] rCb RLC instance control block
2322 * @param[in] rbCb RB control block
2323 * @param[in] newPdu Flag to indicate if its a new AMD PDU.
2324 * @param[in] bufSz Length of the PDU
2327 * -# 1 - To set the poll bit
2328 * -# 0 - Poll bit is not set
2332 PRIVATE Bool kwAmmDlCheckAndSetPoll
2340 PRIVATE Bool kwAmmDlCheckAndSetPoll(gCb, rbCb, newPdu, bufSz)
2347 Bool pollBit = FALSE;
2348 KwAmDl *amDl = &(rbCb->m.amDl);
2350 TRC2(kwAmmDlCheckAndSetPoll)
2353 /* If it's a new PDU increment PDU without poll and bytes without poll
2354 and check if they cross the configured number of poll pdu and poll bytes*/
2358 /* Patch kw004.201 */
2359 amDl->byteWoPoll += bufSz;
2361 if (((amDl->pollPdu != -1) && (amDl->pduWoPoll >= amDl->pollPdu)) ||
2362 ((amDl->pollByte != -1) && (amDl->byteWoPoll >= amDl->pollByte)))
2368 /* Check if both tx/retx buffer are empty or if tx window is stalled */
2369 if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) ||
2370 KW_AM_IS_TRANS_WIN_STALLED(amDl))
2377 amDl->pduWoPoll = 0;
2378 amDl->byteWoPoll = 0;
2380 amDl->pollSn = (amDl->txNext - 1) & amDl->snModMask;
2382 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
2383 "kwAmmDlCheckAndSetPoll: Poll SN = %d UEID:%d CELLID:%d",
2386 rbCb->rlcId.cellId);
2388 /* kw005.201: Fix for poll retransmission timer.
2389 * Timer is stopped if it is already running and
2390 * then starting the timer. Fixes crs
2391 * ccpu00117216 and ccpu00118284 .
2393 if( TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMDL_POLL_RETX_TMR) )
2395 kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMDL_POLL_RETX_TMR);
2398 kwStartTmr(gCb,(PTR)rbCb, KW_EVT_AMDL_POLL_RETX_TMR);
2405 * @brief Private handler to create AMD PDU
2408 * This function constructs header and concatenate it with the data for
2409 * the PDU. It also updates the txBuf with the created PDU.
2411 * @param[in] gCB RLC instance control block
2412 * @param[in] rbCb Downlink RB control block
2413 * @param[in] amHdr AM header
2414 * @param[in] KwDlPduInfo Pointer to PduInfo
2415 * @param[in] pdu PDU buffer
2421 PRIVATE Void kwAmmCreatePdu
2426 KwDlPduInfo *pduInfo,
2430 PRIVATE Void kwAmmCreatePdu(gCb, rbCb, pduInfo, amHdr, pdu)
2434 KwDlPduInfo *pduInfo;
2438 U8 hdr[KW_MAX_HDRSZ];
2442 KwAmDl *amDl = &(rbCb->m.amDl);
2444 TRC2(kwAmmCreatePdu)
2448 amHdr->sn = amDl->txNext;
2450 /*5GNR RLC: Increment txNext only if no segmentation of it is a last segment */
2451 if((!amHdr->si) || (amHdr->si == KW_SI_LAST_SEG))
2453 //printf("\n 5GNRLOG: no segment/last seg SDU with lcId %d Sn %u txNext %u So %u\n",
2454 // rbCb->lch.lChId, amHdr->sn, amDl->txNext, amHdr->so);
2455 amDl->txNext = (amDl->txNext + 1) & amDl->snModMask;
2458 /* Update hdr Info */
2459 SFndLenMsg(pdu, &pduSz);
2461 /* passing newPDU = TRUE*/
2462 amHdr->p = kwAmmDlCheckAndSetPoll(gCb,rbCb, TRUE, pduSz);
2464 /* Construct header with the available hdr Info, set isSegment to FALSE */
2465 kwConstructAmHdr(amHdr, hdr, amDl->snLen, &idx);
2467 /* Concatenate hdr and data */
2468 SAddPreMsgMultInOrder(hdr, idx+1, pdu);
2470 txBuf = kwUtlGetTxBuf(amDl->txBufLst, amHdr->sn);
2471 kwCpyMsg(gCb,pdu,&(pduInfo->pdu));
2472 pduInfo->pduSz = pduSz;
2473 pduInfo->hdrSz = idx+1;
2475 /*Update estHdrSz. deduct current hdrSz */
2476 amDl->estHdrSz -= pduInfo->hdrSz;
2477 /* Reestimate estHdrSz for mid and last seg */
2480 amDl->estHdrSz += ((amHdr->si == KW_SI_MID_SEG)? pduInfo->hdrSz : (pduInfo->hdrSz + 2));
2483 cmLListAdd2Tail(&txBuf->pduLst, &pduInfo->lstEnt);
2484 pduInfo->lstEnt.node = (PTR)pduInfo;
2486 gCb->genSts.bytesSent += pduSz;
2492 * @brief Private handler to remove the retx PDU from the rbCb
2495 * This function releases a retx PDU stored on DL portion of rbCb.
2496 * It also updates the BO if wtForAck flag is not set which implies
2497 * that it is not sent out yet.
2499 * @param[in] gCb RLC instance control block
2500 * @param[in] retx retransmit PDU to be removed
2501 * @param[in] rbCb Radio Bearer Control Block
2507 PRIVATE Void kwRemRetxPdu
2514 PRIVATE Void kwRemRetxPdu(gCb, rbCb, retx)
2522 cmLListDelFrm(&AMDL.retxLst, &retx->lstEnt);
2524 if( AMDL.retxLst.count == 0)
2526 AMDL.nxtRetx = NULLP;
2529 if(retx->pendingReTrans == TRUE)
2531 AMDL.retxBo -= retx->segSz;
2532 AMDL.estHdrSz -= retx->hdrSz;
2535 kwUtlAddReTxPduToBeFreedQueue(gCb, retx);
2536 kwUtlRaiseDlCleanupEvent(gCb);
2542 * @brief Private handler to mark a retx PDU for further retransmission
2545 * This function sets a retx PDU that has not been ACKed in the
2546 * received Status PDU for futher retransmission. If the retransmission
2547 * limit is reached, it releases the retx PDU and informs the higher
2548 * layers about the same.
2550 * @param[in] gCb RLC instance control block
2551 * @param[in] retx retransmit PDU to be removed
2552 * @param[in] rbCb Radio Bearer Control Block
2558 PRIVATE Void kwAmmDlMarkPduForReTx
2565 PRIVATE Void kwAmmDlMarkPduForReTx(*gCb, rbCb, retx)
2571 TRC2(kwAmmDlMarkPduForReTx)
2572 if (AMDL.maxReTxReached == TRUE)
2577 if(retx->pendingReTrans == FALSE)
2579 retx->pendingReTrans = TRUE;
2582 AMDL.retxBo += retx->segSz;
2583 AMDL.estHdrSz += retx->hdrSz;
2585 if (retx->retxCnt > AMDL.maxRetx)
2587 /* RLC_DL_MAX_RETX fix */
2588 /* Marking the RB stalled for DL scheduling. This is to avoid unnecessary */
2589 /* preparation of RLC PDUs and adding the same to Tx Buffer */
2590 /* This condition is to avoid sending StaIndication more than once */
2591 if (TRUE != rbCb->m.amDl.maxReTxReached)
2593 rbCb->m.amDl.maxReTxReached = TRUE;
2594 rbCb->m.amDl.bo = 0;
2595 rbCb->m.amDl.cntrlBo = 0;
2596 rbCb->m.amDl.retxBo = 0;
2597 /* Sending BO update to SCH */
2598 kwUtlSndDStaRsp(gCb, rbCb, 0,0,0,0);
2599 kwAmmSndStaInd(gCb, rbCb, retx);
2600 gRlcStats.amRlcStats.numDLMaxRetx++;
2603 kwRemRetxPdu(gCb,rbCb, retx);
2609 if (AMDL.nxtRetx == NULLP)
2611 AMDL.nxtRetx = retx;
2614 gRlcStats.amRlcStats.numDLRetransPdus++;
2622 * @brief Private handler to check if SDU is completely deliverd and
2623 * send higher layers data confirmation
2626 * This function sends higher layers data confirmation for SDUs which
2627 * have been successfully delivered to the peer RLC entity.
2629 * @param[in] gCb RLC instance control block
2630 * @param[in] rbCb Radio Bearer Control Block
2631 * @param[in] sduLst List of SDUs that were part of the PDU
2632 * @param[in] numSdu Number of SDUs in the list
2638 PRIVATE Void kwAmmDlCheckIsSDUDelivered
2643 KwuDatCfmInfo **datCfm
2646 PRIVATE Void kwAmmDlCheckIsSDUDelivered(gCb, rbCb, sduMap, datCfm)
2650 KwuDatCfmInfo **datCfm;
2655 TRC2(kwAmmDlCheckIsSDUDelivered)
2659 sdu->mode.am.rcvdSz += sduMap->sduSz;
2661 /* send a dat cfm if all the bytes of the sdu have been received */
2662 if (sdu->mode.am.rcvdSz == sdu->actSz)
2664 /* Send DatCfm for this sdu */
2665 if((*datCfm)->numSduIds < KWU_MAX_DAT_CFM)
2667 (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2671 /* This is an error that should never happen, we should resize
2672 * the #define to a larger value or check why we need to
2673 * send so many confirms in one go
2674 * Confrims to PDCP are being dropped in this case
2677 kwuSap = gCb->u.dlCb->kwuDlSap + KW_UI_PDCP;
2678 KwUiKwuDatCfm(&kwuSap->pst, kwuSap->suId, *datCfm);
2680 KW_SHRABL_STATIC_BUF_ALLOC(kwuSap->pst.region, kwuSap->pst.pool, *datCfm, sizeof(KwuDatCfmInfo));
2682 #if (ERRCLASS & ERRCLS_ADD_RES)
2683 if (*datCfm == NULLP)
2685 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
2686 "Memory allocation failed UEID:%d CELLID:%d",
2688 rbCb->rlcId.cellId);
2691 #endif /* ERRCLASS & ERRCLS_RES */
2693 (*datCfm)->numSduIds = 0;
2694 (*datCfm)->rlcId = rbCb->rlcId;
2695 /* ccpu00135618: say total 1026 sduIds to copy the 1025 sduId after
2696 * new allocation of datCfm */
2697 (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2700 /* Remove SDU from the sduQ */
2701 cmLListDelFrm(&AMDL.sduQ, &sdu->lstEnt);
2702 kwUtlAddSduToBeFreedQueue(gCb, sdu);
2703 kwUtlRaiseDlCleanupEvent(gCb);
2710 * @brief Private handler to mark a PDU successful.
2713 * This function is called when we receive a STATUS pdu that marks
2714 * a PDU as successful. It releases the PDU from RLC entity and
2715 * informs PDCP of successful SDUs delivered as a result of this PDU.
2717 * @param[in] gCb RLC instance control block
2718 * @param[in] rbCb Radio Bearer Control Block
2719 * @param[in] sn SN that is successfully delivered to the peer
2725 PRIVATE Void kwAmmDlProcessSuccessfulTxPdu
2730 KwuDatCfmInfo **datCfm
2733 PRIVATE Void kwAmmDlProcessSuccessfulTxPdu(gCb, rbCb, sn, datCfm)
2737 KwuDatCfmInfo **datCfm;
2740 TRC2(kwAmmDlProcessSuccessfulTxPdu)
2743 KwTx *txBuf = kwUtlGetTxBuf(AMDL.txBufLst, sn);
2749 pduNode = txBuf->pduLst.first;
2752 KwDlPduInfo *pduInfo = (KwDlPduInfo *)(pduNode->node);
2753 kwAmmDlCheckIsSDUDelivered(gCb,
2757 pduNode = pduNode->next;
2760 kwUtlAddTxPduToBeFreedQueue(gCb, txBuf);
2761 kwUtlRaiseDlCleanupEvent(gCb);
2762 /* so that it is not processed again */
2763 kwUtlRemovTxBuf(AMDL.txBufLst, txBuf, gCb);
2769 * @brief Handler to send Status Indication to PDCP
2772 * This function is used to send status indication to PDCP when the
2773 * maximum retransmission threshold value is reached for a PDU.
2775 * @param[in] gCb RLC instance control block
2776 * @param[in] rbCb RB control block
2777 * @param[in] retx The PDU/segment that failed max re-transmissions
2783 PRIVATE Void kwAmmSndStaInd
2790 PRIVATE Void kwAmmSndStaInd(gCb, rbCb, retx)
2796 KwuStaIndInfo *staInd;
2799 TRC2(kwAmmSndStaInd);
2802 /* Sap control block */
2803 kwuSap = gCb->u.dlCb->kwuDlSap + KW_UI_PDCP;
2805 /* Allocate memory for staInd Info */
2806 KW_SHRABL_STATIC_BUF_ALLOC(kwuSap->pst.region, kwuSap->pst.pool, staInd, sizeof(KwuStaIndInfo));
2808 #if (ERRCLASS & ERRCLS_ADD_RES)
2809 if (staInd == NULLP)
2811 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
2812 "Memory allocation failed UEID:%d CELLID:%d",
2814 rbCb->rlcId.cellId);
2817 #endif /* ERRCLASS & ERRCLS_RES */
2819 /* Fill staInd Info */
2820 KW_MEM_CPY(&staInd->rlcId, &rbCb->rlcId, sizeof(CmLteRlcId));
2823 staInd->sduId[0] = retx->sduMap.sdu->mode.am.sduId;
2827 KwUiKwuStaInd(&kwuSap->pst, kwuSap->suId, staInd);
2828 #endif /* KW_PDCP */
2834 * @brief Handler to get the next node to be retransmitted from retxLst
2837 * This function is used to get the next node to be retransmitted
2840 * @param[in] gCb RLC instance control block
2841 * @param[in] retx The PDU/segment after which to find a node to be
2848 PRIVATE Void kwGetNxtRetx
2854 PRIVATE Void kwGetNxtRetx(gCb, retx)
2865 tNode = &((*retx)->lstEnt);
2866 tNode = tNode->next;
2870 *retx = (KwRetx *)tNode->node;
2877 }while((*retx)->pendingReTrans == FALSE);
2883 * @brief Handler to process the re-establishment request received from UIM
2885 * @param[in] gCb RLC instance control block
2886 * @param[in] rlcId Identity of the RB in the UE/Cell for which
2887 * re-establishment is to be done
2888 * @param[in] rbCb Downlink RB control block (rbCb is freed in this
2895 PUBLIC Void kwAmmDlReEstablish
2902 PUBLIC Void kwAmmDlReEstablish(gCb, rlcId, rbCb)
2908 /* create a new AM DL RB, reset it and replace in the UeCb*/
2913 KW_ALLOC(gCb, resetRb, sizeof(KwDlRbCb));
2915 /* ccpu00135170 Removing KLOCK warning */
2916 if(resetRb == NULLP)
2921 KW_MEM_CPY(resetRb, rbCb, sizeof(KwDlRbCb));
2922 KW_MEM_SET(&resetRb->m.amDl, 0 , sizeof(KwAmDl));
2924 /* AGHOSH changes start */
2925 /* restore the old AM values */
2926 newAmDl = &resetRb->m.amDl;
2927 oldAmDl = &rbCb->m.amDl;
2929 newAmDl->pollPdu = oldAmDl->pollPdu;
2930 newAmDl->pollByte = oldAmDl->pollByte;
2931 newAmDl->maxRetx = oldAmDl->maxRetx;
2932 newAmDl->snLen = oldAmDl->snLen;
2933 newAmDl->snModMask = oldAmDl->snModMask;
2934 newAmDl->pollRetxTmrInt = oldAmDl->pollRetxTmrInt;
2935 rbCb->boUnRprtdCnt = (U32)0;
2936 rbCb->lastRprtdBoToMac = (U32)0;
2937 cmInitTimers(&(resetRb->m.amDl.pollRetxTmr), 1);
2938 /* AGHOSH changes end */
2940 if (ROK != kwDbmFetchDlUeCb(gCb,rlcId.ueId, rlcId.cellId, &ueCb))
2942 RLOG_ARG2(L_ERROR,DBG_CELLID, rlcId.cellId,
2943 "UeId [%d]: UeCb not found RBID;%d",
2949 if(rlcId.rbType == CM_LTE_SRB)
2951 ueCb->srbCb[rlcId.rbId] = resetRb;
2955 ueCb->drbCb[rlcId.rbId] = resetRb;
2957 /* update into the logical channel array also */
2958 ueCb->lCh[rbCb->lch.lChId - 1].dlRbCb = resetRb;
2960 if((resetRb->rlcId.rbType == CM_LTE_SRB)
2961 &&(resetRb->rlcId.rbId == 1))
2963 /* To stop the traffic on SRB2 and other DRBs*/
2964 kwDlUtlSetReestInProgressForAllRBs(gCb, ueCb);
2968 kwDlUtlSetReestInProgressForRB(gCb, resetRb);
2971 /* allocate the TX array again */
2975 resetRb->m.amDl.txBufLst,
2976 (KW_TX_BUF_BIN_SIZE * sizeof(CmLListCp)));
2977 for(hashIndex = 0; hashIndex < KW_TX_BUF_BIN_SIZE; hashIndex++)
2979 cmLListInit(&(resetRb->m.amDl.txBufLst[hashIndex]));
2982 /* send the old rb of deletion */
2983 kwAmmFreeDlRbCb(gCb,rbCb);
2986 /* TODO: for now we are re-settting the re-establishment flag here
2987 this needs to be fixed
2988 There should be a proper intreface to resume the RBs */
2989 if(rlcId.rbType == CM_LTE_SRB)
2991 kwDlUtlResetReestInProgress(ueCb->srbCb[rlcId.rbId]);
2995 kwDlUtlResetReestInProgress(ueCb->drbCb[rlcId.rbId]);
3002 * @brief Handler to discard a SDU.
3005 * This function is used to discard a SDU after receiving
3006 * the Discard Request from UIM. The SDU is discarded if its
3007 * available and is not mapped to any PDU yet.
3009 * @param[in] gCb RLC instance control block
3010 * @param[in] rbCb RB control block
3011 * @param[in] sduId Sdu ID of the SDU to be discarded
3014 * -# ROK In case of successful discard
3015 * -# RFAILED In case the SDU is not found or already mapped
3018 PUBLIC S16 kwAmmDiscSdu
3025 PUBLIC S16 kwAmmDiscSdu(gCb, rbCb, sduId)
3036 * @brief Handler for Poll retransmit timer expiry
3039 * This function is used to handle events upon expiry of Poll
3042 * @param[in] gCb RLC instance control block
3043 * @param[in] rbCb Downlink RB control block
3048 PUBLIC Void kwAmmPollRetxTmrExp
3054 PUBLIC Void kwAmmPollRetxTmrExp(gCb, rbCb)
3060 KwAmDl *amDl = &(rbCb->m.amDl);
3063 TRC2(kwAmmPollRetxTmrExp);
3066 /* kw003.201 - Correcting the logic for determmining whether to do */
3067 /* any transmission of PDU. As per the spec section */
3068 /* 5.2.2.3, if there is any to transmit or retransmit, */
3069 /* do nothing. Else, pick up the VT(S) -1 for retx */
3070 /* We have nothing to transmit if window is stalled or */
3071 /* there are no SDUs to be transmitted or if there are */
3072 /* PDUs to be retransmitted. */
3073 if(CM_LTE_SRB == rbCb->rlcId.rbType)
3075 gRlcStats.amRlcStats.numDLPollTimerExpiresSrb++;
3079 gRlcStats.amRlcStats.numDLPollTimerExpiresDrb++;
3082 if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) ||
3083 KW_AM_IS_TRANS_WIN_STALLED(amDl))
3085 sn = (amDl->txNext - 1) & amDl->snModMask;
3086 txBuf = kwUtlGetTxBuf(amDl->txBufLst, sn);
3090 kwAmmDlMoveFrmTxtoRetxBuffer(gCb,amDl, &retx, sn);
3092 if (AMDL.nxtRetx == NULLP)
3094 AMDL.nxtRetx = retx;
3097 kwAmmSendDStaRsp(gCb, rbCb, &AMDL);
3100 /* Get the last node in retxLst */
3101 KW_LLIST_LAST_RETX(amDl->retxLst, retx);
3103 /* Unset wtForAck flag for the NACK PDUs */
3106 kwAmmDlMarkPduForReTx(gCb, rbCb, retx);
3107 kwAmmSendDStaRsp(gCb, rbCb, &AMDL);
3115 * @brief Handler to update Acks for the remaining PDUs after the last accessed
3119 * This function is used to handle ACKs for the PDUs remaining after the
3120 * last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and
3121 * sends DatCfm to PDCP for the same.
3123 * @param[in] gCb RLC instance control block
3124 * @param[in] rbCb Downlink Radio Bearer control block
3125 * @param[in] mAckSn The ACK SN after doing the base modulus
3126 * @param[in] rextNode Next node in the re-transmission buffer
3133 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForAckSn
3139 KwuDatCfmInfo **datCfm
3142 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForAckSn(gCb, rbCb, mAckSn, retxNode, datCfm)
3147 KwuDatCfmInfo **datCfm;
3155 TRC2(kwAmmDlUpdateTxAndReTxBufForAckSn);
3157 /* Remove pdus/segs from retxLst */
3160 retx = (KwRetx *)(retxNode->node);
3161 retxNode = retxNode->next;
3162 MODAMT(retx->amHdr.sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3165 kwAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
3169 /* For the remaining; pdus not acknowldeged by the NACK_SN but being
3170 acknowledged by the ACK_SN*/
3171 /* start from the starting of the transmission window and remove till just
3173 mSn = 0; /* same as MODAMT(AMDL.txNextAck, mSn, AMDL.txNextAck);*/
3174 sn = AMDL.txNextAck;
3177 txBuf = kwUtlGetTxBuf(AMDL.txBufLst, sn);
3180 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
3181 "kwAmmDlUpdateTxAndReTxBufForAckSn: ACK for PDU "
3182 "with sn = %ld UEID:%ld CELLID:%ld",
3185 rbCb->rlcId.cellId);
3187 kwAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
3190 sn = (sn + 1) & AMDL.snModMask;
3191 MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3198 * @brief Handler to update Acks for the remaining PDUs after the last accessed
3202 * This function is used to handle ACKs for the PDUs remaining after the
3203 * last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and
3204 * sends DatCfm to PDCP for the same.
3206 * @param[in] gCb RLC instance control block
3207 * @param[in] rbCb Downlink Radio Bearer control block
3208 * @param[in] mAckSn The ACK SN after doing the base modulus
3209 * @param[in] rextNode Next node in the re-transmission buffer
3215 PRIVATE Void kwAmmDlUpdTxAndReTxBufForLessThanNackSn
3222 KwuDatCfmInfo **datCfm
3225 PRIVATE Void kwAmmDlUpdTxAndReTxBufForLessThanNackSn(gCb, rbCb, sn, mNackSn, retxNode, datCfm)
3231 KwuDatCfmInfo **datCfm;
3238 TRC2(kwAmmDlUpdTxAndReTxBufForLessThanNackSn);
3242 retx = (KwRetx *)((*retxNode)->node);
3243 MODAMT(retx->amHdr.sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3246 (*retxNode) = (*retxNode)->next;
3247 kwAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
3255 /* Remove all pdus with SN < NACK_SN from the transmission buffer */
3256 MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3257 while (mSn < mNackSn)
3259 /* this if check seems redundant,why should mSn ever be mTxSn
3260 (which actually is VT(A) */
3261 txBuf = kwUtlGetTxBuf(AMDL.txBufLst, sn);
3262 if ((txBuf != NULLP))
3264 RLOG_ARG3(L_DEBUG,DBG_RBID, rbCb->rlcId.rbId,
3265 "kwHndlStaRsp: Handle ACK (sn = %d) UEID:%d CELLID:%d",
3268 rbCb->rlcId.cellId);
3270 /* Remove pdus from txBuf */
3271 kwAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
3274 sn = (sn + 1) & AMDL.snModMask;
3275 MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3283 * @brief Handler to form construct AM header
3286 * This function is used to construct am header with the available header
3289 * @param[in] gCb RLC instance control block
3290 * @param[in] amHdr AM Header
3291 * @param[in] isSeg Check for Segmentation of PDU
3292 * @param[in] hdr Header field
3293 * @param[in] idx Index
3299 PRIVATE Void kwConstructAmHdr
3307 PRIVATE Void kwConstructAmHdr(amHdr, hdr, snLen, idx)
3314 TRC2(kwConstructAmHdr);
3317 hdr[0] = KW_DATA_BITMASK;
3319 hdr[0] = hdr[0] | (amHdr->p << 6);
3320 hdr[0] = hdr[0] | ((amHdr->si & 0x3) << 4);
3321 if(snLen == KW_AM_CFG_12BIT_SN_LEN)
3323 hdr[0] = hdr[0] | (U8)((amHdr->sn & 0xF00) >> 8);
3324 hdr[1] = (U8)(amHdr->sn & 0x0FF);
3329 hdr[0] = hdr[0] | (U8)((amHdr->sn & 0x30000) >> 16);
3330 hdr[1] = (U8)((amHdr->sn & 0xFF00) >> 8);
3332 hdr[2] = (U8)(amHdr->sn & 0xFF);
3336 if ((amHdr->si == KW_SI_MID_SEG) || (amHdr->si == KW_SI_LAST_SEG))
3339 hdr[(*idx)] = (U8)((amHdr->so & 0xFF00)>> 8);
3341 hdr[(*idx)] = (U8)(amHdr->so & 0xFF);
3348 * @brief This function adds a retx PDU to list of retx PDUs
3351 * kw003.201 - Poll expiry may cause an SN to be added to retx
3352 * out of sequence and hence all additions to retx
3353 * must validate that they are added in sequence
3355 * @param[in] amDl AM Downlink Control Block
3356 * @param[in] retx Retransmit PDU
3362 PRIVATE Void kwAmmAddPduToRetxLst
3368 PRIVATE Void kwAmmAddPduToRetxLst(amDl, retx)
3378 TRC2(kwAmmAddPduToRetxLst);
3380 node = amDl->retxLst.last;
3381 MODAMT(retx->amHdr.sn, retxMSn, amDl->txNextAck,amDl->snModMask);
3382 while(node != NULLP)
3384 tRetx = (KwRetx *)(node->node);
3385 MODAMT(tRetx->amHdr.sn, tMSn, amDl->txNextAck,amDl->snModMask);
3397 amDl->retxLst.crnt = node;
3398 cmLListInsAfterCrnt(&amDl->retxLst, &retx->lstEnt);
3399 retx->lstEnt.node = (PTR)retx;
3403 amDl->retxLst.crnt = amDl->retxLst.first;
3404 cmLListInsCrnt(&amDl->retxLst, &retx->lstEnt);
3405 retx->lstEnt.node = (PTR)retx;
3408 if (amDl->nxtRetx == NULLP)
3410 amDl->nxtRetx = retx;
3417 * @brief Handler to Move the PDU from txBuf to re-transmission buffer
3420 * This function is used to move the PDU from the txBuf to re-transmit buffer
3422 * @param[in] gCb RLC instance control block
3423 * @param[in] amDl AM Downlink Control Block
3424 * @param[in] retx node in the reTx buffer to be moved to, allocated by
3426 * @param[in] sn SN in the tx buffer which needs to be moved
3433 PRIVATE Void kwAmmDlMoveFrmTxtoRetxBuffer
3441 PRIVATE Void kwAmmDlMoveFrmTxtoRetxBuffer(gCb, amDl, retx, sn)
3448 KwTx* txBuf = kwUtlGetTxBuf(amDl->txBufLst, sn);
3449 TRC2(kwAmmDlMoveFrmTxtoRetxBuffer);
3455 while(txBuf->pduLst.first)
3457 KwDlPduInfo *pduInfo = (KwDlPduInfo *)(txBuf->pduLst.first->node);
3458 KW_ALLOC_WC(gCb,*retx, sizeof(KwRetx));
3460 #if (ERRCLASS & ERRCLS_ADD_RES)
3463 RLOG0(L_FATAL, "Memory allocation failed");
3466 #endif /* ERRCLASS & ERRCLS_RES */
3468 /* Move Sdu byte segment from TX buf to retx buf*/
3469 kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb,
3474 /* Delete node from the txBuf Pdu lst */
3475 cmLListDelFrm(&txBuf->pduLst, txBuf->pduLst.first);
3476 KW_FREE_WC(gCb, pduInfo, sizeof(KwDlPduInfo));
3478 /* Remove PDU from txBuf */
3479 kwUtlDelTxBuf(amDl->txBufLst, txBuf,gCb);
3488 * function to free/release the Acknowledged mode RBCB buffers
3491 * This primitive Frees the Acknowledged Mode RbCb transmission Buffer,
3492 * retransmission Buffer and reciption Buffers
3494 * @param [in] gCb - RLC instance control block
3495 * @param [in] rbCb - Downlink RB Control Block
3500 PUBLIC Void kwAmmFreeDlRbCb
3506 PUBLIC Void kwAmmFreeDlRbCb(gCb,rbCb)
3511 /* stop the re-transmission timer */
3512 if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMDL_POLL_RETX_TMR))
3514 kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMDL_POLL_RETX_TMR);
3517 /* store the entire Rb pointer */
3518 rbCb->rlsLnk.node = (PTR)rbCb;
3519 cmLListAdd2Tail(&gCb->u.dlCb->toBeFreed.rbLst, &rbCb->rlsLnk);
3522 cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.amDl.sduQ));
3524 kwUtlRaiseDlCleanupEvent(gCb);
3530 * @brief Handler to create STATUS Pdu
3533 * This function is used to create status pdu
3535 * @param[in] gCb RLC instance control block
3536 * @param[in] rbCb Downlink RB control block
3537 * @param[in] kwDatReq The data to be passed to MAC
3543 PRIVATE Void kwAmmCreateStatusPdu
3550 PRIVATE Void kwAmmCreateStatusPdu(gCb, rbCb, kwDatReq)
3556 KwSn sn; /* sequence number */
3557 KwSn ack_sn; /* Ack sequence number */
3558 Buffer *mBuf; /* control pdu buffer */
3559 MsgLen cntrlPduSz; /* control pdu size */
3560 U8 cntrlPdu[KW_MAX_CNTRL_FIELDS]; /* control pdu to be added to mBuf */
3561 KwUdxDlStaPdu *pStaPdu;
3562 U16 bytesToEncode = 0; /* bytes required to encode the STATUS PDU */
3565 KwNackInfo *kwNackInfo;
3568 TRC2(kwAmmCreateStatusPdu)
3571 pStaPdu = AMDL.pStaPdu;
3580 /* ACK SN Field will be set in the end based on available Grant */
3582 encIdx = bytesToEncode = 3; /* Num Octets before NACK SN info encoding*/
3584 ack_sn = pStaPdu->ackSn;
3586 if (rbCb->m.amDl.snLen == KW_AM_CFG_12BIT_SN_LEN)
3589 /* If alteast one NACK SN Info then set the E1 field */
3590 if (pStaPdu->nackCount)
3600 for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3602 sn = pStaPdu->nackInfo[nkCnt].sn;
3604 kwNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3606 bytesToEncode += 2; /* 2 Octets for NACK SN */
3608 /* Check if E2 : isSegment is set */
3609 if (kwNackInfo->isSegment)
3611 bytesToEncode += 4; /* 4 Octets: SOstart, SOend */
3614 /* Check if E3 : nackRange is set */
3615 if (kwNackInfo->nackRange)
3617 bytesToEncode += 1; /* 1 Octet: NACK range */
3620 /* Check if this NACK info can be accomodated in the Grant */
3621 if( kwDatReq->pduSz >= bytesToEncode)
3623 /* If there is a NACK SN before this then set its
3627 /* NACKSN E1 E2 E3 R */
3628 cntrlPdu[prevEncIdx + 1] |= 0x8;
3631 /* 12 BIT Nack SN encode */
3632 cntrlPdu[encIdx] = (sn & 0xFF0) >> 4;
3635 cntrlPdu[encIdx + 1] = (sn & 0xF) << 4;
3637 if (kwNackInfo->isSegment)
3640 cntrlPdu[encIdx + 1] |= 0x4;
3643 /* Add soStart and soEnd */
3645 cntrlPdu[encIdx + 2] = (kwNackInfo->soStart) >> 8;
3646 cntrlPdu[encIdx + 3] = kwNackInfo->soStart & 0xFF;
3649 cntrlPdu[encIdx + 4] = (kwNackInfo->soEnd) >> 8;
3650 cntrlPdu[encIdx + 5] = kwNackInfo->soEnd & 0xFF;
3653 if (kwNackInfo->nackRange)
3656 cntrlPdu[encIdx + 1] |= 0x2;
3657 if(kwNackInfo->isSegment)
3659 cntrlPdu[encIdx + 6] = kwNackInfo->nackRange;
3663 cntrlPdu[encIdx + 2] = kwNackInfo->nackRange;
3667 gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3669 /* Set ACK SN now */
3672 ack_sn = kwNackInfo->sn;
3674 /* Not even one nack can be accomodated */
3683 prevEncIdx = encIdx;
3684 encIdx = bytesToEncode;
3686 }/* Loop is done for the NackCount */
3691 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
3692 "kwAssembleCntrlInfo: ACK PDU's SN = %d"
3693 "UEID:%d CELLID:%d",
3696 rbCb->rlcId.cellId);
3698 cntrlPdu[0] |= (ack_sn & 0xF00)>> 8;
3699 cntrlPdu[1] = (U8)ack_sn;
3703 else if (rbCb->m.amDl.snLen == KW_AM_CFG_18BIT_SN_LEN)
3705 /* If alteast one NACK SN Info then set the E1 field */
3706 if (pStaPdu->nackCount)
3716 for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3718 sn = pStaPdu->nackInfo[nkCnt].sn;
3720 kwNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3722 bytesToEncode += 3; /* 3 Octets for NACK SN */
3724 /* Check if E2 : isSegment is set */
3725 if (kwNackInfo->isSegment)
3727 bytesToEncode += 4; /* 4 Octets: SOstart, SOend */
3730 /* Check if E3 : nackRange is set */
3731 if (kwNackInfo->nackRange)
3733 bytesToEncode += 1; /* 1 Octet: NACK range */
3736 /* Check if this NACK info can be accomodated in the Grant */
3737 if( kwDatReq->pduSz >= bytesToEncode)
3739 /* If there is a NACK SN before this then set its
3743 /* NACKSN E1 E2 E3 R R R */
3744 cntrlPdu[prevEncIdx + 2] |= 0x20;
3747 /* 18 BIT Nack SN encode */
3748 cntrlPdu[encIdx] = (U8)((sn & 0x3FC00) >> 10);
3751 cntrlPdu[encIdx + 1] = (U8)((sn & 0x3FC) >> 2);
3754 cntrlPdu[encIdx + 2] = (U8)((sn & 0x3)<< 6);
3756 if (kwNackInfo->isSegment)
3758 /* NACKSN E1 E2 E3 R R R */
3760 cntrlPdu[encIdx + 2] |= 0x10;
3763 /* Add soStart and soEnd */
3765 cntrlPdu[encIdx + 3] = (kwNackInfo->soStart) >> 8;
3766 cntrlPdu[encIdx + 4] = (U8)kwNackInfo->soStart;
3769 cntrlPdu[encIdx + 5] = (kwNackInfo->soEnd) >> 8;
3770 cntrlPdu[encIdx + 6] = (U8)(kwNackInfo->soEnd);
3773 if (kwNackInfo->nackRange)
3775 /* NACKSN E1 E2 E3 R R R */
3777 cntrlPdu[encIdx + 2] |= 0x08;
3779 if (kwNackInfo->isSegment)
3781 cntrlPdu[encIdx + 7] = kwNackInfo->nackRange;
3785 cntrlPdu[encIdx + 3] = kwNackInfo->nackRange;
3789 gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3791 /* Set ACK SN now */
3794 ack_sn = kwNackInfo->sn;
3796 /* Not even one nack can be accomodated */
3799 cntrlPdu[2] &= 0xFD;
3805 prevEncIdx = encIdx;
3806 encIdx = bytesToEncode;
3808 }/* Loop is done for the NackCount */
3813 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
3814 "kwAssembleCntrlInfo: ACK PDU's SN = %d"
3815 "UEID:%d CELLID:%d",
3818 rbCb->rlcId.cellId);
3821 cntrlPdu[0] |= (ack_sn & 0x3C000) >> 14;
3822 cntrlPdu[1] = (ack_sn & 0x3FC0) >> 6;
3823 cntrlPdu[2] |= (ack_sn & 0x3F)<< 2;
3830 RLOG_ARG3(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
3831 "kwAssembleCntrlInfo:Conf SN LEN %d is INVALID !!!! UEID:%d CELLID:%d",
3834 rbCb->rlcId.cellId);
3839 SGetMsg(KW_GET_MEM_REGION(gCb), KW_GET_MEM_POOL(gCb),&mBuf);
3841 mBuf = (Buffer *)kwAmmStaPduList[kwAmmStaPduListCnt++];
3843 if(kwAmmStaPduListCnt > 511)
3844 kwAmmStaPduListCnt = 0;
3847 cntrlPduSz = encIdx;
3848 SAddPstMsgMult (cntrlPdu, cntrlPduSz, mBuf);
3850 kwDatReq->pduSz -= cntrlPduSz;
3851 /* Add mBuf to AMDL.mBuf */
3857 #ifdef RLC_STA_PROC_IN_MAC/* RLC Status PDU Processing */
3859 S16 kwProcDlStatusPdu(Pst *udxPst,SuId suId,
3860 CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu);
3863 PRIVATE Void rgAmmExtractElmnt
3870 PRIVATE Void rgAmmExtractElmnt(gCb, pdu, hdrInfo)
3877 U8 pLen = hdrInfo->pLen;
3878 U8 len = (U8)hdrInfo->len;
3886 TRC2(kwAmmExtractElmnt);
3892 SRemPreMsg(&hdr, pdu);
3898 val = tHdr >> (KW_BYTE_LEN - (len));
3902 else /*if (len > 8) */
3906 val = val >> (KW_BYTE_LEN - fLen);
3907 val = val << (len - fLen);
3909 SRemPreMsg(&hdr, pdu);
3913 hdr = hdr >> (KW_BYTE_LEN - rLen);
3916 pLen = (KW_BYTE_LEN - rLen);
3920 rLen = rLen - KW_BYTE_LEN;
3922 tVal = tVal << rLen;
3925 SRemPreMsg(&hdr, pdu);
3927 hdr = hdr >> (KW_BYTE_LEN - rLen);
3930 pLen = (KW_BYTE_LEN - rLen);
3934 hdrInfo->pLen = pLen;
3945 PRIVATE Void rgAmmUlHndlStatusPdu
3955 PRIVATE Void rgAmmUlHndlStatusPdu(udxPst,suId,gCb, rbCb, cntrlPdu, fByte)
3966 KwUdxStaPdu *pStaPdu;
3967 U8 e3; /* NACK RANGE : 5GNR */
3970 U32 resrvdBitsAckSn;
3971 U32 resrvdBitsNackSn;
3974 TRC2(rgAmmUlHndlStatusPdu)
3976 KWDBGP_BRIEF(gCb, "rgAmmUlHndlStatusPdu(rbCb, cntrlPdu, fByte) \n");
3978 KW_MEM_ZERO(&hdrInfo, sizeof(KwExtHdr));
3980 /* Extract the Control PDU */
3981 hdrInfo.hdr = (*fByte << 1);
3984 /* D/C has been shifted in the calling function */
3985 if (hdrInfo.hdr & 0xE0)
3987 KWDBGP_ERROR(gCb, "rgAmmUlHndlStatusPdu: Reserved value for CPT received \n");
3991 KW_ALLOC_SHRABL_BUF(udxPst->region,
3994 sizeof(KwUdxStaPdu));
3996 #if (ERRCLASS & ERRCLS_ADD_RES)
3997 /* Memory allocation failure can not be expected */
4004 if (rbCb->m.amDl.snLen == KW_AM_CFG_12BIT_SN_LEN)
4007 resrvdBitsAckSn = KW_STA_PDU_R_BITS_ACKSN_12BITS;
4008 resrvdBitsNackSn = KW_STA_PDU_R_BITS_NACKSN_12BITS;
4010 else if (rbCb->m.amDl.snLen == KW_AM_CFG_18BIT_SN_LEN)
4013 resrvdBitsAckSn = KW_STA_PDU_R_BITS_ACKSN_18BITS;
4014 resrvdBitsNackSn = KW_STA_PDU_R_BITS_NACKSN_18BITS;
4019 resrvdBitsAckSn = 0;
4020 resrvdBitsAckSn = 0;
4023 pStaPdu->nackCnt = 0;
4025 hdrInfo.hdr = hdrInfo.hdr << KW_CPT_LEN;
4028 hdrInfo.len = KW_SN_LEN;
4029 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4030 pStaPdu->ackSn = hdrInfo.val;
4032 /* Check if NACK Exists */
4033 hdrInfo.len = KW_E1_LEN;
4034 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4035 e1 = (U8)hdrInfo.val;
4036 KWDBGP_DETAIL(gCb, "rgAmmUlHndlStatusPdu: ACK SN = %d \n", pStaPdu->ackSn);
4038 /* Extract the Reserved Bits after ACK SN field */
4039 hdrInfo.len = resrvdBitsAckSn;
4040 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4043 /* If NACK exists in control PDU */
4044 /* For ACKs and NACKs */
4045 while (e1 && (pStaPdu->nackCnt < KW_MAX_NACK_CNT))
4047 hdrInfo.len = snLen;
4048 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4049 pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
4051 hdrInfo.len = KW_E1_LEN;
4052 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4053 e1 = (U8)hdrInfo.val;
4056 /* hdrInfo.len = KW_E1_LEN; --> previusly stored value (for e1) is
4058 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4059 /* e2 = (U8) hdrInfo.val;*/
4061 /* Store e2 value */
4062 pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (U8) hdrInfo.val;
4064 /* Extract e3 : 5GNR */
4065 /* hdrInfo.len = KW_E1_LEN; --> previusly stored value (for e1) is
4067 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4068 e3 = (U8) hdrInfo.val;
4070 /* Extract Reserved Bits after NACK SN */
4071 hdrInfo.len = resrvdBitsNackSn;
4072 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4074 /* Test for resegmentation */
4075 if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
4077 hdrInfo.len = KW_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
4078 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4079 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
4081 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4082 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = hdrInfo.val;
4085 "rgAmmUlHndlStatusPdu: soStart and soEnd = %d %d \n",
4086 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
4087 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd);
4092 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
4093 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = 0;
4096 /* NACK RANGE Field is SET */
4099 /* Extract NACK range field */
4100 hdrInfo.len = KW_NACK_RANGE_LEN;
4101 rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4102 snRange = (U8)hdrInfo.val;
4104 pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
4110 gRlcStats.amRlcStats.numULStaPduRcvd++;
4111 gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
4113 /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
4114 to the last NACK SN + 1 and discard the original ACK_SN*/
4115 if(pStaPdu->nackCnt == KW_MAX_NACK_CNT)
4117 pStaPdu->ackSn = (pStaPdu->nackInfo[KW_MAX_NACK_CNT-1].sn + 1) & amDl->snModMask;
4121 /* Parse & send Status PDU to RLC-DL */
4122 //KwUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
4123 KwUlUdxStaUpdReq(udxPst, suId, &rbCb->rlcId, pStaPdu);
4128 PUBLIC S16 kwProcDlStatusPdu(Pst *udxPst,SuId suId,
4129 CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu)
4131 KwDlRbCb *rbCb = NULLP;
4132 KwDlUeCb *ueCb = NULLP;
4135 S16 retVal = RFAILED;
4137 Pst dlRlcPst = *udxPst;
4139 gCb = KW_GET_KWCB(1); /* DL RLC instance */
4141 if( ROK != kwDbmFetchDlUeCb(gCb,rnti,cellId,&(ueCb)))
4143 printf("\n RLC UECb Not found...\n");
4148 rbCb = ueCb->lCh[lcId - 1].dlRbCb;
4150 /* Skip if mode is not AM */
4151 if((rbCb == NULLP) || (rbCb->mode != CM_LTE_MODE_AM))
4156 if(ROK != SExamMsg((Data *)(&fByte),
4159 printf("\n Failure in Rlc Hdr SExamMsg\n");
4163 if(KW_CNTRL_PDU == ((fByte & KW_DC_POS) >> KW_DC_SHT))
4165 SRemPreMsg(&temp, rlcSdu);
4166 dlRlcPst.selector = 1;/* LWLC*/
4167 rgAmmUlHndlStatusPdu(&dlRlcPst,suId,gCb, rbCb, rlcSdu, &fByte);
4181 /********************************************************************30**
4184 **********************************************************************/