7b309f828a848cbde84b198e0fbdc99da74d44ce
[o-du/l2.git] / src / 5gnrrlc / kw_amm_dl.c
1 /*******************************************************************************
2 ################################################################################
3 #   Copyright (c) [2017-2019] [Radisys]                                        #
4 #                                                                              #
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                                    #
8 #                                                                              #
9 #       http://www.apache.org/licenses/LICENSE-2.0                             #
10 #                                                                              #
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 *******************************************************************************/
18
19 /********************************************************************20**
20   
21         Name:    RLC - AM DL module file
22     
23         Type:    C source file
24   
25         Desc:    Source code for Acknowledged Mode Module functions such as, 
26
27                  Transmission of data/control PDUs 
28                  Retransmission (Feedback in terms of status)
29                  Polling
30                  Assemble SDUs
31                  Reception - reordering
32                  Duplicate detection for byte segments
33                  Reassemble SDUs
34                   
35         File:   kw_amm_dl.c 
36   
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 */
45
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 */
60
61 #include "kw.h"            /* RLC defines */
62 #include "kw_udx.h"
63 #include "kw_dl.h"
64
65
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 */
80
81 #include "kw.x"
82 #include "kw_udx.x"
83 #include "kw_dl.x"
84
85 //UDAY
86 #ifdef L2_OPTMZ
87 extern U32 kwAmmStaPduList[512];
88  U32 kwAmmStaPduListCnt = 0;
89 #endif
90
91
92 /** @file gp_amm_dl.c
93 @brief RLC Acknowledged Mode Downlink Module
94 **/
95 #define KW_MODULE (KW_DBGMASK_AM | KW_DBGMASK_DL)
96
97 U32 kwStatusPduCnt, kwStatusAckCnt, kwStatusNcnt, kwSduSndCnt;
98
99 /* local defines */
100
101 /* local externs */
102
103 /* forward references */
104 EXTERN Void kwAmmDlHndlStatusPdu ARGS ((KwCb  *gCb,
105                                         KwDlRbCb  *rbCb,
106                                         KwUdxStaPdu *pStaPdu));
107
108 /* public variable declarations */
109
110 /* This structure holds all the global structs we need. */
111
112 /* private variable declarations */
113
114 #define KW_AM_RMV_HDR(_gCb, _rbCb, _retx) do { \
115   if ((_retx)->yetToConst == FALSE) \
116   {\
117      Buffer    *_pduInfo; \
118      SSegMsg((_retx)->seg, (_retx)->hdrSz, &_pduInfo); \
119      KW_FREE_BUF((_retx)->seg); \
120      (_retx)->seg = _pduInfo; \
121   }\
122   (_rbCb)->m.amDl.estHdrSz -= retx->hdrSz;\
123 } while(0)
124
125 /* private function declarations */
126
127 PRIVATE Void  kwResegRetxPdus ARGS ((KwCb *gCb,
128                                      KwDlRbCb *rbCb, 
129                                      KwDatReq *kwDatReq));
130
131 PRIVATE Void kwRemRetxPdu ARGS ((KwCb *gCb, 
132                                  KwDlRbCb *rbCb, 
133                                  KwRetx *retx));
134
135 PRIVATE Void kwAmmCreateStatusPdu ARGS ((KwCb *gCb, 
136                                          KwDlRbCb *rbCb,
137                                          KwDatReq *kwDatReq));
138
139 PRIVATE Void kwAmmDlMarkPduForReTx ARGS ((KwCb *gCb,
140                                           KwDlRbCb *rbCb,
141                                           KwRetx *retx));
142
143 PRIVATE Void kwAmmDlProcessSuccessfulTxPdu ARGS((KwCb *gCb, 
144                                                  KwDlRbCb *rbCb,
145                                                  KwSn  sn,
146                                                  KwuDatCfmInfo **datCfm));
147
148 PRIVATE Void kwAmmDlSetTxNextAck ARGS((KwAmDl *amDl, KwSn sn));
149
150 PRIVATE Void kwAmmDlCheckAndStopPollTmr ARGS((KwCb *gCb,
151                                               KwDlRbCb *rbCb,
152                                               KwSn mAckSn));
153
154 PRIVATE Void  kwAssembleSdus ARGS ((KwCb *gCb,
155                                     KwDlRbCb *rbCb, 
156                                     KwDatReq *kwDatReq));
157
158 PRIVATE Bool kwAmmDlCheckAndSetPoll ARGS ((KwCb *gCb,
159                                            KwDlRbCb *rbCb, 
160                                            Bool newPdu, 
161                                            MsgLen bufSz));
162
163 PRIVATE Void kwAmmCreatePdu ARGS ((KwCb *gCb,
164                                    KwDlRbCb *rbCb, 
165                                    KwAmHdr *amHdr, 
166                                    KwDlPduInfo *pduInfo,
167                                    Buffer *pdu));
168
169 PRIVATE Void kwAmmSndStaInd ARGS ((KwCb *gCb,KwDlRbCb *rbCb, KwRetx *retx));
170
171 PRIVATE Void kwGetNxtRetx ARGS ((KwCb *gCb, KwRetx **retx));
172
173 PRIVATE Void kwConstructAmHdr ARGS ((KwAmHdr *amHdr, 
174                                      U8 *hdr,
175                                      U8  snLen,
176                                      U16 *idx));
177
178 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForAckSn ARGS ((KwCb *gCb,
179                                                       KwDlRbCb *rbCb, 
180                                                       KwSn mAckSn,
181                                                       CmLList *retx,
182                                                       KwuDatCfmInfo **datCfm));
183
184 PRIVATE Void kwAmmDlMoveFrmTxtoRetxBuffer ARGS ((KwCb *gCb,
185                                                  KwAmDl *amDl, 
186                                                  KwRetx **retx, 
187                                                  KwSn sn));
188  
189 PRIVATE Void kwAmmDlCheckIsSDUDelivered ARGS((KwCb *gCb,
190                                               KwDlRbCb *rbCb, 
191                                               KwSduMap *sduMap, 
192                                               KwuDatCfmInfo **datCfm));
193
194 PRIVATE Void kwAmmAddPduToRetxLst ARGS((KwAmDl   *amDl,
195                                         KwRetx   *retx));
196
197 PRIVATE Void kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer ARGS(
198 (
199 KwCb          *gCb,
200 KwAmDl        *amDl,
201 KwRetx        **retx,
202 KwDlPduInfo   *pduInfo
203 ));
204
205 PRIVATE Void kwAmmDlHndlStatus4SduByteSegInTxBuf ARGS(
206 (
207 KwCb          *gCb,
208 KwDlRbCb      *rbCb,
209 KwNackInfo    *nackSnInfo,
210 KwRetx        **retx,
211 KwuDatCfmInfo **datCfm
212 ));
213
214 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForNackSn ARGS(
215 (
216  KwCb          *gCb,
217  KwDlRbCb      *rbCb,
218  KwNackInfo    *nackSnInfo,
219  CmLList       **retxNode,
220  KwuDatCfmInfo **datCfm
221  ));
222
223 PRIVATE Void KwDlAmmGetNackSnInfoFrmNackRangeIdx ARGS(
224 (
225 KwAmDl        *amDl,
226 KwNackInfo    *nackInfo,
227 CmLList       *retxNode,
228 KwNackInfo    *nackSnInfo,
229 U8            idx
230 ));
231
232 PRIVATE Void kwAmmDlUpdTxAndReTxBufForLessThanNackSn ARGS(
233 (
234 KwCb            *gCb,
235 KwDlRbCb        *rbCb,
236 KwSn            sn,
237 KwSn            mNackSn,
238 CmLList         **retxNode,
239 KwuDatCfmInfo   **datCfm
240 ));
241 /*****************************************************************************
242
243   AM Module contains the following funcitons:
244
245   -  kwAmmQSdu 
246   -  kwAmmProcessSdus
247      -  kwAmmDlAssembleCntrlInfo
248      -  kwResegRetxPdus
249      -  kwAssembleSdus
250      -  kwAmmDlCheckAndSetPoll
251   -  kwAmmProcessPdus
252      -  kwDlmHndlStaRsp
253      -  kwTriggerStatus
254      -  kwReassembleSdus
255    
256 *******************************************************************************/
257 /** @addtogroup ammode */
258 /*@{*/
259
260 /**
261  * @brief Function to send a Status Response to MAC for a dedicated logical
262  *        channel
263  *       
264  * @details
265  *    Function calculates the current bo and send a Status response for the
266  *    dedicated logical channel if the bo is non zero
267  *
268  * @param[in] gCb    RLC instance control block
269  * @param[in] rbCb   Radio Bearer control block
270  * @param[in] amDl   AM downlink control block
271  * 
272  * @return  Void
273 */
274 #ifdef ANSI
275 PUBLIC Void kwAmmSendDStaRsp
276 (
277 KwCb       *gCb,
278 KwDlRbCb   *rbCb,
279 KwAmDl     *amDl
280 )
281 #else
282 PUBLIC Void kwAmmSendDStaRsp(gCb, rbCb, amDl)
283 KwCb       *gCb;
284 KwDlRbCb   *rbCb;
285 KwAmDl     *amDl;
286 #endif
287 {
288    S32 bo = kwAmmCalculateBo(amDl);
289
290    if(bo)
291    {
292       kwUtlSndDStaRsp(gCb, rbCb, bo, amDl->estHdrSz, amDl->cntrlBo ?TRUE:FALSE,amDl->cntrlBo);
293    }
294    
295    RETVOID;
296 }
297
298 /**
299  * @brief Function to check if the pollSn is acked and stop the poll timer
300  *
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
304  *                     be passed
305  * 
306  * @return  Void
307 */
308 #ifdef ANSI
309 PRIVATE Void kwAmmDlCheckAndStopPollTmr
310 (
311 KwCb       *gCb,
312 KwDlRbCb   *rbCb,
313 KwSn       mAckSn
314 )
315 #else
316 PRIVATE Void kwAmmDlCheckAndStopPollTmr(gCb, rbCb, mAckSn)
317 KwCb       *gCb;
318 KwDlRbCb   *rbCb;
319 KwSn       mAckSn;
320 #endif
321 {
322    KwSn mPollSn;                                                   
323                                                                    
324    MODAMT(rbCb->m.amDl.pollSn, mPollSn, rbCb->m.amDl.txNextAck,rbCb->m.amDl.snModMask);      
325                                                                    
326    if (mPollSn <= mAckSn)                                        
327    {                                                               
328       if (kwChkTmr(gCb, (PTR)rbCb, KW_EVT_AMDL_POLL_RETX_TMR))    
329       {                                                            
330          kwStopTmr(gCb, (PTR)rbCb, KW_EVT_AMDL_POLL_RETX_TMR);    
331       }                                                            
332    }
333
334    RETVOID;
335 }
336
337 /**
338  * @brief Function to set VT(A) and VT(MS). Calculates the VT(MS) from VT(A)
339  *
340  * @param[in,out] amDl    AM downlink control block
341  * @param[in]sn           Sequence number to be set as VT(A)
342  * 
343  * @return  Void
344 */
345 #ifdef ANSI
346 PRIVATE Void kwAmmDlSetTxNextAck
347 (
348 KwAmDl   *amDl,
349 KwSn      sn
350 )
351 #else
352 PRIVATE Void kwAmmDlSetTxNextAck(amDl, sn)
353 KwAmDl   *amDl;
354 KwSn     sn
355 #endif
356 {
357    amDl->txNextAck = sn;
358    
359    RETVOID;
360 }
361
362 /**
363  * @brief Function to process a successfully re-transmitted PDU/segment
364  *       
365  * @details
366  *    Checks if the SDU has been completely delivered or not. Removes the PDU
367  *    from the re-transmission buffer
368  *
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
372  * 
373  * @return  Void
374 */
375 #ifdef ANSI
376 PRIVATE Void kwAmmDlProcessSuccessfulReTx
377 (
378 KwCb            *gCb,
379 KwDlRbCb        *rbCb,
380 KwRetx          *retx,
381 KwuDatCfmInfo   **datCfm
382 )
383 #else
384 PRIVATE Void kwAmmDlProcessSuccessfulReTx(gCb, rbCb, retx, datCfm)
385 KwCb            *gCb;
386 KwDlRbCb        *rbCb;
387 KwRetx          *retx;
388 KwuDatCfmInfo   **datCfm;
389 #endif
390 {
391    kwAmmDlCheckIsSDUDelivered(gCb, rbCb, &(retx->sduMap), datCfm);
392    
393    kwRemRetxPdu(gCb, rbCb, retx);
394
395    RETVOID;
396 }
397
398 /**
399  * @brief Handler to Move the PDU from txBuf to re-transmission buffer 
400  *
401  * @details
402  *    This function is used to move the PDU from the txBuf to re-transmit buffer
403  *
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
407  *                                 this function
408  * @param[in]KwDlPduInfo *pduInfo  TX PDU which needs to be moved
409  * 
410  * @return Void
411  *            
412  */
413
414 #ifdef ANSI
415 PRIVATE Void kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer
416 (
417 KwCb          *gCb,
418 KwAmDl        *amDl,
419 KwRetx        **retx,
420 KwDlPduInfo   *pduInfo
421 )
422 #else
423 PRIVATE Void kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb, amDl, retx, pduInfo)
424 KwCb          *gCb;
425 KwAmDl        *amDl;
426 KwRetx        **retx;
427 KwDlPduInfo   *pduInfo;
428 #endif
429 {
430    TRC2(kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer);
431
432
433    KW_ALLOC_WC(gCb,*retx, sizeof(KwRetx));
434
435 #if (ERRCLASS & ERRCLS_ADD_RES)
436    if (*retx == NULLP)
437    {
438            RLOG0(L_FATAL, "Memory allocation failed");
439            RETVOID;
440    }
441 #endif /* ERRCLASS & ERRCLS_RES */
442
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);
447
448    (*retx)->hdrSz = pduInfo->hdrSz;
449    (*retx)->retxCnt = 1;
450    (*retx)->yetToConst = 0;
451    (*retx)->pendingReTrans = TRUE;
452
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), 
458                    &pduInfo->sduMap, 
459                    sizeof(KwSduMap));
460
461    KW_MEM_CPY(&((*retx)->amHdr), &pduInfo->amHdr, sizeof(KwAmHdr));
462    kwAmmAddPduToRetxLst(amDl, (*retx));
463
464    /* Update the BO appropriately */
465    amDl->retxBo   += (*retx)->segSz;
466    amDl->estHdrSz += (*retx)->hdrSz;
467
468    gRlcStats.amRlcStats.numDLRetransPdus++;
469
470    RETVOID;
471 } /*kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer */
472
473 /**
474  * @brief Function to handle Status of Sdu byte segment for a nackSn 
475  *
476  * @details
477  *    This function is used to move the PDU from the txBuf to re-transmit buffer
478  *
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
483  *                                    this function
484  * @param[in]KwuDatCfmInfo **datCfm Ptr to datCfm
485  * 
486  * @return Void
487  *            
488  */
489
490 #ifdef ANSI
491 PRIVATE Void kwAmmDlHndlStatus4SduByteSegInTxBuf
492 (
493 KwCb          *gCb,
494 KwDlRbCb      *rbCb,
495 KwNackInfo    *nackSnInfo,
496 KwRetx        **retx,
497 KwuDatCfmInfo ** datCfm
498 )
499 #else
500 PRIVATE Void kwAmmDlHndlStatus4SduByteSegInTxBuf(gCb, rbCb, nackSnInfo, retx, datCfm)
501 (
502 KwCb          *gCb;
503 KwDlRbCb      *rbCb;
504 KwNackInfo    *nackSnInfo;
505 KwRetx        **retx;
506 KwuDatCfmInfo **datCfm;
507 )
508 #endif
509 {
510    KwTx    *txBuf=NULLP;
511    CmLList *lnk;
512    CmLList *nextLnk;
513
514    TRC2(kwAmmDlHndlStatus4SduByteSegInTxBuf)
515
516    txBuf = kwUtlGetTxBuf(AMDL.txBufLst, nackSnInfo->sn);
517    if (txBuf == NULLP)
518    {
519            RETVOID;
520    }
521    lnk = txBuf->pduLst.first;
522    while(lnk)
523    {
524       KwDlPduInfo *pduInfo = (KwDlPduInfo *)(lnk->node);
525       KwSn        pduSoEnd = (pduInfo->amHdr.so + pduInfo->sduMap.sduSz - 1);
526
527       /* If So of Sdu byte segment(pduInfo/seg) is < status pdu
528          soStart that means it's ACKED*/
529       if(pduSoEnd < nackSnInfo->soStart) 
530       {
531          kwAmmDlCheckIsSDUDelivered(gCb,
532                rbCb,  
533                &(pduInfo->sduMap), 
534                datCfm);
535
536       }
537       else if (pduSoEnd <= nackSnInfo->soEnd)
538       {
539          /* Move Sdu byte segment from TX buf to retx buf*/
540          kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb, 
541                &rbCb->m.amDl, 
542                retx, 
543                pduInfo);
544       }
545       else
546       {
547          lnk = lnk->next;
548          continue;
549       }
550       nextLnk = lnk->next;
551       /* Delete node from the txBuf Pdu lst */
552       cmLListDelFrm(&txBuf->pduLst, lnk);
553       KW_FREE_WC(gCb, pduInfo, sizeof(KwDlPduInfo));
554       lnk = nextLnk;
555    }
556    if(!txBuf->pduLst.count)
557    {
558       /*No more Sdu byte segment are left. Hence delete txBuf*/
559       kwUtlDelTxBuf(AMDL.txBufLst, txBuf,gCb);
560    }
561
562    RETVOID;
563 }
564
565 /**
566  * @brief Function to handle Status of Sdu byte segment for a nackSn 
567  *
568  * @details
569  *    This function is used to move the PDU from the txBuf to re-transmit buffer
570  *
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
575  *                                  this function
576  * @param[in]KwuDatCfmInfo **datCfm Ptr to datCfm
577  * 
578  * @return Void
579  *            
580  */
581 #ifdef ANSI
582 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForNackSn
583 (
584  KwCb          *gCb,
585  KwDlRbCb      *rbCb,
586  KwNackInfo    *nackSnInfo,
587  CmLList        **retxNode,
588  KwuDatCfmInfo **datCfm
589  )
590 #else
591 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, nackSnInfo, retxNode, datCfm)
592 (
593  KwCb          *gCb;
594  KwDlRbCb      *rbCb;
595  KwNackInfo    *nackSnInfo;
596  CmLList       **retxNode;
597  KwuDatCfmInfo **datCfm;
598  )
599 #endif
600 {
601    KwTx    *txBuf;
602    KwRetx  *retx;
603
604    TRC2(kwAmmDlUpdateTxAndReTxBufForNackSn)
605
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 */
609
610    /* if the NACK_SN is in the transmit buffer, move it to the re-
611          transmit buffer */
612    txBuf = kwUtlGetTxBuf(AMDL.txBufLst, nackSnInfo->sn);
613    if (txBuf != NULLP)
614    {
615       if(nackSnInfo->isSegment)
616       {
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);
621       }
622       else
623       {
624          /*e2= 0 and e3= 0: Move complete PDU from TX buf to retx buf*/
625          kwAmmDlMoveFrmTxtoRetxBuffer(gCb, 
626                &rbCb->m.amDl, 
627                &retx, 
628                nackSnInfo->sn);
629       } 
630
631 #if (ERRCLASS & ERRCLS_ADD_RES)
632       if(retx)
633 #endif
634       {
635               (*retxNode) = retx->lstEnt.next;
636       }
637
638       RETVOID;
639    }
640
641    /* process the pdus/segments in the re-transmit buffer with 
642       this NACK_SN */
643    while (*retxNode)
644    {
645       retx = (KwRetx *)((*retxNode)->node);
646       if (retx->amHdr.sn != nackSnInfo->sn)
647       {
648          break;
649       }
650       if ((nackSnInfo->isSegment) &&
651             ((retx->soEnd < nackSnInfo->soStart) /*|| (retx->amHdr.so > soEnd)*/))
652       {
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",
656                nackSnInfo->sn, 
657                rbCb->rlcId.ueId,
658                rbCb->rlcId.cellId);
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, 
662                rbCb->rlcId.ueId,
663                rbCb->rlcId.cellId);
664
665          (*retxNode) = (*retxNode)->next;
666          kwAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
667       }
668       else if((!nackSnInfo->isSegment) || (retx->soEnd <= nackSnInfo->soEnd))
669       {
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*/
673
674          (*retxNode) = (*retxNode)->next;
675          /* Mark the retx PDU we found for further retransmission  */
676          kwAmmDlMarkPduForReTx(gCb, rbCb, retx);
677       }
678       else
679       { 
680          /* If we are here that means this segment and segments after this are ACKed*/
681          break;
682       }
683    } /* end of retxNode while loop*/
684    RETVOID;
685 }
686
687 /**
688  * @brief Function to get nack Sn information from nackRange index 
689  *
690  * @details
691  *    This function is used to get nack Sn information from nackRange index
692  *
693 * @param[in]KwAmDl        *amDl,
694 * @param[in]KwUdxStaPdu   *StaPdu,
695 * @param[in]KwNackInfo    *nackSnInfo,
696 * @param[in]KwRetx        *retx;
697 * @param[in]KwSn          sn, 
698 * @param[in]U8            idx
699  * 
700  * @return Void
701  *            
702  */
703 #ifdef ANSI
704 PRIVATE Void KwDlAmmGetNackSnInfoFrmNackRangeIdx
705 (
706 KwAmDl        *amDl,
707 KwNackInfo    *nackInfo,
708 CmLList        *retxNode,
709 KwNackInfo    *nackSnInfo,
710 U8            idx
711 )
712 #else
713 PRIVATE Void KwDlAmmGetNackSnInfoFrmNackRangeIdx(amDl, nackInfo, retxNode, nackSnInfo, idx)
714 (
715 KwAmDl        *amDl;
716 KwNackInfo    *nackInfo;
717 CmLList       *retxNode;
718 KwNackInfo    *nackSnInfo;
719 U8            idx;
720 )
721 #endif
722 {
723    KwTx     *txBuf;
724    KwRetx   *retx;
725    CmLList  *node;
726
727    TRC2(KwDlAmmGetNackSnInfoFrmNackRangeIdx)
728
729    nackSnInfo->isSegment = FALSE;
730
731    if((!nackInfo->isSegment) || (!idx && nackSnInfo->nackRange && (!nackInfo->soStart)))
732    {
733       nackSnInfo->soStart = 0;
734       nackSnInfo->soEnd = 0;
735       RETVOID;
736    }
737    txBuf = kwUtlGetTxBuf(amDl->txBufLst, nackSnInfo->sn);
738    if(txBuf != NULLP)
739    {
740       node = txBuf->pduLst.first;
741       while(node)
742       {
743          KwDlPduInfo *pduInfo = (KwDlPduInfo *)(node->node);
744          U16         pduSoEnd = pduInfo->amHdr.so + pduInfo->sduMap.sduSz - 1; 
745          if((!idx) && (pduInfo->amHdr.so == nackInfo->soStart))
746          {
747             nackSnInfo->isSegment = TRUE;
748             nackSnInfo->soStart = pduInfo->amHdr.so;
749             nackSnInfo->soEnd = pduSoEnd;
750             break;
751          }
752          else if((idx == nackSnInfo->nackRange - 1) && \
753                (pduSoEnd == nackInfo->soEnd))
754          {
755             nackSnInfo->isSegment = TRUE;
756             nackSnInfo->soStart = pduInfo->amHdr.so;
757             nackSnInfo->soEnd = pduSoEnd;
758             break;
759          }
760          node = node->next;
761       }
762    }
763    if(!nackSnInfo->isSegment)
764    { 
765       while (retxNode)
766       {
767          retx = (KwRetx *)(retxNode->node);
768          if(retx->amHdr.sn != nackSnInfo->sn)
769          {
770             break;
771          }
772          if((!idx) && (retx->amHdr.so == nackInfo->soStart))
773          {
774             nackSnInfo->isSegment = TRUE;
775             nackSnInfo->soStart = retx->amHdr.so;
776             nackSnInfo->soEnd = retx->soEnd;
777             break;
778          }
779          else if((idx == nackSnInfo->nackRange - 1) && \
780                (retx->soEnd == nackInfo->soEnd))
781          {
782             nackSnInfo->isSegment = TRUE;
783             nackSnInfo->soStart = retx->amHdr.so;
784             nackSnInfo->soEnd = retx->soEnd;
785             break;
786          }
787          retxNode = retxNode->next;
788       }
789    }
790 }
791
792 /**
793  * @brief Function to update transmission buffers and send confimations to
794  *        PDCP on the reception of Status PDU
795  *
796  * @details
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
801  *       buffer
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
804  *       re-transmission
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
808  *       NACK_SNs
809  *
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
813  * 
814  * @return  Void
815 */
816 #ifdef ANSI
817 PUBLIC Void kwAmmDlHndlStatusPdu
818 (
819 KwCb          *gCb,
820 KwDlRbCb      *rbCb,
821 KwUdxStaPdu   *pStaPdu
822 )
823 #else
824 PUBLIC Void kwAmmDlHndlStatusPdu(gCb, rbCb, pStaPdu)
825 KwCb          *gCb;
826 KwDlRbCb      *rbCb;
827 KwUdxStaPdu   *pStaPdu;
828 #endif
829 {
830    KwSn      mAckSn;
831    S32       oldRetxBo;
832    CmLList   *retxNode;
833    KwuDatCfmInfo* datCfm; 
834    KwKwuSapCb    *kwuSap;
835    KwSn       mTxNext;
836
837    TRC2(kwAmmDlHndlStatusPdu)
838    kwStatusPduCnt++;
839
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;
844
845    /* Allocate memory for datCfm Info */
846    KW_SHRABL_STATIC_BUF_ALLOC(kwuSap->pst.region, kwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
847
848 #if (ERRCLASS & ERRCLS_ADD_RES)
849    if (datCfm == NULLP)
850    {
851       RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId, 
852                "Memory allocation failed UEID:%d CELLID:%d",
853                rbCb->rlcId.ueId,
854                rbCb->rlcId.cellId);
855       KW_SHRABL_STATIC_BUF_FREE(kwuSap->pst.region, kwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
856       RETVOID;
857    }
858 #endif /* ERRCLASS & ERRCLS_RES */
859
860    datCfm->numSduIds = 0;
861    datCfm->rlcId = rbCb->rlcId;
862
863    MODAMT(pStaPdu->ackSn, mAckSn, AMDL.txNextAck,AMDL.snModMask);
864    MODAMT(AMDL.txNext,mTxNext, AMDL.txNextAck,AMDL.snModMask);
865
866    if(mAckSn > mTxNext)
867    {
868       RLOG_ARG4(L_WARNING,DBG_RBID, rbCb->rlcId.rbId, 
869                "Invalid ACK SN = %d received. Current Vta =%d"
870                "UEID:%d CELLID:%d", 
871                pStaPdu->ackSn,
872                AMDL.txNextAck,
873                rbCb->rlcId.ueId,
874                rbCb->rlcId.cellId);
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));
877       RETVOID;
878    }
879  
880    /* Venki - stopping the poll retx timer */
881    /*Stop PollRetx Tmr */
882    kwAmmDlCheckAndStopPollTmr(gCb, rbCb, mAckSn);
883
884    /* Set the first node in retx list to retxNode */
885    retxNode = AMDL.retxLst.first;
886
887    /* If NACK exists in control PDU */
888    if (pStaPdu->nackCnt)
889    {
890       KwSn   sn;
891       KwNackInfo nackSnInfo;
892       KwSn   mNackSn;
893       KwSn   txNextAck;
894       KwSn   transWinStartSn = AMDL.txNextAck; /*used to track the SN from which 
895                                            to start processing the transmission
896                                            buffer */
897       U32    idx = 0;
898
899       /* if any NACKs then txNextAck should be equal to the first NACK_SN*/
900       txNextAck = pStaPdu->nackInfo[0].sn;
901
902       kwStatusNcnt += pStaPdu->nackCnt;
903
904       /* For NACKs */
905       while (idx < pStaPdu->nackCnt)
906       {
907          nackSnInfo.isSegment = pStaPdu->nackInfo[idx].isSegment;
908          nackSnInfo.nackRange = pStaPdu->nackInfo[idx].nackRange;
909          nackSnInfo.sn = pStaPdu->nackInfo[idx].sn;
910          
911          RLOG_ARG3(L_DEBUG,DBG_RBID, rbCb->rlcId.rbId, 
912                   "kwHndlStaRsp: NACK SN = %d UEID:%d CELLID:%d",
913                   nackSnInfo.sn,
914                   rbCb->rlcId.ueId,
915                   rbCb->rlcId.cellId);
916
917          nackSnInfo.soStart = pStaPdu->nackInfo[idx].soStart;
918          nackSnInfo.soEnd   = pStaPdu->nackInfo[idx].soEnd;
919
920          /* e2 is used as a boolean indicating presence of SOStart or SOEnd */
921
922          sn = transWinStartSn;
923
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;
928         
929         /* Clear the acked SNs from the retx list */
930          MODAMT(nackSnInfo.sn, mNackSn, AMDL.txNextAck,AMDL.snModMask);
931
932          if ((mNackSn > mAckSn) || (mNackSn >= mTxNext))
933          {
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",
937                      rbCb->rlcId.ueId,
938                      rbCb->rlcId.cellId);
939             KW_SHRABL_STATIC_BUF_FREE(kwuSap->pst.region, kwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
940             RETVOID;
941          }
942
943          /* clear all the SNs < NACK_SN from re-transmission list */   
944          kwAmmDlUpdTxAndReTxBufForLessThanNackSn(gCb, rbCb, sn, mNackSn,
945                                                  &retxNode, &datCfm);
946          
947          if(!nackSnInfo.nackRange)
948          {
949             kwAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, &nackSnInfo, &retxNode, &datCfm);
950             gRlcStats.amRlcStats.numRlcAmCellNackRx++;
951          }
952          else
953          {
954             U8 idx1 = 0;
955             /* Update issegment, soStart, soEnd ,sn  in nackSnInfo and handle
956              * nack sn*/
957             do
958             {
959                KwDlAmmGetNackSnInfoFrmNackRangeIdx(&AMDL, &pStaPdu->nackInfo[idx],
960                                                    retxNode, &nackSnInfo, idx1);
961                
962                kwAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, &nackSnInfo,
963                                                   &retxNode, &datCfm);
964                nackSnInfo.sn = ((nackSnInfo.sn + 1) & (AMDL.snModMask)); 
965                gRlcStats.amRlcStats.numRlcAmCellNackRx++;
966
967             }while((++idx1) < (nackSnInfo.nackRange));
968          }
969
970          idx++;
971       } /* End of nackCnt while loop */
972
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);
976
977       /* Update txNextAck */
978       kwAmmDlSetTxNextAck(&AMDL,txNextAck);
979    }
980    else
981    {
982      kwStatusAckCnt++;
983       /* For All ACKs */
984       RLOG_ARG2(L_UNUSED,DBG_RBID, rbCb->rlcId.rbId,
985                "kwHndlStaRsp: Received All ACKS UEID:%d CELLID:%d",
986                rbCb->rlcId.ueId,
987                rbCb->rlcId.cellId);
988
989       /* For the remaining ACKs  after last nackSn */
990       kwAmmDlUpdateTxAndReTxBufForAckSn(gCb,rbCb, mAckSn, retxNode, &datCfm);
991       
992       /* update txNextAck */
993       kwAmmDlSetTxNextAck(&AMDL, pStaPdu->ackSn); 
994    }
995
996    if(datCfm->numSduIds != 0)
997    {
998       if(datCfm->numSduIds > 1024)
999       {
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",
1003                   datCfm->numSduIds, 
1004                   datCfm->numSduIds-1024,
1005                   rbCb->rlcId.ueId,
1006                   rbCb->rlcId.cellId);
1007          datCfm->numSduIds = 1024;
1008       }
1009       kwSduSndCnt += datCfm->numSduIds;
1010       /* Sap control block */
1011       KwUiKwuDatCfm(&kwuSap->pst, kwuSap->suId, datCfm);
1012    }
1013    else
1014    {
1015       KW_SHRABL_STATIC_BUF_FREE(kwuSap->pst.region, kwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
1016    }
1017
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)
1023    {
1024       kwAmmSendDStaRsp(gCb, rbCb, &AMDL);
1025    }
1026
1027    RETVOID;
1028 }
1029
1030 /**
1031  * @brief Function to calculate the current buffer occupancy
1032  *
1033  * @details 
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
1038  *
1039  * @param[in] amDl AM mode donwlink control block 
1040  *
1041  *  @return S16
1042  *      Calculated bo
1043 */
1044 #ifdef ANSI
1045 PUBLIC S32 kwAmmCalculateBo
1046 (
1047 KwAmDl *amDl
1048 )
1049 #else
1050 PUBLIC S32 kwAmmCalculateBo(amDl)
1051 KwAmDl *amDl;
1052 #endif
1053 {
1054    S32 bo;
1055
1056    /* Make sure non of the bo's are negative */      
1057    if (amDl->bo < 0) 
1058    {   
1059       amDl->bo = 0;                         
1060    }
1061    
1062    if (amDl->cntrlBo < 0) 
1063    {
1064       amDl->cntrlBo = 0;               
1065    }
1066    
1067    if (amDl->retxBo < 0) 
1068    {
1069       amDl->retxBo = 0;                 
1070    }
1071
1072    bo = amDl->cntrlBo + amDl->retxBo;
1073
1074    /* if window is not stalled then add the transmit bo also */
1075    if (! KW_AM_IS_TRANS_WIN_STALLED(amDl)) 
1076    {
1077       bo += amDl->bo;
1078    }
1079    
1080    return bo;
1081 }
1082 U32 kwRxSdu;
1083
1084 /**
1085  * @brief Handler to queue the SDUs received from PDCP
1086  *       
1087  * @details
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
1090  *    same to MAC.
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 
1096  *       to MAC
1097  *
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
1102  *
1103  * @return Void
1104  *      -# RETVOID
1105 */
1106 #ifdef ANSI
1107 PUBLIC Void kwAmmQSdu
1108 (
1109 KwCb            *gCb,
1110 KwDlRbCb        *rbCb,
1111 Buffer          *mBuf,
1112 KwuDatReqInfo   *datReq
1113 )
1114 #else
1115 PUBLIC Void kwAmmQSdu(gCb, rbCb, mBuf, datReq)
1116 KwCb            *gCb;
1117 KwDlRbCb        *rbCb;
1118 Buffer          *mBuf;
1119 KwuDatReqInfo   *datReq;
1120 #endif
1121 {
1122    KwSdu       *sdu;
1123 #ifdef LTE_L2_MEAS
1124 #ifndef L2_L3_SPLIT
1125 #ifdef TENB_STATS
1126    U32         kwWinSz; 
1127 #endif
1128 #endif
1129 #endif
1130    TRC2(kwAmmQSdu)
1131
1132    /* Allocate sdu */
1133    KW_ALLOC_WC(gCb,sdu, sizeof(KwSdu)); 
1134
1135 #if (ERRCLASS & ERRCLS_ADD_RES)
1136    if (sdu == NULLP)
1137    {
1138       RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1139                "Memory allocation failed UEID:%d CELLID:%d",
1140                rbCb->rlcId.ueId,
1141                rbCb->rlcId.cellId);
1142       RETVOID;
1143    }
1144 #endif /* ERRCLASS & ERRCLS_RES */
1145
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);
1152
1153    sdu->mBuf = mBuf;
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
1160 #ifdef MSPD
1161 {
1162 extern U32 dlrate_kwu;
1163 dlrate_kwu += sdu->sduSz;
1164 }
1165 #endif
1166 #endif   
1167    /* Update nxtTx to point to the added sdu if this is the first SDU in the
1168     * queue */
1169    if (AMDL.nxtTx == NULLP)
1170    {
1171       RLOG_ARG2(L_UNUSED,DBG_RBID, rbCb->rlcId.rbId,
1172                "kwAmmQSdu: Received SDU will be transmitted next"
1173                "UEID:%d CELLID:%d",
1174                 rbCb->rlcId.ueId,
1175                 rbCb->rlcId.cellId);
1176       AMDL.nxtTx = sdu;
1177    }
1178
1179    /* Add sdu to the sdu list */
1180    cmLListAdd2Tail(&AMDL.sduQ, &sdu->lstEnt);
1181    sdu->lstEnt.node = (PTR)sdu;
1182 #ifdef LTE_L2_MEAS
1183 #ifndef L2_L3_SPLIT
1184 #ifdef TENB_STATS
1185    if (rbCb->ueCb->tenbStats)
1186    {
1187       if (AMDL.sduQ.count > rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxPktsInSduQ)
1188       {
1189          rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxPktsInSduQ = AMDL.sduQ.count;
1190       }
1191       kwWinSz = KW_AM_TRANS_WIN_SIZE(&AMDL);
1192       if (kwWinSz > rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxWindowSz)
1193       {
1194          rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxWindowSz = kwWinSz;
1195       }
1196    }
1197 #endif
1198 #endif
1199 #endif
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)
1203   {
1204      AMDL.estHdrSz += 2;
1205   }
1206   else
1207   {
1208      AMDL.estHdrSz += 3;
1209   }
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))
1214    {
1215       rbCb->ueCb->numActRb[rbCb->qci]++;
1216       gCb.kwL2Cb.numActUe[rbCb->qci]++;
1217    }
1218 #endif
1219
1220    if(!kwDlUtlIsReestInProgress(rbCb))
1221    {
1222       kwAmmSendDStaRsp(gCb, rbCb, &AMDL);
1223    }
1224
1225    RETVOID;
1226
1227
1228 /**
1229  *
1230  * @brief Private handler to construct control PDU
1231  *
1232  * @details
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.
1236  *
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 
1240  *
1241  *  @return Void 
1242  *
1243  */
1244 #ifdef ANSI
1245 PRIVATE Void kwAmmDlAssembleCntrlInfo 
1246 (
1247 KwCb       *gCb,
1248 KwDlRbCb   *rbCb,
1249 KwDatReq   *kwDatReq
1250 )
1251 #else
1252 PRIVATE Void kwAmmDlAssembleCntrlInfo(gCb, rbCb, kwDatReq)
1253 KwCb       *gCb;
1254 KwDlRbCb   *rbCb;
1255 KwDatReq   *kwDatReq;
1256 #endif
1257 {
1258    KwUdxDlSapCb   *sapCb;
1259    MsgLen         macHdrEstmt;
1260
1261    TRC2(kwAmmDlAssembleCntrlInfo)
1262
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))
1267    {
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;
1273       
1274       /* Create the status Pdu with the required NACKs */
1275       kwAmmCreateStatusPdu(gCb,rbCb,kwDatReq);
1276
1277       sapCb = KW_GET_DL_SAPCB(gCb, rbCb);
1278            KwDlUdxStaProhTmrStart(&(gCb->u.dlCb->udxDlSap->pst), 
1279                              sapCb->suId, &(rbCb->rlcId));
1280           
1281       /* Update number of pdus in pduInfo */
1282       kwDatReq->pduInfo.mBuf[kwDatReq->pduInfo.numPdu] = AMDL.mBuf; 
1283       kwDatReq->pduInfo.numPdu++;
1284       gRlcStats.amRlcStats.numDLStaPduSent++;
1285
1286       KW_FREE_SHRABL_BUF(gCb->u.dlCb->udxDlSap->pst.region, 
1287                          gCb->u.dlCb->udxDlSap->pst.pool,
1288                          AMDL.pStaPdu,
1289                          sizeof(KwUdxDlStaPdu));
1290
1291       AMDL.pStaPdu = NULLP;
1292       AMDL.mBuf = NULLP;
1293       gRlcStats.amRlcStats.numDLStaPduSent++;
1294    }
1295
1296    RETVOID;
1297 }
1298
1299 /**
1300  * @brief Handler to form the PDUs with the size indicated by MAC
1301  *
1302  * @details
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.
1308  *
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 
1316  *      utility function
1317  *
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 
1322  *
1323  * @return Void
1324  *
1325  */
1326 #ifdef ANSI
1327 PUBLIC Void kwAmmProcessSdus
1328 (
1329 KwCb       *gCb,
1330 KwDlRbCb   *rbCb,
1331 KwDatReq   *kwDatReq,
1332 Bool       fillCtrlPdu
1333 )
1334 #else
1335 PUBLIC Void kwAmmProcessSdus(gCb, rbCb, kwDatReq,fillCtrlPdu)
1336 KwCb       *gCb;
1337 KwDlRbCb   *rbCb;
1338 KwDatReq   *kwDatReq;
1339 Bool       fillCtrlPdu;
1340 #endif    
1341 {
1342    TRC2(kwAmmProcessSdus)
1343
1344
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
1348     * it is FALSE */ 
1349
1350    if ((AMDL.cntrlBo != 0) 
1351 #ifdef LTE_ADV
1352         && (fillCtrlPdu)
1353 #endif
1354                                )
1355    {
1356       kwDatReq->boRep.staPduPrsnt = TRUE;
1357       kwDatReq->boRep.staPduBo = AMDL.cntrlBo;
1358
1359       if (AMDL.pStaPdu != NULLP)
1360       {
1361          kwAmmDlAssembleCntrlInfo (gCb, rbCb, kwDatReq);
1362       }
1363       else
1364       {
1365          RLOG_ARG2(L_ERROR, DBG_RBID, rbCb->rlcId.rbId,
1366                   "Miscomputation of control Bo. UEID:%d CELLID:%d",
1367                   rbCb->rlcId.ueId,
1368                   rbCb->rlcId.cellId);
1369       }
1370       AMDL.cntrlBo = 0;
1371    }   
1372
1373    /* Retransmit PDUs /portions of PDUs available in retxLst */
1374    if ((kwDatReq->pduSz > 0) && (AMDL.nxtRetx != NULLP))
1375    {
1376       kwResegRetxPdus (gCb,rbCb, kwDatReq);
1377    }
1378
1379    /* Assemble SDUs to form new PDUs */ 
1380    if ((kwDatReq->pduSz > 0) && (AMDL.nxtTx != 0))
1381    {
1382       kwAssembleSdus(gCb,rbCb, kwDatReq); 
1383    }
1384   
1385    if (AMDL.nxtRetx != NULLP)
1386    {
1387       kwDatReq->boRep.oldestSduArrTime = AMDL.nxtRetx->sduMap.sdu->arrTime;
1388    }
1389    else if (AMDL.nxtTx != NULLP)
1390    {
1391       kwDatReq->boRep.oldestSduArrTime = AMDL.nxtTx->arrTime;
1392    }
1393    /* Accumulate bo */
1394    kwDatReq->boRep.bo = kwAmmCalculateBo(&AMDL);
1395    kwDatReq->boRep.staPduBo = AMDL.cntrlBo;
1396
1397    /* Hdr estimation is moved to kwAmmCreatePDu */
1398    kwDatReq->boRep.estHdrSz = AMDL.estHdrSz;
1399
1400    if(kwDatReq->pduSz > 0)
1401    {
1402       gRlcStats.amRlcStats.numDLBytesUnused += kwDatReq->pduSz;
1403    }
1404    RETVOID;
1405
1406
1407 /**
1408  * @brief Private handler split a PDU/segment into two
1409  *
1410  * @details
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.
1414  *
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
1418  *                       in this
1419  * @param[out]    next   The second part of the split pdu
1420  * @param[in]     size   The size witin crnt, at which to split   
1421  *
1422  * @return  Void
1423  *
1424  */
1425 #ifdef ANSI
1426 PRIVATE Void kwSplitPdu
1427 (
1428 KwCb       *gCb,
1429 KwDlRbCb   *rbCb,
1430 KwRetx     *crnt,
1431 KwRetx     *next,
1432 U16        size
1433 )
1434 #else
1435 PRIVATE Void kwSplitPdu(gCb, rbCb, crnt, next, size)
1436 KwCb       *gCb;
1437 KwDlRbCb   *rbCb;
1438 KwRetx     *crnt;
1439 KwRetx     *next;
1440 U16        size;
1441 #endif
1442 {
1443    U8            si;
1444    KwAmDl        *amDl = &AMDL;
1445
1446    TRC2(kwSplitPdu)
1447    /* Set the SN for the new segment */
1448    next->amHdr.sn = crnt->amHdr.sn;
1449
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;
1454    
1455    crnt->amHdr.p   = 0;
1456
1457    /* Update seg size */
1458    next->segSz = crnt->segSz - size;
1459    crnt->segSz = size;
1460
1461    /* Set the SO fields appropriately */
1462    /* MS_FIX for DL stall */
1463    next->soEnd = crnt->soEnd;
1464
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;
1470    
1471    /* intialize the other fields in the amHdr of next to 0 */
1472    next->amHdr.p = 0;
1473    next->amHdr.dc = 0;
1474    
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;
1480
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;
1486
1487    /* Compute the header size and update the BO appropriately */
1488    if(amDl->snLen == KW_AM_CFG_12BIT_SN_LEN)
1489    {
1490       next->hdrSz = KW_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1491       if(crnt->amHdr.si == KW_SI_FIRST_SEG)
1492       {
1493          crnt->hdrSz = KW_AM_SEG_12BIT_SN_WITHOUT_SO_HDRSZ;
1494       }
1495       else
1496       {
1497          crnt->hdrSz = KW_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1498       }
1499    }
1500    else
1501    {
1502       next->hdrSz = KW_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1503       if(crnt->amHdr.si == KW_SI_FIRST_SEG)
1504       {
1505          crnt->hdrSz = KW_AM_SEG_18BIT_SN_WITHOUT_SO_HDRSZ;
1506       }
1507       else
1508       {
1509          crnt->hdrSz = KW_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1510       }
1511    }
1512
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;
1518    
1519    RETVOID;
1520 }
1521
1522 /**
1523  * @brief Private handler to retransmit PDUs or PDU segments
1524  *
1525  * @details
1526  *    Its a private function called by kwProcessSdus, to create the 
1527  *    PDUs / its segments from the retransmission buffer available in RbCb.
1528  *       
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 
1535  *      required 
1536  *    - Concatenate data and header info and fill pduInfo 
1537  *    - Update retxCnt and send indication to PDCP if it reaches maxRetx 
1538  *      threshold
1539  *
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 
1543  *
1544  * @return  Void
1545  *
1546  */
1547 #ifdef ANSI
1548 PRIVATE Void kwResegRetxPdus 
1549 (
1550 KwCb       *gCb,
1551 KwDlRbCb   *rbCb,
1552 KwDatReq   *kwDatReq
1553 )
1554 #else
1555 PRIVATE Void kwResegRetxPdus(gCb, rbCb, kwDatReq)
1556 KwCb       *gCb;
1557 KwDlRbCb   *rbCb;
1558 KwDatReq   *kwDatReq;
1559 #endif
1560 {
1561    KwAmDl   *amDl;
1562    KwRetx   *retx;
1563    U8       hdr[KW_MAX_HDRSZ];
1564    U16      idx; 
1565    Buffer   *pdu;
1566    MsgLen   pduSz; 
1567 #ifdef LTE_L2_MEAS
1568    U16        sduIdx;
1569    KwL2MeasTb *l2MeasTb;
1570    KwlchInfo  *lchInfo;
1571    U8         numSdus;
1572 #endif
1573
1574    TRC2(kwResegRetxPdus)
1575
1576
1577    amDl  = &AMDL;
1578 #ifdef LTE_L2_MEAS
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)
1583    {
1584       RETVOID;
1585    }
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)
1590    {
1591       RETVOID;
1592    }
1593    l2MeasTb->numLchInfo++;
1594    lchInfo->lcId = rbCb->lch.lChId;
1595    lchInfo->numSdus = 0;
1596 #endif
1597
1598    while ((kwDatReq->pduSz > 0) && (amDl->nxtRetx != NULLP)&&
1599           (kwDatReq->pduInfo.numPdu < KW_MAX_PDU))
1600    {
1601       U16 tmpSz;
1602       
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;
1611
1612       /* kw003.201 - We should have at least one more than basic header */
1613       if (kwDatReq->pduSz <= retx->hdrSz)
1614       {
1615          RETVOID;
1616       }
1617       kwGetNxtRetx(gCb, &(amDl->nxtRetx));
1618
1619       /* Send retx buf without segmentation */
1620       if (kwDatReq->pduSz >= pduSz)
1621       {
1622          U8 pollBit;
1623          
1624          RLOG_ARG2(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId, 
1625                   "kwResegRetxPdus: Send retx buf without segmentation "
1626                   "UEID:%d CELLID:%d", 
1627                   rbCb->rlcId.ueId,
1628                   rbCb->rlcId.cellId);
1629
1630          if (retx->yetToConst)
1631          {
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;
1637          } 
1638
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);
1643
1644          kwDatReq->pduSz  -= pduSz;
1645          AMDL.estHdrSz    -= retx->hdrSz;
1646 #ifdef LTE_L2_MEAS   
1647
1648          if (rbCb->rlcId.rbType == CM_LTE_DRB)
1649          {
1650             numSdus = 0;
1651             for (sduIdx = lchInfo->numSdus ; 
1652                   ((numSdus < retx->numSdu) && (sduIdx < KW_L2MEAS_SDUIDX)) ; 
1653                   sduIdx++, numSdus++)
1654             {
1655                lchInfo->sduInfo[sduIdx].arvlTime = retx->sduMap[numSdus].sdu->arrTime;
1656                lchInfo->sduInfo[sduIdx].isRetxPdu = TRUE; /* TODO : for later use */
1657             }
1658             lchInfo->numSdus += numSdus;
1659          }
1660 #endif
1661       }
1662       else
1663       {
1664          KwRetx *tNode;
1665          
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",
1670                   rbCb->rlcId.ueId,
1671                   rbCb->rlcId.cellId);
1672
1673          /* Eliminate fixed header size if the pdu is segmented for the */
1674          /* first time                                                  */
1675          if(amDl->snLen == KW_AM_CFG_12BIT_SN_LEN)
1676          {
1677             if(retx->amHdr.si < KW_SI_LAST_SEG)
1678             {
1679                kwDatReq->pduSz -= KW_AM_SEG_12BIT_SN_WITHOUT_SO_HDRSZ;
1680             }
1681             else
1682             {
1683                kwDatReq->pduSz -= KW_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1684             }
1685          }
1686          else
1687          {
1688             if(retx->amHdr.si < KW_SI_LAST_SEG)
1689             {
1690                kwDatReq->pduSz -= KW_AM_SEG_18BIT_SN_WITHOUT_SO_HDRSZ;
1691             }
1692             else
1693             {
1694                kwDatReq->pduSz -= KW_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1695             }
1696          }
1697          if (kwDatReq->pduSz <= 0)
1698          {
1699             RETVOID;
1700          }
1701
1702          /* Allocate memory for tracking a new segment */
1703          KW_ALLOC_WC(gCb,tNode, sizeof(KwRetx)); 
1704 #if (ERRCLASS & ERRCLS_ADD_RES)
1705          if (tNode == NULLP)
1706          {
1707             RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1708                      "Memory allocation failed UEID:%d CELLID:%d",
1709                      rbCb->rlcId.ueId,
1710                      rbCb->rlcId.cellId);
1711             RETVOID;
1712          }
1713 #endif /* ERRCLASS & ERRCLS_RES */
1714
1715          /* initialize the list pointer to 0 instead of memset */
1716          tNode->lstEnt.next = 0;
1717          tNode->lstEnt.prev = 0;
1718          
1719          /* Segment header and data */
1720          KW_AM_RMV_HDR(gCb, rbCb, retx);
1721
1722          /* kw003.201 - Split the payload and update other fields */
1723          kwSplitPdu(gCb,rbCb, retx, tNode, kwDatReq->pduSz); 
1724
1725 #ifdef LTE_L2_MEAS
1726          numSdus = 0;
1727          /* ccpu00143043 */
1728          sduIdx = lchInfo->numSdus;
1729          for (numSdus = 0, sduIdx = lchInfo->numSdus; 
1730               ((numSdus < retx->numSdu) && (sduIdx < KW_L2MEAS_SDUIDX));
1731               numSdus++, sduIdx++)
1732          {
1733             lchInfo->sduInfo[sduIdx].arvlTime = 
1734                   retx->sduMap[numSdus].sdu->arrTime;
1735             lchInfo->sduInfo[sduIdx].isRetxPdu = TRUE;
1736          }
1737          lchInfo->numSdus = sduIdx;
1738          if ((retx->amHdr.lsf == 0) && (lchInfo->numSdus > 0))
1739          {
1740             lchInfo->numSdus--;
1741          }
1742 #endif
1743          /* Construct hdr with the available hdr values */
1744          kwConstructAmHdr(&retx->amHdr, hdr, amDl->snLen, &idx);
1745          SAddPreMsgMultInOrder(hdr, idx + 1, retx->seg);
1746
1747          retx->hdrSz = idx + 1;
1748
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; 
1754       }
1755
1756       kwCpyMsg(gCb,retx->seg, &pdu);
1757
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;
1767    }
1768 #ifndef ALIGN_64BIT
1769    RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId, 
1770                  "kwResegRetxPdus: retxBo after resegmentation = %ld"
1771                  "UEID:%d CELLID:%d", 
1772                  amDl->retxBo,
1773                  rbCb->rlcId.ueId,
1774                  rbCb->rlcId.cellId);
1775 #else
1776    RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
1777                  "kwResegRetxPdus: retxBo after resegmentation = %d "
1778                  "UEID:%d CELLID:%d", 
1779                  amDl->retxBo,
1780                  rbCb->rlcId.ueId,
1781                  rbCb->rlcId.cellId);
1782 #endif
1783
1784    RETVOID;
1785 }
1786
1787
1788 /**
1789  * @brief Private handler to assemble SDUs to form new data PDU(s)
1790  *
1791  * @details
1792  *    Its a private function called by kwProcessSdus, to create the new data 
1793  *    PDUs from the SDU queue of RbCb.
1794  *
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 
1799  *      as required 
1800  *    - Concatenate data and header info and fill pduInfo  
1801  *
1802  * @param[in]  rbCb     RB control block
1803  * @param[in]  kwdatReq DatReq to be sent to MAC 
1804  *
1805  * @return  Void 
1806  *
1807  */
1808 #ifdef ANSI
1809 PRIVATE Void kwAssembleSdus 
1810 (
1811 KwCb       *gCb,
1812 KwDlRbCb   *rbCb,
1813 KwDatReq   *kwDatReq
1814 )
1815 #else
1816 PRIVATE Void kwAssembleSdus (gCb, rbCb, kwDatReq)
1817 KwCb       *gCb;
1818 KwDlRbCb   *rbCb;
1819 KwDatReq   *kwDatReq;
1820 #endif
1821 {
1822    Buffer          *pdu         = NULLP;
1823    MsgLen          macGrntSz    = kwDatReq->pduSz;
1824    KwAmDl          *amDl        = &AMDL;
1825    KwSdu           *sdu         = amDl->nxtTx;
1826    KwSduMap        sduMap;
1827    Bool            nxtTxUpd     = FALSE;
1828    KwuDiscSduInfo  *discSduInfo = NULLP;
1829    KwKwuSapCb* kwuSap = gCb->u.dlCb->kwuDlSap + KW_UI_PDCP;
1830 #ifdef LTE_L2_MEAS
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;
1836    Bool             newIdx;
1837    Bool             isSduSegmented;
1838    S32              oldBo;
1839    KwlchInfo        lchInfo;
1840    KwlchInfo        *dstLchInfo;
1841    U32              segSduCnt = 0;
1842    U32              lchIdx;
1843    U32              numSdus = 0;
1844    U32              currSduIdx = 0;
1845    KwL2MeasTb       *l2MeasTb;
1846 #endif
1847    /* Discard new changes starts */
1848    Ticks                timeDiff = 0;
1849    Ticks                curTime  = 0;
1850    U8                   numNewPdu = 0;
1851    KwTx                 *txBuf = NULLP;
1852    /* Discard new changes ends */
1853    VOLATILE U32         startTime = 0;
1854    U32                  hdrEstmt;
1855    U32                  fixedHdrSz;
1856    U32                  pduSz;
1857    KwAmHdr              *amHdr = NULLP;
1858    KwDlPduInfo          *pduInfo = NULLP;
1859
1860    TRC2(kwAssembleSdus)
1861
1862
1863 #ifdef LTE_L2_MEAS   
1864    contSduLst.numSdus = 0; 
1865    contSduLst.lcId = rbCb->lch.lChId;
1866    oldBo = amDl->bo;
1867    lchInfo.lcId = rbCb->lch.lChId;
1868    lchInfo.numSdus = 0;
1869 #endif
1870    /* Discard new changes starts */
1871    /* Allocate memory for discSdu Info */
1872    KW_SHRABL_STATIC_BUF_ALLOC(kwuSap->pst.region,
1873                               kwuSap->pst.pool,
1874                               discSduInfo, 
1875                               sizeof(KwuDiscSduInfo));
1876
1877 #if (ERRCLASS & ERRCLS_ADD_RES)
1878    if (discSduInfo == NULLP)
1879    {
1880       RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId, 
1881                "Memory allocation failed UEID:%d CELLID:%d",
1882                rbCb->rlcId.ueId,
1883                rbCb->rlcId.cellId);
1884       RETVOID;
1885    }
1886 #endif /* ERRCLASS & ERRCLS_RES */
1887
1888    discSduInfo->numSduIds = 0;
1889    discSduInfo->rlcId = rbCb->rlcId;
1890
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)
1896    {
1897       fixedHdrSz   = KW_AM_PDU_12BIT_SN_HDRSZ;
1898    }
1899    else
1900    {
1901       fixedHdrSz   = KW_AM_PDU_18BIT_SN_HDRSZ;
1902    }
1903
1904    while ((macGrntSz > fixedHdrSz) && (sdu != NULLP) &&
1905           (kwDatReq->pduInfo.numPdu < KW_MAX_PDU) && 
1906           (numNewPdu < KW_MAX_NEW_DL_PDU))
1907    {
1908 #ifdef LTE_L2_MEAS   
1909       isSduSegmented = sdu->mode.am.isSegmented;
1910 #endif
1911       /* Discard new changes starts */
1912       if ((sdu->mode.am.isSegmented == FALSE) && (rbCb->discTmrInt > 0) && \
1913             (rbCb->rlcId.rbType == CM_LTE_DRB))
1914       {
1915          //leftAmSdus[rbCb->qci]--;
1916          timeDiff = KW_TIME_DIFF(curTime,sdu->arrTime); 
1917          if (timeDiff > rbCb->discTmrInt)
1918          {
1919             CmLList* nxtNode;
1920             /*starting Task*/
1921             SStartTask(&startTime, PID_RLC_AMM_DISC_SDUS);
1922 #ifdef LTE_L2_MEAS 
1923             KW_UPD_L2_DL_DISC_SDU_STS(gCb,rbCb);
1924             /* TODO need to send disc cfm to pdcp */
1925 #endif
1926             /* Update bo for boReport */
1927             amDl->bo -= sdu->sduSz;
1928
1929             /* Get next sdu for assembly */
1930             nxtNode = sdu->lstEnt.next;
1931
1932             /* store the info for sending it to PDCP */
1933             if(discSduInfo->numSduIds > 500)
1934             {
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",
1938                      rbCb->rlcId.ueId,
1939                      rbCb->rlcId.cellId);
1940                break;
1941             }
1942
1943             discSduInfo->sduIds[discSduInfo->numSduIds] = sdu->mode.am.sduId;
1944             discSduInfo->numSduIds++;
1945
1946             cmLListDelFrm(&amDl->sduQ, &sdu->lstEnt);
1947
1948             kwUtlAddSduToBeFreedQueue(gCb, sdu);
1949             kwUtlRaiseDlCleanupEvent(gCb);
1950
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;
1954
1955             if(nxtNode)
1956                sdu = (KwSdu*)nxtNode->node;
1957             else
1958                sdu = NULLP;
1959
1960             /*stopping Task*/
1961             SStopTask(startTime, PID_RLC_AMM_DISC_SDUS);
1962             continue;
1963          }
1964       }
1965       nxtTxUpd = FALSE;
1966
1967 #ifdef LTE_L2_MEAS
1968       newIdx = FALSE;
1969 #endif
1970       /** kw003.201 - Check for window stall when you are
1971        *  creating a new PDU
1972        */
1973       if (KW_AM_IS_TRANS_WIN_STALLED(amDl))
1974       {
1975          //int *a = NULLP;
1976          printf("\n Window stalled  \n");
1977          gRlcStats.amRlcStats.numRlcAmCellWinStall++;
1978          //*a = 10;
1979          break;
1980       }
1981
1982       hdrEstmt = fixedHdrSz; 
1983
1984       if (sdu->mode.am.isSegmented)
1985       {
1986          /* Adding two byte for SO */
1987          hdrEstmt += 2;
1988       } 
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;
1994
1995       macGrntSz -= hdrEstmt;
1996       /* kw005.201 Check for PDU Size is large enough.
1997        * Fix for ccpu00118973 
1998        * */
1999       if(macGrntSz <= 0)
2000       {
2001          break;
2002       }
2003
2004       /* Dont create new txBuf for segmented SDU */
2005       if (!sdu->mode.am.isSegmented)
2006       {
2007          /* Update txBuf */
2008          KW_ALLOC_WC(gCb,txBuf, sizeof(KwTx));
2009
2010          cmLListInit(&txBuf->pduLst);
2011
2012 #if (ERRCLASS & ERRCLS_ADD_RES)
2013          if (txBuf == NULLP)
2014          {
2015             U32 avblMem = 0;
2016             SRegInfoShow(gCb->init.region, &avblMem);
2017             RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId, 
2018                   "Memory allocation failed UEID:%d CELLID:%d",
2019                   rbCb->rlcId.ueId,
2020                   rbCb->rlcId.cellId);
2021             RETVOID;
2022          }
2023 #endif /* ERRCLASS & ERRCLS_RES */
2024
2025          kwUtlStoreTxBuf(amDl->txBufLst, txBuf, amDl->txNext);
2026       }
2027       else
2028       {
2029          txBuf = kwUtlGetTxBuf(amDl->txBufLst, amDl->txNext);
2030       }
2031
2032       KW_ALLOC_WC(gCb,pduInfo, sizeof(KwDlPduInfo));
2033 #if (ERRCLASS & ERRCLS_ADD_RES)
2034       if (pduInfo == NULLP)
2035       {
2036          U32 avblMem = 0;
2037          SRegInfoShow(gCb->init.region, &avblMem);
2038          RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId, 
2039                "Memory allocation failed UEID:%d CELLID:%d",
2040                rbCb->rlcId.ueId,
2041                rbCb->rlcId.cellId);
2042          RETVOID;
2043       }
2044 #endif /* ERRCLASS & ERRCLS_RES */
2045
2046       /*Initialize DL segment structure */
2047       pduInfo->lstEnt.next = NULLP;
2048       pduInfo->lstEnt.prev = NULLP;
2049       pduInfo->lstEnt.node = NULLP;
2050
2051       pduInfo->pdu = NULLP;
2052       pduInfo->amHdr.dc = 0;
2053       pduInfo->amHdr.p = 0;
2054       pduInfo->amHdr.si = 0;
2055       pduInfo->amHdr.so = 0;
2056
2057       pduInfo->amHdr.sn = amDl->txNext;
2058
2059       if (macGrntSz >= sdu->sduSz)
2060       {
2061          pdu = sdu->mBuf;     
2062          sdu->mBuf = NULLP; 
2063          /* Update Framing Info */
2064          if (sdu->mode.am.isSegmented) 
2065          {
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;
2071
2072
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);
2076          }
2077          else
2078          {
2079             gRlcStats.amRlcStats.numRlcAmCellSduTx++;
2080          }
2081          amHdr          = &pduInfo->amHdr; 
2082          /* Create PDU with hdr and data */
2083          kwAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
2084
2085          //printf("\n Segmentation not required case: numPdu %d pdu  %p \n",kwDatReq->pduInfo.numPdu, pdu);
2086
2087 #ifdef LTE_L2_MEAS_RLC
2088          kwUtlUpdSduSnMap(rbCb, sdu, kwDatReq, TRUE);
2089 #endif /*  LTE_L2_MEAS */
2090
2091          /* kw005.201 ccpu00117318, updating the statistics */
2092          kwUtlIncrementKwuStsSduTx(gCb->u.dlCb->kwuDlSap + rbCb->kwuSapId);
2093 #ifdef LTE_L2_MEAS
2094          if(KW_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb))
2095          {
2096             if(isSduSegmented)
2097             {
2098                *sduIdx    = dlIpThPut->lastSduIdx;
2099             }
2100             else
2101             {
2102                KW_GETSDUIDX(*sduIdx);
2103                newIdx = TRUE;
2104             }
2105             kwUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
2106             kwUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz, 
2107                   sdu->mode.am.sduId, newIdx);
2108             /* Update the arrival time for each SDU */
2109             /* ccpu00143043 */
2110             if ( lchInfo.numSdus < KW_L2MEAS_SDUIDX)
2111             {
2112                lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime; 
2113                lchInfo.numSdus++;
2114             }
2115          }
2116 #endif
2117          sduMap.sduSz    = sdu->sduSz;
2118       }
2119       else 
2120       {
2121          /* Segmentation
2122           * Allocate buffer for next PDU
2123           * Remove the segmented portion from SDUQ 
2124           * Calculate the hdr with LI for SDU */
2125
2126          Buffer  *remSeg = NULLP;
2127
2128          //printf("\n SDU segmentation case: numPdu %d pdu %p \n", kwDatReq->pduInfo.numPdu, pdu);
2129 #ifdef LTE_L2_MEAS
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) )
2133          {
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)
2137             {
2138                KW_GETSDUIDX(*sduIdx);
2139                newIdx = TRUE;
2140             }
2141             else
2142             {
2143                *sduIdx    = dlIpThPut->lastSduIdx;
2144             }
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))
2149             {
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)
2153                {
2154                   segSduCnt++;
2155                }
2156             }
2157          }
2158 #endif
2159
2160          /* Segment the SDU to the size of the PDU and update header Info */
2161          SSegMsg(sdu->mBuf, macGrntSz, &remSeg);
2162          pdu = sdu->mBuf;      
2163          sdu->mBuf = remSeg;
2164
2165          /* Update SI and SN */
2166          if (sdu->mode.am.isSegmented) 
2167          {
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;
2173
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);
2176          }
2177          else
2178          {
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;
2184
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);
2187          }
2188
2189          amHdr = &pduInfo->amHdr; 
2190          /* Create PDU with hdr and data */
2191          kwAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
2192
2193          sdu->mode.am.isSegmented = TRUE;
2194          sdu->sduSz -= macGrntSz;
2195          sduMap.sduSz = macGrntSz;
2196
2197 #ifdef LTE_L2_MEAS_RLC
2198          kwUtlUpdSduSnMap(rbCb, sdu, kwDatReq, FALSE);
2199 #endif /*  LTE_L2_MEAS */
2200
2201          amDl->nxtTx = sdu;
2202          nxtTxUpd    = TRUE;
2203       }
2204
2205       /* Update bo for boReport */
2206       amDl->bo -= sduMap.sduSz;
2207
2208       sduMap.sdu = sdu;
2209
2210       /* Update pduInfo */
2211       kwDatReq->pduInfo.mBuf[kwDatReq->pduInfo.numPdu] = pdu; 
2212       kwDatReq->pduInfo.numPdu++;
2213       numNewPdu++;
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));
2219       pdu = NULLP;
2220
2221       macGrntSz -= sduMap.sduSz;
2222       /* Get next sdu for assembly */
2223       KW_LLIST_NEXT_SDU(amDl->sduQ, sdu);
2224
2225    } /*End of pduSz loop */
2226
2227    kwDatReq->pduSz = macGrntSz;
2228    /* Updating nxtTx to sdu in the Q */
2229    if (!nxtTxUpd)
2230       amDl->nxtTx = sdu;
2231
2232 #ifdef LTE_L2_MEAS
2233    if(KW_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) && 
2234          (rbCb->rlcId.rbType == CM_LTE_DRB))
2235    {
2236       numSdus = 0;
2237       currSduIdx = 0;
2238       l2MeasTb = kwUtlGetCurMeasTb(gCb, rbCb);
2239       kwUtlUpdateBurstSdus(gCb, rbCb, &contSduLst, dataVol, *totMacGrant);
2240       if ((lchInfo.numSdus != 0) && (l2MeasTb != NULLP))
2241       {
2242          for (lchIdx = 0; ((lchIdx < l2MeasTb->numLchInfo)
2243                   && (lchIdx < KW_MAX_ACTV_DRB )); lchIdx++)
2244          {
2245             if (l2MeasTb->lchInfo[lchIdx].lcId == rbCb->lch.lChId)
2246             {
2247                /* Lch Info already added in Retx procedure */
2248                break;
2249             }
2250          }
2251          if (lchIdx < KW_MAX_ACTV_DRB)
2252          {
2253             if (lchIdx == l2MeasTb->numLchInfo)
2254             {
2255                l2MeasTb->lchInfo[lchIdx].lcId = rbCb->lch.lChId;
2256                l2MeasTb->lchInfo[lchIdx].numSdus = 0;
2257                l2MeasTb->numLchInfo++;
2258             }
2259             dstLchInfo = &l2MeasTb->lchInfo[lchIdx];
2260             currSduIdx = l2MeasTb->lchInfo[lchIdx].numSdus;
2261             while ((numSdus < lchInfo.numSdus) && (currSduIdx < KW_L2MEAS_SDUIDX)) 
2262             {
2263                dstLchInfo->sduInfo[currSduIdx].arvlTime = lchInfo.sduInfo[numSdus].arvlTime;
2264                dstLchInfo->sduInfo[currSduIdx].isRetxPdu = FALSE;
2265                numSdus++;
2266                currSduIdx++;
2267             }
2268             l2MeasTb->lchInfo[lchIdx].numSdus += numSdus;
2269          }
2270       }
2271       /* Fix Klock warning */
2272       if(l2MeasTb != NULLP)
2273       {
2274          l2MeasTb->txSegSduCnt += segSduCnt;
2275       }
2276    }
2277    *totMacGrant -= (oldBo - amDl->bo);
2278 #endif
2279
2280    if(discSduInfo->numSduIds != 0)
2281    {
2282       /* Sap control block */
2283       KwUiKwuDiscSduCfm(&kwuSap->pst, kwuSap->suId, discSduInfo);
2284    }
2285    else
2286    {
2287       KW_SHRABL_STATIC_BUF_FREE(kwuSap->pst.region, kwuSap->pst.pool, discSduInfo, sizeof(KwuDiscSduInfo));
2288    }
2289
2290
2291 #ifndef ALIGN_64BIT
2292    RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId, 
2293          "kwAssembleSdus: BO after assembly = %ld UEID:%d CELLID:%d",
2294          amDl->bo,
2295          rbCb->rlcId.ueId,
2296          rbCb->rlcId.cellId);
2297 #else
2298    RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
2299          "kwAssembleSdus: BO after assembly = %d UEID:%d CELLID:%d",
2300          amDl->bo,
2301          rbCb->rlcId.ueId,
2302          rbCb->rlcId.cellId);
2303 #endif
2304
2305    RETVOID;
2306 }
2307
2308 /**
2309  * @brief Private handler to check if the poll bit needs to be set for data PDU
2310  *
2311  * @details
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 
2314  *    same.
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 
2320  *
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
2325  *
2326  * @return  Bool 
2327  *      -# 1 - To set the poll bit
2328  *      -# 0 - Poll bit is not set
2329  *
2330  */
2331 #ifdef ANSI
2332 PRIVATE Bool kwAmmDlCheckAndSetPoll
2333 (
2334 KwCb       *gCb,
2335 KwDlRbCb   *rbCb,
2336 Bool       newPdu,
2337 MsgLen     bufSz
2338 )
2339 #else
2340 PRIVATE Bool kwAmmDlCheckAndSetPoll(gCb, rbCb, newPdu, bufSz)
2341 KwCb       *gCb;
2342 KwDlRbCb   *rbCb;
2343 Bool       newPdu;
2344 MsgLen     bufSz;
2345 #endif
2346
2347    Bool     pollBit = FALSE;
2348    KwAmDl   *amDl = &(rbCb->m.amDl);
2349
2350    TRC2(kwAmmDlCheckAndSetPoll)
2351
2352  
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*/ 
2355    if (newPdu)
2356    {
2357       amDl->pduWoPoll++;
2358       /* Patch kw004.201 */
2359       amDl->byteWoPoll += bufSz;
2360
2361      if (((amDl->pollPdu != -1) && (amDl->pduWoPoll >= amDl->pollPdu)) || 
2362          ((amDl->pollByte != -1) && (amDl->byteWoPoll >= amDl->pollByte))) 
2363      {
2364         pollBit = TRUE;
2365      }
2366    }
2367
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))
2371    {
2372       pollBit = TRUE;
2373    }
2374    
2375    if (pollBit)
2376    {
2377       amDl->pduWoPoll  = 0;
2378       amDl->byteWoPoll = 0;
2379
2380       amDl->pollSn = (amDl->txNext - 1) & amDl->snModMask;
2381
2382       RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId, 
2383                 "kwAmmDlCheckAndSetPoll: Poll SN = %d UEID:%d CELLID:%d", 
2384                 amDl->pollSn,
2385                 rbCb->rlcId.ueId,
2386                 rbCb->rlcId.cellId);
2387
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 .
2392        * */
2393       if( TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMDL_POLL_RETX_TMR) )
2394       {
2395          kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMDL_POLL_RETX_TMR);
2396       }
2397
2398       kwStartTmr(gCb,(PTR)rbCb, KW_EVT_AMDL_POLL_RETX_TMR);
2399    }
2400
2401    RETVALUE(pollBit);
2402 }
2403
2404 /**
2405  * @brief Private handler to create AMD PDU 
2406  *
2407  * @details
2408  *    This function constructs header and concatenate it with the data for
2409  *    the PDU. It also updates the txBuf with the created PDU.
2410  *
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 
2416  *
2417  *  @return  Void
2418  *
2419  */
2420 #ifdef ANSI
2421 PRIVATE Void kwAmmCreatePdu
2422 (  
2423 KwCb       *gCb,
2424 KwDlRbCb   *rbCb,
2425 KwAmHdr    *amHdr,
2426 KwDlPduInfo *pduInfo,
2427 Buffer     *pdu
2428 )
2429 #else
2430 PRIVATE Void kwAmmCreatePdu(gCb, rbCb, pduInfo, amHdr, pdu)
2431 KwCb       *gCb;
2432 KwDlRbCb   *rbCb;
2433 KwAmHdr    *amHdr;
2434 KwDlPduInfo *pduInfo;
2435 Buffer     *pdu;
2436 #endif
2437 {
2438    U8       hdr[KW_MAX_HDRSZ];
2439    U16      idx;
2440    KwTx     *txBuf;
2441    MsgLen   pduSz;
2442    KwAmDl   *amDl = &(rbCb->m.amDl);
2443
2444    TRC2(kwAmmCreatePdu)
2445
2446
2447    /* Update sn */
2448    amHdr->sn = amDl->txNext;
2449
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))
2452    {
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;
2456    }
2457
2458    /* Update hdr Info */
2459    SFndLenMsg(pdu, &pduSz);
2460
2461    /* passing newPDU = TRUE*/
2462    amHdr->p = kwAmmDlCheckAndSetPoll(gCb,rbCb, TRUE, pduSz);
2463
2464    /* Construct header with the available hdr Info, set isSegment to FALSE */
2465    kwConstructAmHdr(amHdr, hdr, amDl->snLen, &idx);
2466
2467    /* Concatenate hdr and data */
2468    SAddPreMsgMultInOrder(hdr, idx+1, pdu);
2469    
2470    txBuf = kwUtlGetTxBuf(amDl->txBufLst, amHdr->sn);
2471    kwCpyMsg(gCb,pdu,&(pduInfo->pdu));
2472    pduInfo->pduSz = pduSz;
2473    pduInfo->hdrSz = idx+1;
2474
2475    /*Update estHdrSz. deduct current hdrSz */
2476     amDl->estHdrSz -= pduInfo->hdrSz;
2477     /* Reestimate estHdrSz for mid and last seg */
2478     if(amHdr->si & 0x1)
2479     {
2480        amDl->estHdrSz += ((amHdr->si == KW_SI_MID_SEG)? pduInfo->hdrSz : (pduInfo->hdrSz + 2));
2481     }
2482
2483    cmLListAdd2Tail(&txBuf->pduLst, &pduInfo->lstEnt);
2484    pduInfo->lstEnt.node = (PTR)pduInfo;
2485
2486    gCb->genSts.bytesSent += pduSz;
2487    
2488    RETVOID;
2489 }
2490
2491 /**
2492  * @brief Private handler to remove the retx PDU from the rbCb
2493  *
2494  * @details
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.
2498  *
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
2502  *
2503  * @return Void 
2504  *
2505  */
2506 #ifdef ANSI
2507 PRIVATE Void kwRemRetxPdu
2508 (  
2509 KwCb          *gCb,
2510 KwDlRbCb      *rbCb,
2511 KwRetx        *retx
2512 )
2513 #else
2514 PRIVATE Void kwRemRetxPdu(gCb, rbCb, retx)
2515 KwCb          *gCb;
2516 KwDlRbCb      *rbCb;
2517 KwRetx        *retx;
2518 #endif
2519 {
2520    TRC2(kwRemRetxPdu)
2521
2522    cmLListDelFrm(&AMDL.retxLst, &retx->lstEnt); 
2523
2524    if( AMDL.retxLst.count == 0)
2525    {
2526       AMDL.nxtRetx = NULLP;
2527    }
2528
2529    if(retx->pendingReTrans == TRUE)
2530    {
2531       AMDL.retxBo -= retx->segSz;
2532       AMDL.estHdrSz -= retx->hdrSz;
2533    }
2534
2535    kwUtlAddReTxPduToBeFreedQueue(gCb, retx);
2536    kwUtlRaiseDlCleanupEvent(gCb);
2537
2538    RETVOID;
2539 }
2540
2541 /**
2542  * @brief Private handler to mark a retx PDU for further retransmission
2543  *
2544  * @details
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.
2549  *
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
2553  *
2554  * @return Void 
2555  *
2556  */
2557 #ifdef ANSI
2558 PRIVATE Void kwAmmDlMarkPduForReTx
2559 (
2560 KwCb          *gCb,
2561 KwDlRbCb      *rbCb,
2562 KwRetx        *retx
2563 )
2564 #else
2565 PRIVATE Void kwAmmDlMarkPduForReTx(*gCb, rbCb, retx)
2566 KwCb          *gCb;
2567 KwDlRbCb      *rbCb;
2568 KwRetx        *retx;
2569 #endif
2570 {
2571    TRC2(kwAmmDlMarkPduForReTx)
2572    if (AMDL.maxReTxReached == TRUE)
2573    {
2574       RETVOID;
2575    }
2576   
2577    if(retx->pendingReTrans == FALSE)
2578    {
2579       retx->pendingReTrans = TRUE;
2580       ++retx->retxCnt;
2581
2582       AMDL.retxBo   += retx->segSz;
2583       AMDL.estHdrSz += retx->hdrSz;
2584
2585       if (retx->retxCnt > AMDL.maxRetx)
2586       {
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)
2592          {
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++;
2601          }
2602
2603          kwRemRetxPdu(gCb,rbCb, retx);
2604          
2605          RETVOID;
2606       }
2607
2608
2609       if (AMDL.nxtRetx == NULLP)
2610       {
2611          AMDL.nxtRetx = retx;
2612       }
2613
2614       gRlcStats.amRlcStats.numDLRetransPdus++;
2615    }
2616
2617
2618    RETVOID;
2619 }
2620
2621 /**
2622  * @brief Private handler to check if SDU is completely deliverd and
2623  *        send higher layers data confirmation
2624  *
2625  * @details 
2626  *    This function sends higher layers data confirmation for SDUs which
2627  *    have been successfully delivered to the peer RLC entity.
2628  *
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
2633  *
2634  * @return Void 
2635  *
2636  */
2637 #ifdef ANSI
2638 PRIVATE Void kwAmmDlCheckIsSDUDelivered
2639 (
2640 KwCb            *gCb,
2641 KwDlRbCb        *rbCb,
2642 KwSduMap        *sduMap,
2643 KwuDatCfmInfo   **datCfm
2644 )
2645 #else
2646 PRIVATE Void kwAmmDlCheckIsSDUDelivered(gCb, rbCb, sduMap, datCfm)
2647 KwCb            *gCb;
2648 KwDlRbCb        *rbCb;
2649 KwSduMap        *sduMap;
2650 KwuDatCfmInfo   **datCfm;
2651 #endif
2652 {
2653    KwSdu *sdu;
2654    
2655    TRC2(kwAmmDlCheckIsSDUDelivered)
2656    
2657    sdu = sduMap->sdu;
2658
2659    sdu->mode.am.rcvdSz += sduMap->sduSz;
2660
2661    /* send a dat cfm if all the bytes of the sdu have been received */
2662    if (sdu->mode.am.rcvdSz == sdu->actSz)
2663    {
2664       /* Send DatCfm for this sdu */
2665       if((*datCfm)->numSduIds < KWU_MAX_DAT_CFM)
2666       {
2667          (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2668       }
2669       else
2670       {
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
2675           */
2676          KwKwuSapCb    *kwuSap;
2677          kwuSap = gCb->u.dlCb->kwuDlSap + KW_UI_PDCP;
2678          KwUiKwuDatCfm(&kwuSap->pst, kwuSap->suId, *datCfm);
2679
2680          KW_SHRABL_STATIC_BUF_ALLOC(kwuSap->pst.region, kwuSap->pst.pool, *datCfm, sizeof(KwuDatCfmInfo));
2681
2682 #if (ERRCLASS & ERRCLS_ADD_RES)
2683          if (*datCfm == NULLP)
2684          {
2685             RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId, 
2686                   "Memory allocation failed UEID:%d CELLID:%d",
2687                   rbCb->rlcId.ueId,
2688                   rbCb->rlcId.cellId);
2689             RETVOID;
2690          }
2691 #endif /* ERRCLASS & ERRCLS_RES */
2692
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;
2698       }
2699
2700       /* Remove SDU from the sduQ */
2701       cmLListDelFrm(&AMDL.sduQ, &sdu->lstEnt);
2702       kwUtlAddSduToBeFreedQueue(gCb, sdu);
2703       kwUtlRaiseDlCleanupEvent(gCb);
2704    }
2705
2706    RETVOID;
2707
2708
2709 /**
2710  * @brief Private handler to mark a PDU successful.
2711  *
2712  * @details
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.
2716  *
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 
2720  *
2721  * @return Void 
2722  *
2723  */
2724 #ifdef ANSI
2725 PRIVATE Void kwAmmDlProcessSuccessfulTxPdu
2726 (
2727 KwCb            *gCb,
2728 KwDlRbCb        *rbCb,
2729 KwSn            sn,
2730 KwuDatCfmInfo   **datCfm
2731 )
2732 #else
2733 PRIVATE Void kwAmmDlProcessSuccessfulTxPdu(gCb, rbCb, sn, datCfm)
2734 KwCb            *gCb;
2735 KwDlRbCb        *rbCb;
2736 KwSn            sn;
2737 KwuDatCfmInfo   **datCfm;
2738 #endif
2739 {
2740    TRC2(kwAmmDlProcessSuccessfulTxPdu)
2741    CmLList *pduNode;
2742   
2743    KwTx *txBuf = kwUtlGetTxBuf(AMDL.txBufLst, sn);
2744    
2745    if (txBuf == NULLP)
2746    {
2747            RETVOID;
2748    }
2749    pduNode = txBuf->pduLst.first;
2750    while(pduNode)
2751    {
2752       KwDlPduInfo *pduInfo = (KwDlPduInfo *)(pduNode->node);
2753       kwAmmDlCheckIsSDUDelivered(gCb,
2754                               rbCb,  
2755                               &(pduInfo->sduMap), 
2756                               datCfm);
2757       pduNode = pduNode->next;
2758    }
2759    
2760    kwUtlAddTxPduToBeFreedQueue(gCb, txBuf);
2761    kwUtlRaiseDlCleanupEvent(gCb);
2762    /* so that it is not processed again */
2763    kwUtlRemovTxBuf(AMDL.txBufLst, txBuf, gCb);
2764
2765    RETVOID;
2766 }
2767
2768 /**
2769  * @brief  Handler to send Status Indication to PDCP
2770  *
2771  * @details
2772  *    This function is used to send status indication to PDCP when the 
2773  *    maximum retransmission threshold value is reached for a PDU.
2774  * 
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
2778  *
2779  * @return  Void
2780  *
2781  */
2782 #ifdef ANSI
2783 PRIVATE Void kwAmmSndStaInd
2784 (
2785 KwCb       *gCb,
2786 KwDlRbCb   *rbCb,
2787 KwRetx     *retx
2788 )
2789 #else
2790 PRIVATE Void kwAmmSndStaInd(gCb, rbCb, retx)
2791 KwCb       *gCb;
2792 KwDlRbCb   *rbCb;
2793 KwRetx     *retx;
2794 #endif
2795 {
2796    KwuStaIndInfo   *staInd;
2797    KwKwuSapCb      *kwuSap;
2798
2799    TRC2(kwAmmSndStaInd);
2800
2801
2802    /* Sap control block */
2803    kwuSap = gCb->u.dlCb->kwuDlSap + KW_UI_PDCP;
2804
2805    /* Allocate memory for staInd Info */
2806    KW_SHRABL_STATIC_BUF_ALLOC(kwuSap->pst.region, kwuSap->pst.pool, staInd, sizeof(KwuStaIndInfo));
2807
2808 #if (ERRCLASS & ERRCLS_ADD_RES)
2809    if (staInd == NULLP)
2810    {
2811       RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId, 
2812             "Memory allocation failed UEID:%d CELLID:%d",
2813             rbCb->rlcId.ueId,
2814             rbCb->rlcId.cellId);
2815       RETVOID;
2816    }
2817 #endif /* ERRCLASS & ERRCLS_RES */
2818
2819    /* Fill staInd Info */ 
2820    KW_MEM_CPY(&staInd->rlcId, &rbCb->rlcId, sizeof(CmLteRlcId));    
2821    
2822    staInd->numSdu = 1;
2823    staInd->sduId[0] = retx->sduMap.sdu->mode.am.sduId;
2824
2825 #ifdef KW_PDCP
2826 #else
2827    KwUiKwuStaInd(&kwuSap->pst, kwuSap->suId, staInd);
2828 #endif /* KW_PDCP */
2829
2830    RETVOID;
2831 }
2832
2833 /**
2834  * @brief  Handler to get the next node to be retransmitted from retxLst
2835  *
2836  * @details
2837  *    This function is used to get the next node to be retransmitted 
2838  *    from the retxLst
2839  *            
2840  *  @param[in] gCb     RLC instance control block 
2841  *  @param[in] retx    The PDU/segment after which to find a node to be 
2842  *                     retransmitted
2843  *
2844  *  @return  Void 
2845  *
2846  */
2847 #ifdef ANSI
2848 PRIVATE Void kwGetNxtRetx 
2849 (
2850 KwCb     *gCb,
2851 KwRetx   **retx
2852 )
2853 #else
2854 PRIVATE Void kwGetNxtRetx(gCb, retx)
2855 KwCb     *gCb;
2856 KwRetx   **retx;
2857 #endif
2858 {
2859    CmLList *tNode;
2860
2861    TRC2(kwGetNxtRetx);
2862
2863    do
2864    {
2865       tNode = &((*retx)->lstEnt);
2866       tNode = tNode->next;
2867       
2868       if (tNode)
2869       {
2870          *retx = (KwRetx *)tNode->node;
2871       }
2872       else
2873       {
2874          *retx = NULLP;
2875          RETVOID;
2876       }
2877    }while((*retx)->pendingReTrans == FALSE);
2878
2879    RETVOID;
2880 }
2881
2882 /**
2883  * @brief  Handler to process the re-establishment request received from UIM
2884  *
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
2889  *                         function)
2890  *
2891  * @return  Void 
2892  *
2893  */
2894 #ifdef ANSI
2895 PUBLIC Void kwAmmDlReEstablish
2896 (
2897 KwCb         *gCb,
2898 CmLteRlcId   rlcId,
2899 KwDlRbCb     *rbCb
2900 )
2901 #else
2902 PUBLIC Void kwAmmDlReEstablish(gCb, rlcId, rbCb)
2903 KwCb         *gCb;
2904 CmLteRlcId   rlcId;
2905 KwDlRbCb     *rbCb;
2906 #endif
2907 {
2908    /* create a new AM DL RB, reset it and replace in the UeCb*/
2909    KwDlUeCb   *ueCb;
2910    KwDlRbCb   *resetRb;
2911    KwAmDl* newAmDl;
2912    KwAmDl* oldAmDl;
2913    KW_ALLOC(gCb, resetRb, sizeof(KwDlRbCb));
2914    
2915    /* ccpu00135170 Removing KLOCK warning */
2916    if(resetRb == NULLP)
2917    {
2918       RETVOID;
2919    }
2920
2921    KW_MEM_CPY(resetRb, rbCb, sizeof(KwDlRbCb));
2922    KW_MEM_SET(&resetRb->m.amDl, 0 , sizeof(KwAmDl));
2923
2924 /* AGHOSH changes start */
2925    /* restore the old AM values */
2926    newAmDl = &resetRb->m.amDl;
2927    oldAmDl = &rbCb->m.amDl;
2928
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 */
2939  
2940    if (ROK != kwDbmFetchDlUeCb(gCb,rlcId.ueId, rlcId.cellId, &ueCb))
2941    {
2942       RLOG_ARG2(L_ERROR,DBG_CELLID, rlcId.cellId,
2943                "UeId [%d]: UeCb not found RBID;%d",
2944                rlcId.ueId,
2945                rlcId.rbId);
2946       RETVOID;
2947    }
2948    
2949    if(rlcId.rbType == CM_LTE_SRB)
2950    {
2951       ueCb->srbCb[rlcId.rbId] = resetRb;
2952    }
2953    else
2954    {
2955       ueCb->drbCb[rlcId.rbId] = resetRb;
2956    }
2957    /* update into the logical channel array also */
2958    ueCb->lCh[rbCb->lch.lChId - 1].dlRbCb = resetRb;
2959  
2960    if((resetRb->rlcId.rbType == CM_LTE_SRB)
2961                 &&(resetRb->rlcId.rbId == 1))
2962    {
2963       /* To stop the traffic on SRB2 and other DRBs*/
2964       kwDlUtlSetReestInProgressForAllRBs(gCb, ueCb);
2965    }
2966    else 
2967    {
2968       kwDlUtlSetReestInProgressForRB(gCb, resetRb);      
2969    }
2970
2971    /* allocate the TX array again */
2972 #ifndef  LTE_TDD
2973    U32 hashIndex;
2974    KW_ALLOC(gCb,
2975                    resetRb->m.amDl.txBufLst,
2976                    (KW_TX_BUF_BIN_SIZE * sizeof(CmLListCp)));
2977    for(hashIndex = 0; hashIndex < KW_TX_BUF_BIN_SIZE; hashIndex++)
2978    {
2979            cmLListInit(&(resetRb->m.amDl.txBufLst[hashIndex]));
2980    }
2981 #endif
2982    /* send the old rb of deletion */
2983    kwAmmFreeDlRbCb(gCb,rbCb); 
2984
2985
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)
2990    {
2991       kwDlUtlResetReestInProgress(ueCb->srbCb[rlcId.rbId]);
2992    }
2993    else
2994    {
2995       kwDlUtlResetReestInProgress(ueCb->drbCb[rlcId.rbId]);
2996    }      
2997       
2998    RETVOID;
2999 }
3000
3001 /**
3002  * @brief  Handler to discard a SDU.
3003  *
3004  * @details
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.
3008  *   
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
3012  *
3013  *  @return  S16
3014  *     -# ROK      In case of successful discard
3015  *     -# RFAILED  In case the SDU is not found or already mapped
3016  */
3017 #ifdef ANSI
3018 PUBLIC S16 kwAmmDiscSdu
3019 (
3020 KwCb       *gCb,
3021 KwDlRbCb   *rbCb,
3022 U32        sduId 
3023 )
3024 #else
3025 PUBLIC S16 kwAmmDiscSdu(gCb, rbCb, sduId)
3026 KwCb       *gCb;
3027 KwDlRbCb   *rbCb;  
3028 U32        sduId; 
3029 #endif
3030 {
3031    TRC2(kwAmmDiscSdu);
3032    RETVALUE(RFAILED);
3033
3034
3035 /**
3036  * @brief  Handler for Poll retransmit timer expiry
3037  *
3038  * @details
3039  *    This function is used to handle events upon expiry of Poll 
3040  *    retransmit timer.
3041  *  
3042  * @param[in] gCb    RLC instance control block
3043  * @param[in] rbCb   Downlink RB control block 
3044  *
3045  * @return  Void 
3046  */
3047 #ifdef ANSI
3048 PUBLIC Void kwAmmPollRetxTmrExp
3049 (
3050 KwCb       *gCb,
3051 KwDlRbCb   *rbCb
3052 )
3053 #else
3054 PUBLIC Void kwAmmPollRetxTmrExp(gCb, rbCb)
3055 KwCb       *gCb;
3056 KwDlRbCb   *rbCb;
3057 #endif
3058 {
3059    KwRetx        *retx; 
3060    KwAmDl        *amDl = &(rbCb->m.amDl);
3061    KwSn          sn;
3062    KwTx          *txBuf;
3063    TRC2(kwAmmPollRetxTmrExp);
3064
3065    
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)
3074    {
3075       gRlcStats.amRlcStats.numDLPollTimerExpiresSrb++;
3076    }
3077    else
3078    {
3079       gRlcStats.amRlcStats.numDLPollTimerExpiresDrb++;
3080    }
3081
3082    if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) || 
3083         KW_AM_IS_TRANS_WIN_STALLED(amDl)) 
3084    {
3085       sn = (amDl->txNext - 1) & amDl->snModMask;
3086       txBuf = kwUtlGetTxBuf(amDl->txBufLst, sn);
3087
3088       if (txBuf != NULLP)
3089       {
3090          kwAmmDlMoveFrmTxtoRetxBuffer(gCb,amDl, &retx, sn); 
3091          
3092          if (AMDL.nxtRetx == NULLP)
3093          {
3094             AMDL.nxtRetx = retx;
3095          }
3096          
3097          kwAmmSendDStaRsp(gCb, rbCb, &AMDL);         
3098          RETVOID;
3099       }
3100       /* Get the last node in retxLst */
3101       KW_LLIST_LAST_RETX(amDl->retxLst, retx);
3102
3103       /* Unset wtForAck flag for the NACK PDUs */ 
3104       if (retx != NULLP)
3105       {
3106          kwAmmDlMarkPduForReTx(gCb, rbCb, retx);
3107          kwAmmSendDStaRsp(gCb, rbCb, &AMDL);         
3108       }
3109    }
3110
3111    RETVOID;
3112
3113
3114 /**
3115  * @brief  Handler to update Acks for the remaining PDUs after the last accessed
3116  *         NACK PDU.
3117  *
3118  * @details 
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.
3122  *
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          
3127  *
3128  * @return  Void
3129  *
3130  */
3131
3132 #ifdef ANSI
3133 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForAckSn
3134 (
3135 KwCb            *gCb,
3136 KwDlRbCb        *rbCb,
3137 KwSn            mAckSn,
3138 CmLList         *retxNode,
3139 KwuDatCfmInfo   **datCfm
3140 )
3141 #else
3142 PRIVATE Void kwAmmDlUpdateTxAndReTxBufForAckSn(gCb, rbCb, mAckSn, retxNode, datCfm)
3143 KwCb            *gCb;
3144 KwDlRbCb        *rbCb;
3145 KwSn            mAckSn;
3146 CmLList         *retxNode;
3147 KwuDatCfmInfo   **datCfm;
3148 #endif
3149 {
3150    KwSn    mSn;
3151    KwSn    sn;
3152    KwRetx  *retx;
3153    KwTx    *txBuf;
3154
3155    TRC2(kwAmmDlUpdateTxAndReTxBufForAckSn);
3156
3157    /* Remove pdus/segs from retxLst */ 
3158    while (retxNode)
3159    {
3160       retx = (KwRetx *)(retxNode->node);
3161       retxNode = retxNode->next;
3162       MODAMT(retx->amHdr.sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3163       if (mSn < mAckSn) 
3164       {
3165          kwAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
3166       }
3167    }
3168
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
3172       before ACK_SN*/
3173    mSn = 0;       /* same as MODAMT(AMDL.txNextAck, mSn, AMDL.txNextAck);*/
3174    sn = AMDL.txNextAck;
3175    while(mSn < mAckSn)
3176    {
3177       txBuf = kwUtlGetTxBuf(AMDL.txBufLst, sn);
3178       if (txBuf != NULLP)
3179       {
3180          RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId, 
3181                  "kwAmmDlUpdateTxAndReTxBufForAckSn: ACK for PDU "
3182                  "with sn = %ld UEID:%ld CELLID:%ld",
3183                  sn,
3184                  rbCb->rlcId.ueId,
3185                  rbCb->rlcId.cellId);
3186
3187          kwAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
3188       }
3189       
3190       sn = (sn + 1) & AMDL.snModMask;
3191       MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3192    }
3193
3194    RETVOID;
3195 }
3196
3197 /**
3198  * @brief  Handler to update Acks for the remaining PDUs after the last accessed
3199  *         NACK PDU.
3200  *
3201  * @details 
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.
3205  *
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          
3210  *
3211  * @return  Void
3212  *
3213  */
3214 #ifdef ANSI
3215 PRIVATE Void kwAmmDlUpdTxAndReTxBufForLessThanNackSn
3216 (
3217 KwCb            *gCb,
3218 KwDlRbCb        *rbCb,
3219 KwSn            sn,
3220 KwSn            mNackSn,
3221 CmLList         **retxNode,
3222 KwuDatCfmInfo   **datCfm
3223 )
3224 #else
3225 PRIVATE Void kwAmmDlUpdTxAndReTxBufForLessThanNackSn(gCb, rbCb, sn, mNackSn, retxNode, datCfm)
3226 KwCb            *gCb;
3227 KwDlRbCb        *rbCb;
3228 KwSn            sn;
3229 KwSn            mNackSn;
3230 CmLList         **retxNode;
3231 KwuDatCfmInfo   **datCfm;
3232 #endif
3233 {
3234    KwSn    mSn;
3235    KwRetx  *retx;
3236    KwTx    *txBuf=NULLP;
3237
3238    TRC2(kwAmmDlUpdTxAndReTxBufForLessThanNackSn);
3239
3240    while (*retxNode)
3241    {
3242       retx = (KwRetx *)((*retxNode)->node);
3243       MODAMT(retx->amHdr.sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3244       if (mSn < mNackSn)
3245       {
3246          (*retxNode) = (*retxNode)->next;
3247          kwAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
3248       }
3249       else
3250       {
3251          break;
3252       }
3253    }
3254
3255    /* Remove all pdus with SN < NACK_SN from the transmission buffer */ 
3256    MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3257    while (mSn < mNackSn)
3258    {
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)) 
3263       {
3264          RLOG_ARG3(L_DEBUG,DBG_RBID, rbCb->rlcId.rbId, 
3265                "kwHndlStaRsp: Handle ACK (sn = %d) UEID:%d CELLID:%d",
3266                sn,
3267                rbCb->rlcId.ueId,
3268                rbCb->rlcId.cellId);
3269
3270          /* Remove pdus from txBuf */
3271          kwAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
3272       }
3273
3274       sn = (sn + 1) & AMDL.snModMask;
3275       MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3276    }
3277    
3278    RETVOID;
3279 }
3280
3281
3282 /**
3283  * @brief  Handler to form construct AM header
3284  *
3285  * @details 
3286  *    This function is used to construct am header with the available header
3287  *    elements.
3288  *
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
3294  *  
3295  * @return Void            
3296  *
3297  */
3298 #ifdef ANSI
3299 PRIVATE Void kwConstructAmHdr
3300 (
3301 KwAmHdr   *amHdr,
3302 U8        *hdr,
3303 U8         snLen,
3304 U16       *idx
3305 )
3306 #else
3307 PRIVATE Void kwConstructAmHdr(amHdr, hdr, snLen, idx)
3308 KwAmHdr   *amHdr;
3309 U8        *hdr;
3310 U8         snLen;
3311 U16       *idx;
3312 #endif
3313 {
3314    TRC2(kwConstructAmHdr);
3315                                                             
3316    *idx = 0;
3317     hdr[0] = KW_DATA_BITMASK;
3318     
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)
3322    {
3323       hdr[0] = hdr[0] | (U8)((amHdr->sn & 0xF00) >> 8);
3324       hdr[1] =  (U8)(amHdr->sn & 0x0FF);
3325       (*idx)++;
3326    }
3327    else
3328    {
3329       hdr[0] = hdr[0] | (U8)((amHdr->sn & 0x30000) >> 16);
3330       hdr[1] =  (U8)((amHdr->sn & 0xFF00) >> 8);
3331       (*idx)++;
3332       hdr[2] =  (U8)(amHdr->sn & 0xFF);
3333       (*idx)++;
3334    }
3335     
3336    if ((amHdr->si == KW_SI_MID_SEG) || (amHdr->si == KW_SI_LAST_SEG))                                      
3337    {
3338       (*idx)++;
3339       hdr[(*idx)] = (U8)((amHdr->so & 0xFF00)>> 8);
3340       (*idx)++;
3341       hdr[(*idx)] = (U8)(amHdr->so & 0xFF);
3342    }                                                        
3343
3344    RETVOID;
3345 }
3346
3347 /**
3348  * @brief  This function adds a retx PDU to list of retx PDUs
3349  *
3350  * @details
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   
3354  *
3355  * @param[in] amDl   AM Downlink Control Block
3356  * @param[in] retx   Retransmit PDU
3357  * 
3358  * @return Void
3359  *            
3360  */
3361 #ifdef ANSI
3362 PRIVATE Void kwAmmAddPduToRetxLst
3363 (
3364 KwAmDl   *amDl,
3365 KwRetx   *retx
3366 )
3367 #else
3368 PRIVATE Void kwAmmAddPduToRetxLst(amDl, retx)
3369 KwAmDl   *amDl;
3370 KwRetx   *retx;
3371 #endif
3372 {
3373    CmLList   *node;
3374    KwRetx    *tRetx;
3375    KwSn      tMSn;
3376    KwSn      retxMSn;
3377    
3378    TRC2(kwAmmAddPduToRetxLst);
3379  
3380    node = amDl->retxLst.last;
3381    MODAMT(retx->amHdr.sn, retxMSn, amDl->txNextAck,amDl->snModMask);
3382    while(node != NULLP)
3383    {
3384       tRetx = (KwRetx *)(node->node);
3385       MODAMT(tRetx->amHdr.sn, tMSn, amDl->txNextAck,amDl->snModMask);
3386       if (tMSn > retxMSn)
3387       {
3388          node = node->prev;
3389       }
3390       else
3391       {
3392          break;
3393       }
3394    }
3395    if (node)
3396    {
3397       amDl->retxLst.crnt = node;
3398       cmLListInsAfterCrnt(&amDl->retxLst, &retx->lstEnt);
3399       retx->lstEnt.node = (PTR)retx;
3400    }
3401    else
3402    {
3403       amDl->retxLst.crnt = amDl->retxLst.first;
3404       cmLListInsCrnt(&amDl->retxLst, &retx->lstEnt);
3405       retx->lstEnt.node = (PTR)retx;
3406    }
3407
3408    if (amDl->nxtRetx == NULLP)
3409    {
3410       amDl->nxtRetx = retx;
3411    }
3412
3413    RETVOID;
3414 }
3415
3416 /**
3417  * @brief Handler to Move the PDU from txBuf to re-transmission buffer 
3418  *
3419  * @details
3420  *    This function is used to move the PDU from the txBuf to re-transmit buffer
3421  *
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
3425  *                         this function
3426  * @param[in]  sn          SN in the tx buffer which needs to be moved
3427  * 
3428  * @return Void
3429  *            
3430  */
3431
3432 #ifdef ANSI
3433 PRIVATE Void kwAmmDlMoveFrmTxtoRetxBuffer
3434 (
3435 KwCb          *gCb,
3436 KwAmDl        *amDl,
3437 KwRetx        **retx,
3438 KwSn          sn
3439 )
3440 #else
3441 PRIVATE Void kwAmmDlMoveFrmTxtoRetxBuffer(gCb, amDl, retx, sn)
3442 KwCb          *gCb;
3443 KwAmDl        *amDl;
3444 KwRetx        **retx;
3445 KwSn          sn; 
3446 #endif
3447 {
3448    KwTx* txBuf = kwUtlGetTxBuf(amDl->txBufLst, sn);
3449    TRC2(kwAmmDlMoveFrmTxtoRetxBuffer);
3450
3451    if (txBuf == NULLP)
3452    {
3453            RETVOID;
3454    }
3455    while(txBuf->pduLst.first)
3456    {
3457       KwDlPduInfo *pduInfo = (KwDlPduInfo *)(txBuf->pduLst.first->node);
3458       KW_ALLOC_WC(gCb,*retx, sizeof(KwRetx));
3459
3460 #if (ERRCLASS & ERRCLS_ADD_RES)
3461       if (*retx == NULLP)
3462       {
3463               RLOG0(L_FATAL, "Memory allocation failed");
3464               RETVOID;
3465       }
3466 #endif /* ERRCLASS & ERRCLS_RES */
3467
3468       /* Move Sdu byte segment from TX buf to retx buf*/
3469       kwAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb, 
3470             amDl, 
3471             retx, 
3472             pduInfo);
3473       
3474       /* Delete node from the txBuf Pdu lst */
3475       cmLListDelFrm(&txBuf->pduLst, txBuf->pduLst.first);
3476       KW_FREE_WC(gCb, pduInfo, sizeof(KwDlPduInfo));
3477    }
3478    /* Remove PDU from txBuf */
3479    kwUtlDelTxBuf(amDl->txBufLst, txBuf,gCb); 
3480    
3481    RETVOID;
3482 }
3483
3484
3485
3486 /*
3487  * @brief
3488  *    function to free/release the Acknowledged mode RBCB buffers
3489  *
3490  * @details
3491  *    This primitive Frees the Acknowledged Mode RbCb transmission Buffer,
3492  *    retransmission Buffer and reciption Buffers
3493  *
3494  * @param [in]   gCb    - RLC instance control block
3495  * @param [in]   rbCb   - Downlink RB Control Block
3496  *
3497  * @return Void
3498  */
3499 #ifdef ANSI
3500 PUBLIC Void kwAmmFreeDlRbCb
3501 (
3502 KwCb       *gCb,
3503 KwDlRbCb   *rbCb
3504 )
3505 #else
3506 PUBLIC Void kwAmmFreeDlRbCb(gCb,rbCb)
3507 KwCb       *gCb;
3508 KwDlRbCb   *rbCb;
3509 #endif
3510 {
3511    /* stop the re-transmission timer */
3512    if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMDL_POLL_RETX_TMR))
3513    {
3514       kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMDL_POLL_RETX_TMR);
3515    }
3516
3517    /* store the entire Rb pointer */      
3518    rbCb->rlsLnk.node = (PTR)rbCb;
3519    cmLListAdd2Tail(&gCb->u.dlCb->toBeFreed.rbLst, &rbCb->rlsLnk);
3520
3521    /* the sdu queue */
3522    cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.amDl.sduQ));
3523
3524    kwUtlRaiseDlCleanupEvent(gCb);
3525    
3526    RETVOID;
3527 }
3528
3529 /**
3530  * @brief  Handler to create STATUS Pdu
3531  *
3532  * @details
3533  *    This function is used to create status pdu 
3534  *
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
3538  *
3539  * @return Void
3540  *
3541  */
3542 #ifdef ANSI
3543 PRIVATE Void kwAmmCreateStatusPdu
3544 (
3545 KwCb       *gCb,
3546 KwDlRbCb   *rbCb,
3547 KwDatReq   *kwDatReq
3548 )
3549 #else
3550 PRIVATE Void kwAmmCreateStatusPdu(gCb, rbCb, kwDatReq)
3551 KwCb       *gCb;
3552 KwDlRbCb   *rbCb;
3553 KwDatReq   *kwDatReq;
3554 #endif
3555 {
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 */
3563     U16             encIdx = 0;
3564     U16             prevEncIdx = 0;
3565     KwNackInfo      *kwNackInfo;
3566     U16           nkCnt = 0;
3567
3568     TRC2(kwAmmCreateStatusPdu)
3569
3570
3571     pStaPdu = AMDL.pStaPdu;
3572
3573
3574     /* D/C| CPT| */
3575     /* 0 - Control
3576        1 - Data */
3577     cntrlPdu[0] = 0x00;
3578     cntrlPdu[2] = 0x00;
3579
3580     /* ACK SN Field will be set in the end based on available Grant */
3581
3582     encIdx = bytesToEncode = 3; /* Num Octets before NACK SN info encoding*/
3583
3584     ack_sn = pStaPdu->ackSn;
3585
3586     if (rbCb->m.amDl.snLen == KW_AM_CFG_12BIT_SN_LEN)
3587     {
3588
3589        /* If alteast one NACK SN Info then set the E1 field */
3590        if (pStaPdu->nackCount)
3591        {
3592           /* 12 BIT SN CASE:
3593              In Third Octet:
3594              7  6 5 4 3 2 1 0
3595              E1 R R R R R R R 
3596            */
3597           cntrlPdu[2] = 0x80;
3598        }
3599
3600        for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3601        {           
3602           sn = pStaPdu->nackInfo[nkCnt].sn;
3603
3604           kwNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3605
3606           bytesToEncode += 2; /* 2 Octets for NACK SN */
3607
3608           /* Check if E2 : isSegment is set */
3609           if (kwNackInfo->isSegment)
3610           {
3611              bytesToEncode += 4; /* 4 Octets: SOstart, SOend */ 
3612           }
3613
3614           /* Check if E3 : nackRange is set */
3615           if (kwNackInfo->nackRange)
3616           {
3617              bytesToEncode += 1; /* 1 Octet: NACK range */
3618           }
3619
3620           /* Check if this NACK info can be accomodated in the Grant */
3621           if( kwDatReq->pduSz >= bytesToEncode)
3622           {
3623              /* If there is a NACK SN before this then set its 
3624                 E1 bit */
3625              if(prevEncIdx)
3626              {
3627                 /* NACKSN  E1 E2 E3 R */
3628                 cntrlPdu[prevEncIdx + 1] |= 0x8;
3629              }
3630
3631              /* 12 BIT Nack SN encode */
3632              cntrlPdu[encIdx] = (sn & 0xFF0) >> 4;
3633
3634              /* Next Octet */
3635              cntrlPdu[encIdx + 1] = (sn & 0xF) << 4;
3636
3637              if (kwNackInfo->isSegment)
3638              {
3639                 /*Set E2 Bit */
3640                 cntrlPdu[encIdx + 1] |= 0x4;
3641
3642
3643                 /* Add soStart and soEnd */
3644                 /* SOstart */
3645                 cntrlPdu[encIdx + 2] = (kwNackInfo->soStart) >> 8; 
3646                 cntrlPdu[encIdx + 3] = kwNackInfo->soStart & 0xFF;
3647
3648                 /* SOend */
3649                 cntrlPdu[encIdx + 4] = (kwNackInfo->soEnd) >> 8;
3650                 cntrlPdu[encIdx + 5] = kwNackInfo->soEnd & 0xFF;
3651              }
3652
3653              if (kwNackInfo->nackRange)
3654              {
3655                 /*Set E3 Bit */
3656                 cntrlPdu[encIdx + 1] |= 0x2;
3657                 if(kwNackInfo->isSegment)
3658                 {
3659                    cntrlPdu[encIdx + 6] = kwNackInfo->nackRange;
3660                 }
3661                 else
3662                 {
3663                    cntrlPdu[encIdx + 2] = kwNackInfo->nackRange;
3664                 }
3665              }
3666
3667              gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3668           }
3669           /* Set ACK SN now */
3670           else
3671           {
3672              ack_sn = kwNackInfo->sn;
3673
3674              /* Not even one nack can be accomodated */
3675              if (nkCnt == 0)
3676              {
3677                cntrlPdu[2] = 0x0;
3678              }
3679
3680              break;
3681           }
3682
3683           prevEncIdx = encIdx;
3684           encIdx = bytesToEncode;
3685
3686        }/* Loop is done for the NackCount */
3687
3688         /* set ACK SN */
3689        {
3690
3691           RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId, 
3692                 "kwAssembleCntrlInfo: ACK PDU's SN = %d"
3693                 "UEID:%d CELLID:%d",
3694                 ack_sn,
3695                 rbCb->rlcId.ueId,
3696                 rbCb->rlcId.cellId);
3697
3698           cntrlPdu[0] |= (ack_sn & 0xF00)>> 8; 
3699           cntrlPdu[1] =  (U8)ack_sn;
3700        }
3701
3702     }
3703     else if (rbCb->m.amDl.snLen == KW_AM_CFG_18BIT_SN_LEN)
3704     {
3705        /* If alteast one NACK SN Info then set the E1 field */
3706        if (pStaPdu->nackCount)
3707        {
3708           /* 12 BIT SN CASE:
3709              In Third Octet:
3710              7  6 5 4 3 2 1 0
3711              ACKSN       E1 R 
3712            */
3713           cntrlPdu[2] = 0x2;
3714        }
3715
3716        for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3717        {           
3718           sn = pStaPdu->nackInfo[nkCnt].sn;
3719
3720           kwNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3721
3722           bytesToEncode += 3; /* 3 Octets for NACK SN */
3723
3724           /* Check if E2 : isSegment is set */
3725           if (kwNackInfo->isSegment)
3726           {
3727              bytesToEncode += 4; /* 4 Octets: SOstart, SOend */ 
3728           }
3729
3730           /* Check if E3 : nackRange is set */
3731           if (kwNackInfo->nackRange)
3732           {
3733              bytesToEncode += 1; /* 1 Octet: NACK range */
3734           }
3735
3736           /* Check if this NACK info can be accomodated in the Grant */
3737           if( kwDatReq->pduSz >= bytesToEncode)
3738           {
3739              /* If there is a NACK SN before this then set its 
3740                 E1 bit */
3741              if(prevEncIdx)
3742              {
3743                 /* NACKSN  E1 E2 E3 R R R */
3744                 cntrlPdu[prevEncIdx + 2] |= 0x20;
3745              }
3746
3747              /* 18 BIT Nack SN encode */
3748              cntrlPdu[encIdx] = (U8)((sn & 0x3FC00) >> 10);
3749
3750              /* Next Octet */
3751              cntrlPdu[encIdx + 1] = (U8)((sn & 0x3FC) >> 2);
3752
3753              /* Next Octet */
3754              cntrlPdu[encIdx + 2] = (U8)((sn & 0x3)<< 6);
3755
3756              if (kwNackInfo->isSegment)
3757              {
3758                 /* NACKSN  E1 E2 E3 R R R */
3759                 /*Set E2 Bit */
3760                 cntrlPdu[encIdx + 2] |= 0x10;
3761
3762
3763                 /* Add soStart and soEnd */
3764                 /* SOstart */
3765                 cntrlPdu[encIdx + 3] = (kwNackInfo->soStart) >> 8;
3766                 cntrlPdu[encIdx + 4] = (U8)kwNackInfo->soStart;
3767
3768                 /* SOend */
3769                 cntrlPdu[encIdx + 5] = (kwNackInfo->soEnd) >> 8; 
3770                 cntrlPdu[encIdx + 6] = (U8)(kwNackInfo->soEnd);
3771              }
3772
3773              if (kwNackInfo->nackRange)
3774              {
3775                 /* NACKSN  E1 E2 E3 R R R */
3776                 /*Set E3 Bit */
3777                 cntrlPdu[encIdx + 2] |= 0x08;
3778
3779                 if (kwNackInfo->isSegment)
3780                 {
3781                    cntrlPdu[encIdx + 7] = kwNackInfo->nackRange;
3782                 }
3783                 else
3784                 {
3785                    cntrlPdu[encIdx + 3] = kwNackInfo->nackRange;
3786                 }
3787              }
3788
3789              gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3790           }
3791           /* Set ACK SN now */
3792           else
3793           {
3794              ack_sn = kwNackInfo->sn;
3795
3796              /* Not even one nack can be accomodated */
3797              if (nkCnt == 0)
3798              {
3799                cntrlPdu[2] &= 0xFD;
3800              }
3801
3802              break;
3803           }
3804
3805           prevEncIdx = encIdx;
3806           encIdx = bytesToEncode;
3807
3808        }/* Loop is done for the NackCount */
3809    
3810        /* set ACK SN */
3811        {
3812
3813           RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId, 
3814                 "kwAssembleCntrlInfo: ACK PDU's SN = %d"
3815                 "UEID:%d CELLID:%d",
3816                 ack_sn,
3817                 rbCb->rlcId.ueId,
3818                 rbCb->rlcId.cellId);
3819
3820
3821           cntrlPdu[0] |=  (ack_sn & 0x3C000) >> 14;
3822           cntrlPdu[1] =  (ack_sn & 0x3FC0) >> 6;
3823           cntrlPdu[2] |= (ack_sn & 0x3F)<< 2;
3824        }
3825
3826     }
3827     else
3828     {
3829        /* ERROR Log */
3830        RLOG_ARG3(L_ERROR,DBG_RBID,rbCb->rlcId.rbId, 
3831              "kwAssembleCntrlInfo:Conf SN LEN  %d  is INVALID !!!! UEID:%d CELLID:%d",
3832              rbCb->m.amDl.snLen,
3833              rbCb->rlcId.ueId,
3834              rbCb->rlcId.cellId);
3835     }
3836
3837
3838 #ifndef L2_OPTMZ
3839     SGetMsg(KW_GET_MEM_REGION(gCb), KW_GET_MEM_POOL(gCb),&mBuf);
3840 #else
3841     mBuf = (Buffer *)kwAmmStaPduList[kwAmmStaPduListCnt++];
3842     SResetMBuf(mBuf);
3843     if(kwAmmStaPduListCnt > 511)
3844        kwAmmStaPduListCnt = 0;
3845 #endif
3846
3847     cntrlPduSz = encIdx;
3848     SAddPstMsgMult (cntrlPdu, cntrlPduSz, mBuf);
3849
3850     kwDatReq->pduSz -= cntrlPduSz;
3851     /* Add mBuf to AMDL.mBuf */
3852     AMDL.mBuf = mBuf;
3853  
3854     RETVOID;
3855 }
3856
3857 #ifdef RLC_STA_PROC_IN_MAC/* RLC Status PDU Processing */
3858
3859 S16 kwProcDlStatusPdu(Pst *udxPst,SuId suId,
3860       CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu);
3861
3862 #ifdef ANSI
3863 PRIVATE Void rgAmmExtractElmnt
3864 (
3865 KwCb       *gCb,
3866 Buffer     *pdu,
3867 KwExtHdr   *hdrInfo
3868 )
3869 #else
3870 PRIVATE Void rgAmmExtractElmnt(gCb, pdu, hdrInfo)
3871 KwCb       *gCb;
3872 Buffer     *pdu;
3873 KwExtHdr   *hdrInfo;
3874 #endif
3875 {
3876    U8   hdr;
3877    U8   pLen = hdrInfo->pLen;
3878    U8   len  = (U8)hdrInfo->len;
3879    U16  val;
3880    U8   tHdr;
3881    U8   fLen;
3882    U8   rLen;
3883    /* U8   rLen1 = 0; */
3884    U16  tVal;
3885
3886    TRC2(kwAmmExtractElmnt);
3887
3888    hdr = hdrInfo->hdr;
3889
3890    if (pLen == 0)
3891    {
3892       SRemPreMsg(&hdr, pdu);
3893       pLen = 8;
3894    }
3895    tHdr = hdr;
3896    if (len <= 8)
3897    {
3898       val = tHdr >> (KW_BYTE_LEN - (len));
3899       hdr =  hdr << len;
3900       pLen -= len;
3901    }
3902    else /*if (len > 8) */
3903    {
3904       fLen = pLen;
3905       val = tHdr;
3906       val = val >> (KW_BYTE_LEN - fLen);
3907       val = val << (len - fLen);
3908       rLen = len - fLen;
3909       SRemPreMsg(&hdr, pdu);
3910       tHdr = hdr;
3911       if (rLen <= 8)
3912       {
3913          hdr = hdr >> (KW_BYTE_LEN - rLen);
3914          val = val | hdr;
3915          hdr = tHdr << rLen;
3916          pLen = (KW_BYTE_LEN - rLen);
3917       }
3918       else
3919       {
3920         rLen = rLen - KW_BYTE_LEN;
3921         tVal = hdr;
3922         tVal = tVal << rLen;
3923         val = val | tVal;
3924
3925         SRemPreMsg(&hdr, pdu);
3926         tHdr = hdr;
3927         hdr = hdr >> (KW_BYTE_LEN - rLen);
3928         val = val | hdr;
3929         hdr = tHdr << rLen;
3930         pLen = (KW_BYTE_LEN - rLen);
3931       }
3932    }
3933
3934    hdrInfo->pLen = pLen;
3935    hdrInfo->hdr = hdr;
3936    hdrInfo->val = val;
3937
3938    RETVOID;
3939 }
3940
3941
3942
3943
3944 #ifdef ANSI
3945 PRIVATE Void rgAmmUlHndlStatusPdu
3946 (
3947 Pst        *udxPst,
3948 SuId       suId,
3949 KwCb       *gCb,
3950 KwDlRbCb   *rbCb,
3951 Buffer     *cntrlPdu,
3952 U8         *fByte
3953 )
3954 #else
3955 PRIVATE Void rgAmmUlHndlStatusPdu(udxPst,suId,gCb, rbCb, cntrlPdu, fByte)
3956 Pst        *udxPst;
3957 SuId       suId;
3958 KwCb       *gCb;
3959 KwDlRbCb   *rbCb;
3960 Buffer     *cntrlPdu;
3961 U8         *fByte;
3962 #endif
3963 {
3964    U8             e1;
3965    KwExtHdr       hdrInfo;
3966    KwUdxStaPdu    *pStaPdu;
3967    U8             e3; /* NACK RANGE : 5GNR */
3968    U32            snLen;
3969    U32            snRange;
3970    U32            resrvdBitsAckSn;
3971    U32            resrvdBitsNackSn;
3972
3973
3974    TRC2(rgAmmUlHndlStatusPdu)
3975
3976    KWDBGP_BRIEF(gCb, "rgAmmUlHndlStatusPdu(rbCb, cntrlPdu, fByte) \n");
3977
3978    KW_MEM_ZERO(&hdrInfo, sizeof(KwExtHdr));
3979
3980    /* Extract the Control PDU */
3981    hdrInfo.hdr  = (*fByte << 1);
3982    hdrInfo.pLen = 4;
3983
3984    /* D/C has been shifted in the calling function */
3985    if (hdrInfo.hdr & 0xE0)
3986    {
3987       KWDBGP_ERROR(gCb, "rgAmmUlHndlStatusPdu: Reserved value for CPT received \n");
3988       RETVOID;
3989    }
3990
3991    KW_ALLOC_SHRABL_BUF(udxPst->region, 
3992                        udxPst->pool, 
3993                        pStaPdu, 
3994                        sizeof(KwUdxStaPdu));
3995
3996 #if (ERRCLASS & ERRCLS_ADD_RES)
3997    /* Memory allocation failure can not be expected  */
3998    if(!pStaPdu)
3999    {
4000      RETVOID;
4001    }
4002 #endif   
4003
4004    if (rbCb->m.amDl.snLen == KW_AM_CFG_12BIT_SN_LEN)
4005    {
4006       snLen = 12;
4007       resrvdBitsAckSn = KW_STA_PDU_R_BITS_ACKSN_12BITS;
4008       resrvdBitsNackSn = KW_STA_PDU_R_BITS_NACKSN_12BITS;
4009    }
4010    else if (rbCb->m.amDl.snLen == KW_AM_CFG_18BIT_SN_LEN)
4011    {
4012       snLen = 18;
4013       resrvdBitsAckSn = KW_STA_PDU_R_BITS_ACKSN_18BITS;
4014       resrvdBitsNackSn = KW_STA_PDU_R_BITS_NACKSN_18BITS;
4015    }
4016    else
4017    {
4018       snLen = KW_SN_LEN;
4019       resrvdBitsAckSn = 0;
4020       resrvdBitsAckSn = 0;
4021    }
4022
4023    pStaPdu->nackCnt = 0;
4024    /* For CPT */
4025    hdrInfo.hdr = hdrInfo.hdr << KW_CPT_LEN;
4026
4027    /* ACK Sn */
4028    hdrInfo.len = KW_SN_LEN;
4029    rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4030    pStaPdu->ackSn = hdrInfo.val;
4031
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);
4037
4038    /* Extract the Reserved Bits after ACK SN field */
4039    hdrInfo.len = resrvdBitsAckSn;
4040    rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4041
4042
4043    /* If NACK exists in control PDU */
4044    /* For ACKs and NACKs */
4045    while (e1 && (pStaPdu->nackCnt < KW_MAX_NACK_CNT))
4046    {
4047       hdrInfo.len = snLen;
4048       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4049       pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
4050
4051       hdrInfo.len = KW_E1_LEN;
4052       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4053       e1 = (U8)hdrInfo.val;
4054
4055       /* Extract e2 */
4056       /* hdrInfo.len = KW_E1_LEN; --> previusly stored value (for e1) is
4057          already present*/
4058       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4059       /*  e2 = (U8) hdrInfo.val;*/
4060
4061       /* Store e2 value */
4062       pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (U8) hdrInfo.val;
4063
4064       /* Extract e3 : 5GNR */
4065       /* hdrInfo.len = KW_E1_LEN; --> previusly stored value (for e1) is
4066          already present*/
4067       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4068       e3 = (U8) hdrInfo.val;
4069
4070       /* Extract Reserved Bits after NACK SN */
4071       hdrInfo.len = resrvdBitsNackSn;
4072       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4073
4074       /* Test for resegmentation */
4075       if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
4076       {
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;
4080
4081          rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4082          pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd   = hdrInfo.val;
4083
4084          KWDBGP_DETAIL(gCb,
4085                        "rgAmmUlHndlStatusPdu: soStart and soEnd = %d %d \n",
4086                        pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
4087                        pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd);
4088       }
4089       else
4090       {
4091          hdrInfo.len = 0;
4092          pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
4093          pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd   = 0;
4094
4095       }
4096       /* NACK RANGE Field is SET */
4097       if (e3)
4098       {
4099          /* Extract NACK range field */
4100          hdrInfo.len = KW_NACK_RANGE_LEN;
4101          rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
4102          snRange = (U8)hdrInfo.val;
4103
4104          pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
4105
4106       }
4107       pStaPdu->nackCnt++;
4108    }
4109
4110    gRlcStats.amRlcStats.numULStaPduRcvd++;
4111    gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
4112
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)
4116    {
4117       pStaPdu->ackSn = (pStaPdu->nackInfo[KW_MAX_NACK_CNT-1].sn + 1) & amDl->snModMask;
4118    }
4119
4120
4121    /* Parse & send Status PDU to RLC-DL */
4122    //KwUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
4123    KwUlUdxStaUpdReq(udxPst, suId, &rbCb->rlcId, pStaPdu);
4124
4125    RETVOID;
4126 }
4127
4128 PUBLIC S16 kwProcDlStatusPdu(Pst *udxPst,SuId suId,
4129       CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu)
4130 {
4131    KwDlRbCb      *rbCb = NULLP;   
4132    KwDlUeCb      *ueCb = NULLP; 
4133    U8        fByte;
4134    U8        temp;
4135    S16       retVal = RFAILED;
4136    KwCb      *gCb;
4137    Pst       dlRlcPst = *udxPst;
4138
4139    gCb = KW_GET_KWCB(1); /* DL RLC instance */
4140
4141    if( ROK != kwDbmFetchDlUeCb(gCb,rnti,cellId,&(ueCb)))
4142    {
4143      printf("\n RLC UECb Not found...\n");
4144      RETVALUE(RFAILED);
4145    }
4146
4147
4148    rbCb = ueCb->lCh[lcId - 1].dlRbCb;
4149
4150    /* Skip if mode is not AM */
4151    if((rbCb ==  NULLP) || (rbCb->mode != CM_LTE_MODE_AM))
4152    {
4153       RETVALUE(RFAILED);
4154    }
4155
4156    if(ROK != SExamMsg((Data *)(&fByte),
4157             rlcSdu, 0))
4158    {
4159       printf("\n Failure in Rlc Hdr SExamMsg\n");
4160       RETVALUE(RFAILED);
4161    }
4162
4163    if(KW_CNTRL_PDU == ((fByte & KW_DC_POS) >> KW_DC_SHT))
4164    {
4165       SRemPreMsg(&temp, rlcSdu);
4166       dlRlcPst.selector = 1;/* LWLC*/
4167       rgAmmUlHndlStatusPdu(&dlRlcPst,suId,gCb, rbCb, rlcSdu, &fByte);
4168       retVal = ROK;
4169    }
4170
4171    RETVALUE(retVal);
4172 }
4173
4174
4175 #endif
4176
4177
4178 /*@}*/
4179
4180 \f  
4181 /********************************************************************30**
4182   
4183          End of file
4184 **********************************************************************/