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 /**********************************************************************
25 Desc: Source code for RLC Unacknowledged mode assembly and
26 reassembly.This file contains following functions
36 **********************************************************************/
37 static const char* RLOG_MODULE_NAME="RLC";
38 static int RLOG_MODULE_ID=2048;
39 static int RLOG_FILE_ID=239;
42 * @brief RLC Unacknowledged Mode downlink module
45 /* header (.h) include files */
46 #include "common_def.h"
47 #include "ckw.h" /* RRC layer */
48 #include "lkw.h" /* RRC layer */
49 #include "kwu.h" /* RLC service user */
50 #include "lkw.h" /* LM Interface */
51 #include "rgu.h" /* MAC layer */
52 #include "kw_env.h" /* RLC environment options */
54 #include "kw.h" /* RLC layer */
60 /* header/extern include files (.x) */
62 #include "ckw.x" /* RRC layer */
63 #include "kwu.x" /* RLC service user */
64 #include "lkw.x" /* LM Interface */
65 #include "rgu.x" /* MAC later */
67 #include "kw.x" /* RLC layer */
71 #define KW_MODULE (KW_DBGMASK_UM | KW_DBGMASK_DL)
73 /* variables for logging :declared in BRDCM cl */
75 extern U32 dldrops_kwu_um;
77 extern U32 buffer_occ;
78 extern U32 dlrate_kwu;
81 PRIVATE Void kwUmmEstHdrSz ARGS ((KwUmDl *umUl));
83 PRIVATE Void kwUmmCreatePdu ARGS ((RlcCb *gCb,
87 KwPduInfo *datReqPduInfo));
89 /** @addtogroup ummode */
93 * @brief Handler to queue a SDU in the SDU queue, update BO and report
94 * it to the lower layer.
97 * This function is used to queue the received SDU in the
98 * SDU queue maintained in the radio bearer control block.
99 * After queuing the SDU, BO is updated and is reported
100 * to the lower layer.
102 * @param[in] gCb RLC Instance control block
103 * @param[in] rbCb RB control block
104 * @param[in] datReq Ptr to the datReq sent from PDCP
105 * @param[in] mBuf Sdu data
110 PUBLIC Void kwUmmQSdu
114 KwuDatReqInfo *datReq,
118 PUBLIC Void kwUmmQSdu(gCb,rbCb,datReq,mBuf)
121 KwuDatReqInfo *datReq;
125 MsgLen len; /* SDU buffer length */
126 KwSdu *sdu; /* SDU */
130 KW_UPD_L2_DL_TOT_SDU_STS(gCb,rbCb);
132 RLC_ALLOC_WC(gCb, sdu, (Size)sizeof(KwSdu));
133 #if (ERRCLASS & ERRCLS_ADD_RES)
136 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
137 "Memory allocation failed UEID:%d CELLID:%d",
143 #endif /* ERRCLASS & ERRCLS_ADD_RES */
145 /* Discard new changes starts */
146 kwUtlGetCurrTime(&sdu->arrTime);
147 /* Discard new changes ends */
148 SFndLenMsg(mBuf,&len);
153 sdu->mode.um.sduId = datReq->sduId;
154 sdu->mode.um.isSegmented = FALSE;
155 #ifndef RGL_SPECIFIC_CHANGES
164 rbCb->m.umDl.bo += len;
166 cmLListAdd2Tail(&(rbCb->m.umDl.sduQ), &sdu->lstEnt);
167 sdu->lstEnt.node = (PTR)sdu;
169 kwUmmEstHdrSz(&rbCb->m.umDl);
171 if(!rlcDlUtlIsReestInProgress(rbCb))
173 kwUtlSndDStaRsp(gCb,rbCb,rbCb->m.umDl.bo,rbCb->m.umDl.estHdrSz,FALSE,0);
176 /* kw005.201 added support for L2 Measurement */
177 #ifdef LTE_L2_MEAS_RLC
178 /* Update numActUe if it is not active */
179 if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_ACT_UE) &&
180 (rbCb->ueCb->numActRb[rbCb->qci]++ == 0))
182 rlcCb.kwL2Cb.numActUe[rbCb->qci]++;
191 * @brief Handler to form PDU(s) and update the BO.
194 * -# This function forms pdu(s) from the SDU(s) in the
195 * SDU queue and returns them.
196 * -# This function also updates the BO along with the
197 * along with the estimated Header size.
199 * @param[in] rbCb RB control block
200 * @param[out] pduInfo Pdu Info to be filled and the PDU size to be
201 * formed and the updated BO
202 * @param[in] pduSz The size for which PDUs have to constructed
205 * -# ROK In case of success
206 * -# RFAILED If allocation of Sdu fails
209 PUBLIC Void kwUmmProcessSdus
216 PUBLIC Void kwUmmProcessSdus(gCb, rbCb, datReq)
222 CmLList *firstNode; /* First Node in SDU queue */
223 U8 fi=0; /* Framing Info */
224 Buffer *pdu; /* Buffer for holding the formed PDU */
225 KwPduInfo *pduInfo; /* PDU Info pointer */
226 S16 pduSz; /* PDU Size to be constructed */
228 /* kw005.201 added support for L2 Measurement */
230 KwContSduLst contSduLst; /*Contained sduLst */
231 S32 dataVol = rbCb->m.umDl.bo;
232 U32* totMacGrant= &(datReq->totMacGrant);
233 KwL2MeasDlIpTh *dlIpThPut = &rbCb->l2MeasIpThruput.dlIpTh;
234 U8 *sduIdx = &dlIpThPut->lastSduIdx;
237 KwlchInfo lchInfo = {0};
245 TRC2(kwUmmProcessSdus)
250 pduInfo = &(datReq->pduInfo);
251 pduSz = datReq->pduSz;
254 contSduLst.numSdus = 0;
255 contSduLst.lcId = rbCb->lch.lChId;
256 oldBo = rbCb->m.umDl.bo;
257 lchInfo.lcId = rbCb->lch.lChId;
261 /* Discard new changes starts */
262 kwUtlGetCurrTime(&curTime);
265 while ((pduSz > 0) && (rbCb->m.umDl.sduQ.count > 0) &&
266 (rbCb->m.umDl.numLi < KW_MAX_DL_LI) && (pduInfo->numPdu < KW_MAX_PDU))
268 CM_LLIST_FIRST_NODE(&rbCb->m.umDl.sduQ,firstNode);
269 sdu = (KwSdu *)(firstNode->node);
271 if ((sdu->mode.um.isSegmented == FALSE) && (rbCb->discTmrInt > 0) &&
272 (rbCb->rlcId.rbType == CM_LTE_DRB))
274 timeDiff = KW_TIME_DIFF(curTime,sdu->arrTime);
276 if (timeDiff >= rbCb->discTmrInt)
279 KW_UPD_L2_DL_DISC_SDU_STS(gCb, rbCb);
281 rbCb->m.umDl.bo -= sdu->sduSz;
282 KW_RMV_SDU(gCb,&rbCb->m.umDl.sduQ,sdu);
286 /* When forming a new PDU, pdu == NULLP
287 -# Eliminate MAC header size for each pdu
288 -# Initialize the li array to 0
289 -# Substract the fixed header length based on SN length
296 KW_RMV_MAC_HDR_SZ(pduSz);
298 /* account for the RLC header size */
299 pduSz -= rbCb->m.umDl.snLen;
301 /* kw005.201 fixing pduSz <= 0 problem, ccpu00119417 */
307 rbCb->m.umDl.numLi = 0;
308 if (sdu->mode.um.isSegmented == TRUE)
318 kwUtlCalcLiForSdu(gCb,rbCb->m.umDl.numLi,sdu->sduSz,&pduSz);
320 /* Exact fit scenario :
321 If the SDU size matches with the PDU size
322 -# Allocate memory equal to PDU size;
324 -# Remove SDu from queue
325 -# Append to already existing PDU portion if present .
326 -# Add Header and create complete PDU and place it in
329 if (sdu->sduSz == pduSz)
338 SCatMsg(pdu, sdu->mBuf, M1M2);
341 rbCb->m.umDl.bo -= pduSz;
345 if(KW_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb))
347 if(sdu->mode.um.isSegmented)
349 *sduIdx = dlIpThPut->lastSduIdx;
353 KW_GETSDUIDX(*sduIdx);
356 kwUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
357 kwUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
358 sdu->mode.um.sduId, newIdx);
360 if ( lchInfo.numSdus < KW_L2MEAS_SDUIDX)
362 lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime;
363 lchInfo.sduInfo[lchInfo.numSdus].isRetxPdu = FALSE;
368 /* kw005.201 added support for L2 Measurement */
369 #ifdef LTE_L2_MEAS_RLC
370 kwUtlUpdSduSnMap(rbCb, sdu, datReq, TRUE);
371 if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_DL_DELAY) ||
372 (rbCb->rbL2Cb.measOn & LKW_L2MEAS_UU_LOSS))
375 if ( lchInfo.numSdus < KW_L2MEAS_SDUIDX)
377 lchInfo.arvlTime[lchInfo.numSdus] = sdu->arrTime;
381 #endif /* LTE_L2_MEAS */
382 KW_RMV_SDU(gCb,&(rbCb->m.umDl.sduQ),sdu); /* kw003.201 */
383 kwUtlIncrementKwuStsSduTx(gCb->u.dlCb->kwuDlSap + rbCb->kwuSapId);
385 kwUmmCreatePdu(gCb,rbCb,pdu,fi,pduInfo);
389 /* Concatenation scenario :
390 If SDU size is less than the requested PDU size
391 -# Allocate memory and copy SDU into it.
393 -# Remove SDU from the Queue.
394 -# Append to already existing PDU portion if present .
395 -# If the SDU size is greater than 2047 or the number of i
396 LIs reaches max, place it as a separate PDU in pduInfo and
399 place the msglen in li array and continue with the next SDU.
400 -# If the number of PDUs is more than KW_MAX_PDU, return from
401 the function even if pduSize > 0.
403 else if (sdu->sduSz < pduSz)
412 SCatMsg(pdu, sdu->mBuf ,M1M2);
414 rbCb->m.umDl.bo -= sdu->sduSz;
417 /* kw005.201 added support for L2 Measurement */
418 #ifdef LTE_L2_MEAS_RLC
419 kwUtlUpdSduSnMap(rbCb, sdu, datReq, TRUE);
420 #endif /* LTE_L2_MEAS */
421 if (sdu->sduSz < 2048 && rbCb->m.umDl.numLi < KW_MAX_DL_LI)
423 rbCb->m.umDl.li[(rbCb->m.umDl.numLi)++] = sdu->sduSz;
427 kwUmmCreatePdu(gCb, rbCb, pdu, fi, pduInfo);
430 if ( pduInfo->numPdu == KW_MAX_PDU)
432 /* Could not transmit what MAC asked for because the number
433 * of PDUs to be transmitted has reached maximum. */
434 RLOG_ARG2(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
435 "Maximum Pdu limit has been reached UEID:%d CELLID:%d",
442 if(KW_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) )
444 if(sdu->mode.um.isSegmented)
446 *sduIdx = dlIpThPut->lastSduIdx;
450 KW_GETSDUIDX(*sduIdx);
453 kwUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
454 kwUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
455 sdu->mode.um.sduId, newIdx);
457 if ( lchInfo.numSdus < KW_L2MEAS_SDUIDX)
459 lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime;
460 lchInfo.sduInfo[lchInfo.numSdus].isRetxPdu = FALSE;
465 KW_RMV_SDU(gCb,&(rbCb->m.umDl.sduQ),sdu);
466 /* kw005.201 ccpu00117318, updating the statistics */
467 kwUtlIncrementKwuStsSduTx(gCb->u.dlCb->kwuDlSap + rbCb->kwuSapId);
469 /* Segmentation scenario :
470 If size of SDU is greater than PDU size
471 -# Allocate memory and Segment the Sdu.
473 -# Append to already existing PDU if any.
474 -# Set the second bit of the framing info.
475 -# Create the complete PDU and place in pduInfo.
481 SSegMsg(sdu->mBuf,pduSz,&remSdu);
484 if(KW_MEAS_IS_DL_IP_MEAS_ON_FOR_RB(gCb, rbCb))
486 if(sdu->mode.um.isSegmented)
488 *sduIdx = dlIpThPut->lastSduIdx;
492 KW_GETSDUIDX(*sduIdx);
495 kwUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
496 kwUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
497 sdu->mode.um.sduId, newIdx);
499 if(KW_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb))
501 if(sdu->actSz == sdu->sduSz)
513 SCatMsg(pdu, sdu->mBuf, M1M2);
514 RLC_FREE_BUF_WC(sdu->mBuf);
518 rbCb->m.umDl.bo -= pduSz;
519 sdu->mode.um.isSegmented = TRUE;
524 /* kw005.201 added support for L2 Measurement */
525 #ifdef LTE_L2_MEAS_RLC
526 kwUtlUpdSduSnMap(rbCb, sdu, datReq, FALSE);
527 #endif /* LTE_L2_MEAS */
529 kwUmmCreatePdu(gCb,rbCb,pdu,fi,pduInfo);
532 /* kw005.201 added support for L2 Measurement */
534 #ifdef LTE_L2_MEAS_RLC
535 if((rbCb->rbL2Cb.measOn) &&
536 (rbCb->m.umDl.sduQ.count == 0) &&
539 if(--(rbCb->ueCb->numActRb[rbCb->qci]) == 0)
541 rlcCb.kwL2Cb.numActUe[rbCb->qci]--;
544 #endif /* LTE_L2_MEAS */
546 kwUtlUpdateBurstSdus(gCb, rbCb, &contSduLst, dataVol, *totMacGrant);
547 /* Need to check into optimizing this code : TODO */
548 if(KW_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) && (lchInfo.numSdus != 0))
550 KwL2MeasTb *l2MeasTb = kwUtlGetCurMeasTb(gCb, rbCb);
552 /* Fix Klock warning */
553 if ((lchInfo.numSdus != 0) && (l2MeasTb != NULLP) &&
554 (l2MeasTb->numLchInfo < KW_MAX_ACTV_DRB))
556 cmMemcpy((U8 *) &l2MeasTb->lchInfo[l2MeasTb->numLchInfo], (U8 *) &lchInfo, sizeof(KwlchInfo));
557 l2MeasTb->numLchInfo++;
559 l2MeasTb->txSegSduCnt += segSduCnt;
561 *totMacGrant -= (oldBo - rbCb->m.umDl.bo);
564 /* If we have a situation wherein the size requested is greater than the total size of SDUs
565 and a pdu buffer which is not null, this if loop helps to send
566 a non null PDU to the lower layer.
568 if (pduSz > 0 && pdu)
570 if (pduInfo->numPdu != KW_MAX_PDU)
572 rbCb->m.umDl.numLi--;
573 kwUmmCreatePdu(gCb,rbCb,pdu,fi,pduInfo);
578 RLC_FREE_BUF_WC(pdu);
582 kwUmmEstHdrSz(&rbCb->m.umDl);
583 datReq->boRep.bo = rbCb->m.umDl.bo;
584 datReq->boRep.estHdrSz = rbCb->m.umDl.estHdrSz;
585 datReq->boRep.staPduPrsnt = FALSE;
586 if (rbCb->m.umDl.sduQ.count > 0)
588 datReq->boRep.oldestSduArrTime =
589 ((KwSdu *)(rbCb->m.umDl.sduQ.first->node))->arrTime;
595 * @brief Handler to process the re-establishment request received from i
599 * This function does the following functions :
600 * Remove all the SDUs in the SDU queue.
602 * @param[in] gCb RLC Instance control block
603 * @param[in] rlcID Identity of the RLC entity for which
604 * re-establishment is to be done
605 * @param[in] sendReEst Whether to send re-establishment complete
606 * indication to upper layer or not
607 * @param[in] rbCb RB control block for which re-establishment
613 PUBLIC Void rlcDlUmmReEstablish
621 PUBLIC Void rlcDlUmmReEstablish(gCb, rlcId, rbCb)
628 /* The re-establishment indication is sent from the UL only */
629 TRC2(rlcDlUmmReEstablish)
632 kwUmmFreeDlRbCb(gCb, rbCb);
634 rbCb->m.umDl.vtUs = 0;
636 /* this would have been set when re-establishment was triggered
638 rlcDlUtlResetReestInProgress(rbCb);
643 * @brief Handler to create the header and complete a PDU.
646 * This function is used to create the header of a PDU and concatenate it
647 * with the data part of the PDU.
648 * Also updates the statistics
649 * Sets the passed pdu to NULLP
651 * @param[in] gCb RLC instance control block
652 * @param[in,out] rbCb RB control block
654 * @param[in] fi Framing Info field
655 * @param[out] datReqPduInfo Holder in which to copy the created PDU pointer
660 PRIVATE Void kwUmmCreatePdu
666 KwPduInfo *datReqPduInfo
669 PRIVATE Void kwUmmCreatePdu(gCb, rbCb, pdu, fi, datReqPduInfo)
674 KwPduInfo *datReqPduInfo
677 KwSn sn; /* Sequence Number */
678 U32 liCount; /* LI count */
679 U8 e = 0; /* Extension Bit */
680 U32 count; /* Loop Counter */
683 /* create a big array to store the header, assuming 3 bytes per 2 L1s
684 * (2 bytes if only a single LI) and 2 bytes for the
686 * size of header = ( NumLi /2 ) * 3 + (NumLi % 2) * 2 + 2;
687 * where NumLi = Number of Length Indicators to be sent
689 U8 hdr[((KW_MAX_DL_LI >> 1) * 3) + ((KW_MAX_DL_LI & 0x01) << 1) + 2];
690 U32 idx = 0; /* To index to the hdr array */
692 /* Note: idx is not checked against crossing the hdr array bound as
693 * liCount will be < KW_MAX_DL_LI and as per the size calculated above;
694 * idx cannot cross the array
700 /* stats updated before for bytes sent before adding RLC headers */
701 kwUtlIncrementGenStsBytesAndPdusSent(&gCb->genSts, pdu);
703 sn = rbCb->m.umDl.vtUs;
704 liCount = rbCb->m.umDl.numLi;
706 if(liCount > KW_MAX_DL_LI)
707 liCount = KW_MAX_DL_LI;
709 /* if there are any LI's then set the first E bit */
715 if (rbCb->m.umDl.snLen == 1)
717 hdr[idx++] = (fi << 6) | (e << 5) | sn;
719 else /* SN length is 2 */
721 /* SN length is 10 bits */
722 hdr[idx] = (fi << 3) | (e << 2) | (sn >> 8);
723 hdr[++idx] = sn & 0xff;
728 for (count = 0;count < liCount;count++)
730 /* In each iteration we try and encode 2 LIs */
731 /* if this is the last LI then e should be 0 */
732 if(count == liCount - 1)
737 /* ccpu00135170 Fixing KLOCK warning */
738 if((idx + 1)>= hdrSz)
742 /* odd LI, 1st , 3rd etc */
743 hdr[idx] = (e << 7) | (rbCb->m.umDl.li[count] >> 4);
744 hdr[++idx] = (rbCb->m.umDl.li[count] & 0xf) << 4;
747 if(count == liCount - 1)
751 else if(count >= liCount)
755 /* ccpu00135170 Fixing KLOCK warning */
756 if((idx + 1)>= hdrSz)
760 /* even one, 2nd , 4th etc LI's, count starts at 0 */
761 hdr[idx] |= ((e << 3) | (rbCb->m.umDl.li[count] >> 8));
762 hdr[++idx] = rbCb->m.umDl.li[count] & 0xff;
766 /* if odd number of L1s increment idx */
772 /* increment VT(US) */
773 rbCb->m.umDl.vtUs = (rbCb->m.umDl.vtUs + 1) & rbCb->m.umDl.modBitMask;
775 /* add the header to the beginning of the pdu */
776 SAddPreMsgMultInOrder(hdr, idx, pdu);
778 datReqPduInfo->mBuf[datReqPduInfo->numPdu++] = pdu;
783 * @brief Handler to estimate the header size of the RLC SDUs
784 * present in the SDU queue.
787 * This function is used to update the estimated header size variable in RB.
788 * This function is called when a SDU is queued and when a PDU is formed and
789 * sent to the lower layer.
791 * @param[in] umDl UM mode downlink control block
796 PRIVATE Void kwUmmEstHdrSz
801 PRIVATE Void kwUmmEstHdrSz(umDl)
805 /* The header size is estimated as :
806 If sdu count = 0 then 0
807 else sdu count * 2 + 1; the 1 is added for the FI and SN byte;
810 umDl->estHdrSz = (umDl->sduQ.count)?((umDl->sduQ.count << 1) + 1) : 0;
816 * @brief Handler to discard a SDU.
819 * This function is used to discard a SDU after receiving
820 * the Discard Request from the upper layer.The SDU is discarded if
821 * it is present and is not mapped to any PDU yet.
822 * The discards coming from the upper layer would be coming in
823 * sequence according to the sduId, so we should find the sduId at the
824 * head of the sduQ. Discards if there is a match else does nothing.
826 * @param[in] rbCb RB control block
827 * @param[in] sduId SDU ID of the SDU to be discarded
832 PUBLIC Void kwUmmDiscSdu
839 PUBLIC Void kwUmmDiscSdu(gCb,rbCb,sduId)
845 CmLList *tmpNode; /* Temporary Node in SDU queue */
850 CM_LLIST_FIRST_NODE(&rbCb->m.umDl.sduQ,tmpNode);
854 KwSdu *sdu = (KwSdu *)tmpNode->node;
856 if (sdu->mode.um.sduId == sduId && sdu->mode.um.isSegmented == FALSE)
858 /* kw005.201 added support for L2 Measurement */
859 KW_RMV_SDU(gCb,&rbCb->m.umDl.sduQ,sdu);
860 gCb->genSts.numSduDisc++;
870 * function to free/release the UnAcknowledged mode RBCB buffers
873 * This primitive Frees the Unacknowldged Mode RbCb sdu queue
875 * @param [in] gCb - RLC instance control block
876 * @param [in] rbCb - RB Control Block
881 PUBLIC Void kwUmmFreeDlRbCb
887 PUBLIC Void kwUmmFreeDlRbCb(gCb,rbCb)
892 TRC2(kwUmmFreeDlRbCb)
895 /* cat the SDU queue to the to be freed list */
896 cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.umDl.sduQ));
897 kwUtlRaiseDlCleanupEvent(gCb);
900 } /* kwUmmFreeDlRbCb */
902 /********************************************************************30**
904 **********************************************************************/