Building mib PDU and SSB changes at scheduler
[o-du/l2.git] / src / 5gnrsch / rg_sch_drx.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  
21      Name:     LTE-MAC layer
22   
23      Type:     C source file
24   
25      Desc:     C source code for DRX realted functions 
26   
27      File:     rg_sch_drx.c
28   
29 **********************************************************************/
30
31 /** @file rg_sch_drx.c
32 @brief This file implements the DRX processing .
33 */
34
35 static const char* RLOG_MODULE_NAME="MAC";
36 static int RLOG_MODULE_ID=4096;
37 static int RLOG_FILE_ID=163;
38
39 /* header include files -- defines (.h) */
40 #include "envopt.h"        /* environment options */
41 #include "envdep.h"        /* environment dependent */
42 #include "envind.h"        /* environment independent */
43 #include "gen.h"           /* general layer */
44 #include "ssi.h"           /* system service interface */
45 #include "cm_hash.h"       /* common hash list */
46 #include "cm_llist.h"      /* common linked list library */
47 #include "cm_err.h"        /* common error */
48 #include "cm_lte.h"        /* common LTE */
49 #include "lrg.h"
50 #include "rgr.h"
51 #include "rgm.h"
52 #include "tfu.h"
53 #include "rg_env.h"
54 #include "rg_sch_inf.h"
55 #ifdef LTEMAC_PH3_HDFDD
56 #include "rg_sch_hdfdd.h"
57 #endif /*LTEMAC_PH3_HDFDD*/
58 #include "rg_sch.h"
59 #include "rg_sch_err.h"
60 #include "rg_sch_cmn.h"
61 #include "rl_interface.h"
62 #include "rl_common.h"
63
64 /* header/extern include files (.x) */
65 #include "gen.x"           /* general layer typedefs */
66 #include "ssi.x"           /* system services typedefs */
67 #include "cm5.x"           /* common timers */
68 #include "cm_hash.x"       /* common hash list */
69 #include "cm_lib.x"        /* common library */
70 #include "cm_llist.x"      /* common linked list */
71 #include "cm_mblk.x"       /* memory management */
72 #include "cm_tkns.x"       /* common tokens */
73 #include "cm_lte.x"       /* common tokens */
74 #include "tfu.x"           /* TFU types */
75 #include "lrg.x"           /* layer management typedefs for MAC */
76 #include "rgr.x"           /* layer management typedefs for MAC */
77 #include "rgm.x"           /* layer management typedefs for MAC */
78 #include "rg_sch_inf.x"         /* typedefs for Scheduler */
79 #ifdef LTEMAC_PH3_HDFDD
80 #include "rg_sch_hdfdd.x"
81 #endif /*LTEMAC_PH3_HDFDD*/
82
83 #include "rg_sch.x"        /* typedefs for Scheduler */
84 #include "rg_sch_cmn.x"
85
86  /**
87  *  @file rg_sch_drx.c This file gives the describes the design for DRX feature. 
88  *
89  * DRX is Discontinuous Reception i.e. the UE in order to save some battery
90  * would not monitor (decode) PDCCHs at all times. Instead the UE is configured
91  * with a periodically occuring duration wherein it shall monitor PDCCHs. The UE
92  * can be called ACTIVE at this time, this time is a minimum of a configurable
93  * value - onDuration and a maximum of Infinity. 
94  *
95  * ACTIVE time  MIN (onDuration)  MAX (infinity)
96  *
97  * A sample configuration is periodicity of 10 subframes (ms) and an offset
98  * value of 3. This can be represented as the diagram given below. The portion
99  * marked as ACTIVE is the onDuration and the UE monitors PDCCHs. 
100  *
101  * @code
102  *
103  *          <-ACTIVE-><---IN-ACTIVE------><-ACTIVE-><---IN-ACTIVE--
104  * 
105  * |__|__|__|--------|__|__|__|__|__|__|__|--------|__|__|__|__|__|
106  *  0   1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
107  *
108  * @endcode
109  */
110 #ifdef LTE_TDD
111 /******************************************************************************
112  *                         Structure definitions for TDD                      *
113  ******************************************************************************/
114
115 /** @brief : No of DL subframes in a particular TDD configuration
116  *
117  *  @details : Special subframes in TDD can carry PDCCH if configured
118  *             for DwPTS. For normal CP with subframe configruation (0-8)
119  *             & extended CP with subframe configuration (0-6), Special
120  *             Subframes can carry PDCCH and are represented in row 0.
121  *             Extended CP with subframe configuraton (7-8), which do 
122  *             not carry PDCCH are represented in row 1. 
123  *             rgSchDrxDlSfTddCfg[1][2] represent number of DL subframes
124  *             in TDD config 2 where DwPTS can carry PDCCH and 
125  *             rgSchDrxDlSfTddCfg[0][2] represent number of DL subframes
126  *             in TDD config 2 where no DwPTS exits.
127  */
128
129 PRIVATE U8 rgSchDrxDlSfTddCfg[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG] = 
130 {
131    {2,4,6,6,7,8,3},
132    {4,6,8,7,8,9,5}
133 };
134
135 /** @brief : No of DL subframes till next SFN from a particular subframe 
136  *
137  *  @details :For a given Special subframe config
138  *            (refer rgSchDrxDlSfTddCfg for an explanation) and given
139  *            TDD config, how many DL subframes till Next SFN from this
140  *            subframe onwards.
141  *   
142  */
143
144 PRIVATE U8 rgSchDrxDLSfTillNxtSFN[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG]
145                             [RGSCH_NUM_SUB_FRAMES]= 
146 {
147    {
148       {2,1,1,1,1,1,0,0,0,0},
149       {4,3,3,3,3,2,1,1,1,1},
150       {6,5,5,5,4,3,2,2,2,1},
151       {6,5,5,5,5,5,4,3,2,1},
152       {7,6,6,6,6,5,4,3,2,1},
153       {8,7,7,7,6,5,4,3,2,1},
154       {3,2,2,2,2,2,1,1,1,1}
155
156    },
157    { 
158       {4,3,2,2,2,2,1,0,0,0},
159       {6,5,4,4,4,3,2,1,1,1},
160       {8,7,6,6,5,4,3,2,1,1},
161       {7,6,5,5,5,5,4,3,2,1},
162       {8,7,6,6,6,5,4,3,2,1},
163       {9,8,7,7,6,5,4,3,2,1},
164       {5,4,3,3,3,3,2,1,1,1}
165    }
166 }; /*rgSchDrxDLSfTillNxtSFN*/
167
168
169 /** @brief : Lookup table for DL subframe given the number of subframes 
170  *
171  *  @details :For a given Special subframe config
172  *            (refer rgSchDrxDlSfTddCfg for an explanation) and given
173  *            TDD config, the DL subframe index given the number of subframes 
174  *   
175  */
176
177 PRIVATE U8 rgSchDrxDLSftoDLSfIdx[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG]
178                          [RGSCH_NUM_SUB_FRAMES]= 
179 {
180    {
181       {5,0},
182       {9,0,4,5},
183       {9,0,3,4,5,8},
184       {9,0,5,6,7,8},
185       {9,0,4,5,6,7,8},
186       {9,0,3,4,5,6,7,8},
187       {9,0,5}
188    },
189    { 
190       {6,0,1,5},
191       {9,0,1,4,5,6},
192       {9,0,1,3,4,5,6,8},
193       {9,0,1,5,6,7,8},
194       {9,0,1,4,5,6,7,8},
195       {9,0,1,3,4,5,6,7,8},
196       {9,0,1,5,6}
197    }
198 };/* rgSchdrxDLSftoDLSfIdx*/
199 /* ccpu00134196-[Add]-DRX retx timer changes */
200 /* The k+4 th subframe in TDD at which HARQ RTT expires may be an Uplink SF.
201    In such case, the drx retx timer may start at the next pdcch sf instead
202    of at k+4 itself */
203 U8 rgSchDrxHarqRetxFirstPsf[RGSCH_MAX_TDD_CFG][RGSCH_NUM_SUB_FRAMES] = {
204   {0, 0, 4, 0, 6, 0, 0, 4, 0, 6}, 
205   {0, 0, 4, 6, 0, 0, 0, 4, 6, 0}, 
206   {0, 0, 4, 0, 0, 0, 0, 4, 0, 0}, 
207   {0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, 
208   {0, 0, 4, 4, 0, 0, 0, 0, 0, 0}, 
209   {0, 0, 4, 0, 0, 0, 0, 0, 0, 0}, 
210   {0, 0, 4, 6, 5, 0, 0, 4, 7, 0}, 
211 };
212 #endif  /* LTE_TDD */
213
214 /******************************************************************************
215  *                         Start of Function declarations                     *
216  ******************************************************************************/
217 PRIVATE Void rgSCHDrxTtiHdlOnDurUl ARGS((
218 RgSchCellCb        *cell,
219 U16                ulIndex
220 ));
221 PRIVATE Void rgSCHDrxTtiHdlOnDurDl ARGS((
222 RgSchCellCb    *cell,
223 U16                dlIndex
224 ));
225 PRIVATE Void rgSCHDrxTtiHdlDlHarqRTT ARGS((
226 RgSchCellCb          *cell,
227 U16                   dlIndex
228 ));
229 PRIVATE Void rgSCHDrxTtiHdlUlHarqRTT ARGS((
230 RgSchCellCb          *cell,
231 U16                   ulIndex
232 ));
233  PRIVATE S16 rgSCHDrxTtiHdlOnDur ARGS((RgSchCellCb *cellCb, U16 dlIndex, 
234                                         U16 ulIndex));
235  PRIVATE S16 rgSCHDrxTtiHdlInActv ARGS((RgSchCellCb *cellCb, U16 dlIndex,
236                                         U16 ulIndex));
237  PRIVATE S16 rgSCHDrxTtiHdlShortCycle ARGS((RgSchCellCb *cell, U16 dlIndex, 
238                                        U16 ulIndex));
239  PRIVATE S16 rgSCHDrxTtiHdlDlHarq ARGS((RgSchCellCb *cellCb, U16 dlIndex,
240                                        U16 ulIndex));
241  PRIVATE S16 rgSCHDrxCpyUeCfg ARGS((RgSchDrxUeCb *drxCb,
242                                      RgrUeDrxCfg* ueDrxCfg));
243  
244  PRIVATE S16 rgSCHDrxGetNxtOnDur ARGS((RgSchCellCb* cell,RgSchDrxUeCb* drxCb,
245                                        CmLteTimingInfo* nxtOnDur,
246                                        U8 delta));
247  
248 PRIVATE Void rgSCHDrxMvToNxtOnDurOcc ARGS((RgSchCellCb* cell,
249                                            RgSchUeCb* ue,
250                                            U16      idx,
251                                            Bool    calcFrmOffst));
252 #ifdef LTE_TDD
253 PRIVATE Void rgSCHDrxCalcNxtTmrExpry ARGS((RgSchCellCb     *cell,
254                                            RgSchUeCb       *ue,
255                                            U16              delta,
256                                            U32              tmrLen,
257                                            S16             *distance,
258                                            U16             *idx
259                                           ));
260 PRIVATE S16 rgSCHDrxGetNxtTmrExpry ARGS((RgSchCellCb *cell,U16 curTime,
261                                           U32 duration, 
262                                          CmLteTimingInfo* tmrExpryIdx));
263 #endif /* LTE_TDD */
264 #ifdef EMTC_ENABLE
265 EXTERN S16 rgSCHEmtcDrxCpyUeCfg
266 (
267  RgSchUeCb     *ueCb,
268  RgrUeDrxCfg   *drxCfg
269 );
270 EXTERN S16 rgSCHDrxTtiHdlUlHarq 
271 (
272 RgSchCellCb          *cell,
273 U16                   dlIndex,
274 U16                   ulIndex
275 );
276 EXTERN Void rgSCHDrxUeUlHqReset
277 (
278 RgSchCellCb   *cell,
279 RgSchUeCb     *ue,
280 RgUeUlHqCb   *hqE
281 );
282
283 #endif
284
285 /** @brief This function handles the per TTI handling of the DRX module. 
286  *   Invoked by rgSCHTti @sa rgSCHTti. 
287  *
288  * @details This function goes through the drxQ and marks the UE as ACTIVE or
289  * INACTIVE based on the timers and thier status.
290  *
291  *     Function: rgSCHDrxTtiInd 
292  *
293  *         Processing steps:
294  *         - Processing is divided into respective timer handling. 
295  *         - Calculate the DL and UL indices as follows 
296  *         @code
297  *             dlIndex = (cell->crntTime.sfn * 10 + cell->crntTime.slot +
298  *                   RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
299  *
300  *             ulIndex = (cell->crntTime.sfn * 10 + cell->crntTime.slot +
301  *                   RG_SCH_DRX_UL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
302  *         @endcode
303  *         - Call rgSCHDrxTtiHdlOnDur to handle onDurationTimer handling
304  *         - Call rgSCHDrxTtiHdlInActv to handle drx-InactivityTimer handling
305  *         - Call rgSCHDrxTtiHdlShortCycle  to handle Short cycle timer.
306  *         - Call rgSCHDrxTtiHdlDlHarq  to handle HARQ RTT and drx-retransmission
307  *         timers.
308  *         - Call rgSchDrxTtiHdlUlHarq to handle Uplink HARQ processing -
309  *         related to ACTIVITY when a UE is expecting a grant for an uplink
310  *         re-transmissions.
311  *         - Post this processing the ueCb->dlInactvMask's DRX Bit shall be set
312  *         or reset to denote ACTIVITY or INACTIVITY respectively.
313  *         - Post this processing the ueCb->ulInactvMask's DRX Bit shall be set
314  *         or reset to denote ACTIVITY or INACTIVITY respectively.
315  *         - Add the UE to the list of Active/inactive UEs.
316  *
317  * @param RgSchCellCb *cell
318  * @param [out] CmLListCp *dlInactvLst List to which the DL in-active UEs are 
319  *                            added*
320  * @return 
321  */
322 #ifdef ANSI
323 PUBLIC Void rgSCHDrxTtiInd 
324 (
325 RgSchCellCb  *cell
326 )
327 #else
328 PUBLIC Void rgSCHDrxTtiInd (cell)
329 RgSchCellCb  *cell;
330 #endif
331 {
332    U16 dlIndex;
333    U16 ulIndex;
334
335    TRC2(rgSCHDrxTtiInd );
336
337
338    dlIndex = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot +
339          RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
340
341    ulIndex = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot +
342          RG_SCH_DRX_UL_DELTA) % RG_SCH_MAX_DRXQ_SIZE; 
343
344 #ifdef LTEMAC_R9
345    rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex);
346    /* checks the Ul-Retransmission timer */
347 #ifdef EMTC_ENABLE
348    if(cell->emtcEnable)
349    {
350       rgSCHDrxTtiHdlUlHarq (cell, dlIndex, ulIndex);
351    }
352 #endif 
353    rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex);
354    
355    /*Process Short cycle expiry before On duration timer so that long cycles
356     * On Duration can be processed if timer has expired*/
357    rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex);
358    rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex);
359
360 #else /*LTEMAC_R9*/
361    rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex);
362    rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex);
363    /* checks the Ul-Retransmission timer */
364 #ifdef EMTC_ENABLE
365    if(cell->emtcEnable)
366    {
367       rgSCHDrxTtiHdlUlHarq (cell, dlIndex, ulIndex);
368    }
369 #endif
370    rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex);
371    rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex);
372
373 #endif /*LTEMAC_R9*/
374
375    RETVOID;
376
377 }/*rgSCHDrxTtiInd*/
378
379 /** @brief This function is called to handle onDurationTimer per TTI processing.
380  *
381  * @details
382  *    Invoked by - rgSCHDrxTtiInd 
383  *
384  *     Function:  rgSCHDrxTtiHdlOnDur
385  *
386  *         Processing steps:
387  *
388  *           - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
389  *
390  *           - For Downlink we shall look at an index that is 
391  *             n + RG_SCH_DRX_DL_DELTA. 
392  *
393  *
394  *             - For Uplink we shall look at an index that is 
395  *               n + RG_SCH_DRX_UL_DELTA as
396  *             we are concerned with the PDCCH and not the actual PUSCH.
397  *
398  *
399  * @param  RgSchCellCb  *cellCb
400  * @param  U16          dlIndex
401  * @param  U16          ulIndex
402  * @return ROK/RFAILED 
403  */
404
405 #ifdef ANSI
406 PRIVATE S16 rgSCHDrxTtiHdlOnDur
407 (
408 RgSchCellCb*  cell,
409 U16           dlIndex,
410 U16           ulIndex
411 )
412 #else
413 PRIVATE S16 rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex)
414 RgSchCellCb*  cell;
415 U16           dlIndex;
416 U16           ulIndex;
417 #endif
418 {
419
420    TRC2(rgSCHDrxTtiHdlOnDur);
421
422 #if ( ERRCLASS & ERRCLS_INT_PAR )
423    if ( cell == (RgSchCellCb* )NULLP )
424    {
425       RETVALUE(RFAILED);
426    }
427 #endif
428
429    rgSCHDrxTtiHdlOnDurDl(cell,dlIndex);
430   
431    rgSCHDrxTtiHdlOnDurUl(cell, ulIndex);
432
433    RETVALUE(ROK);
434
435 }/*rgSCHDrxTtiHdlOnDur*/
436
437
438 /** @brief This function handles the processing for drxInactityTimer per TTI
439  *
440  * @details
441  * Invoked by - rgSCHDrxTtiInd 
442  *
443  *     Function: rgSCHDrxTtiHdlInActv
444  *
445  *         Processing steps:
446  *
447  *         - For Downlink we shall look at an index that is 
448  *             n + RG_SCH_DRX_DL_DELTA of the drxQ. 
449  *
450  *         - MARK UE AS INACTIVE BASED ON DRX-INACTIVITY TIMER EXPIRY
451  *
452  *
453  *            - For Uplink we shall look at an index that is 
454  *              n + RG_SCH_DRX_UL_DELTA as
455  *             we are concerned with the PDCCH and not the actual PUSCH.
456  *
457  *
458  * @param  RgSchCellCb *cellCb
459  * @param  U16          dlIndex
460  * @param  U16          ulIndex
461  * @return ROK/RFAILED 
462  */
463
464 #ifdef ANSI
465 PUBLIC S16 rgSCHDrxTtiHdlInActv
466 (
467 RgSchCellCb  *cell,
468 U16 dlIndex,
469 U16 ulIndex
470 )
471 #else
472 PUBLIC S16 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex)
473 RgSchCellCb  *cell;
474 U16 dlIndex;
475 U16 ulIndex;
476 #endif
477 {
478    CmLList           *node;
479    RgSchDRXCellCb    *drxCell=NULLP;
480    RgSchUeCb         *ue=NULLP;
481    RgSchDrxUeCb      *drxUe=NULLP;
482    U16                shrtCycleExpIndx;
483    CmLListCp         dlInactvLst; /* list of UE's becoming DL-inactive */
484    CmLListCp         ulInactvLst; /* list of UE's becoming UL-inactive */
485    RgSchCmnCell      *cellSch = NULLP;
486    Bool              delInUlScan = FALSE;
487
488    TRC2(rgSCHDrxTtiHdlInActv);
489
490 #if ( ERRCLASS & ERRCLS_INT_PAR )   
491    if ( cell == (RgSchCellCb* )NULLP) 
492    {
493       RETVALUE(RFAILED);
494    }
495 #endif
496
497
498    drxCell     = (cell->drxCb);
499    delInUlScan = drxCell->delInUlScan;
500   
501   
502    /***********************************************************
503     *    Scanning inActvitiyQ in DL
504     ***********************************************************/
505
506    /* The DL loop will scan for UE's whose inactivity timer has
507     * expired. It will switch the cycle to short or long based
508     * on the cycle configured.
509     * Furhter,if !delInUlScan, then will remove the UE from the
510     * inactivity q. 
511     */
512
513    node = drxCell->drxQ[dlIndex].inActvTmrQ.first;
514
515    /* Initialize DL inactive list */
516    cmLListInit(&dlInactvLst);
517    
518    /* Initialize UL inactive list */
519    cmLListInit(&ulInactvLst);
520    
521    while (node)
522    {
523       ue    = (RgSchUeCb*)node->node;
524       node  = node->next;
525       drxUe = RG_SCH_DRX_GET_UE(ue);
526
527       if ( delInUlScan == TRUE)
528       {
529          drxUe->drxInactDistance--;
530       }
531
532       if ( drxUe->drxInactDistance != DRX_TMR_EXPRD ) 
533       {
534          continue;
535       }
536
537       /* UE is inactive as inactivity timer has expired */
538       drxUe->drxDlInactvMask  |= RG_SCH_DRX_INACTVTMR_BITMASK;
539
540
541       /* update the ue mask only if no condition in drx
542        * is keeping ue active
543        */
544       if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
545       {
546          /* set the UE has DRX inactive */
547          ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
548
549          /* Add to DL inactive list */
550          cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
551          ue->dlDrxInactvLnk.node = (PTR)ue;
552       }
553
554       /*Remove from the queue if !delInUlScan */
555       if( delInUlScan == FALSE )
556       {
557          cmLListDelFrm(&(drxCell->drxQ[dlIndex].inActvTmrQ), 
558                &(drxUe->inActvTmrEnt));
559
560          drxUe->drxInactvIndx = DRX_INVALID;
561
562       }/* if (delInUlScan == FALSE) */
563
564       if (drxUe->isShortCycleCfgd)
565       {
566          /* add shorty cycle expirty */
567          drxUe->isLongCycle = FALSE;
568
569          shrtCycleExpIndx = (dlIndex + (drxUe->shortCycleTmrLen *
570                   drxUe->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
571
572          drxUe->drxShortCycleDistance = (drxUe->shortCycleTmrLen *
573                drxUe->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
574
575          /*Remove the UE from existing index*/
576          if (drxUe->shortCycleIndx != DRX_INVALID)
577          {
578             cmLListDelFrm(&(drxCell->drxQ[drxUe->shortCycleIndx].shortCycleQ),
579                   &(drxUe->shortCycleEnt));
580          }
581
582          cmLListAdd2Tail(&(drxCell->drxQ[shrtCycleExpIndx].shortCycleQ),
583                &(drxUe->shortCycleEnt));
584
585          drxUe->shortCycleEnt.node = (PTR)ue;
586          drxUe->shortCycleIndx     = shrtCycleExpIndx;
587
588          /*Calculate onDuration again & move the
589           * ueCb to the next Onduration occurence
590           */
591
592          /*we maybe at any position in the RF timeline,
593           * need to calculate onDuration from the starting
594           * offset
595           */
596          rgSCHDrxMvToNxtOnDurOcc(cell,ue,RG_SCH_DRX_DL_DELTA,TRUE);
597
598       }/*isShortCycleCfgd */
599       else
600       {
601          /* use the long cycle */
602          drxUe->isLongCycle = TRUE;
603       }/*isLongCycle*/
604    }/*while(node) */
605
606
607
608    /***********************************************************
609     *    Scanning inActvitiyQ in UL
610     ***********************************************************/
611
612    /* The UL loop will scan for UE's whose inactivity timer has
613     * expired and mark the UE's UL inactive.
614     * Furhter,if delInUlScan, then will remove the UE from the
615     * inactivity q. 
616     */
617
618    /* For Uplink we shall look at an index that is n + RG_SCH_DRX_UL_DELTA as
619       we are concerned with the PDCCH and not the actual PUSCH.*/
620
621
622
623    node = drxCell->drxQ[ulIndex].inActvTmrQ.first;
624
625
626    while (node)
627    {
628       ue    = (RgSchUeCb*)node->node;
629       node  = node->next;
630       drxUe = RG_SCH_DRX_GET_UE(ue);
631
632       if ( delInUlScan == FALSE)
633       {
634          drxUe->drxInactDistance--;
635       }
636       
637       if ( drxUe->drxInactDistance != DRX_TMR_EXPRD ) 
638       {
639         continue;
640       }
641
642       /* Need to mark the UE as inactive due to expiry of
643        * DRX inactivity timer */
644
645       /* UE is inactive as inactivity timer has expired */
646       drxUe->drxUlInactvMask  |= RG_SCH_DRX_INACTVTMR_BITMASK;
647
648       /* update the ue mask only if no other condition in
649        * drx is keeping ue active */
650
651       if (!RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
652       {
653          /* set the inactivity bit */
654          ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
655
656          /* Add to Ul inactive list */
657          cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
658          ue->ulDrxInactvLnk.node = (PTR)ue;
659       }
660
661       if ( delInUlScan == TRUE)
662       {
663          /* remove from queue */
664          cmLListDelFrm(&(drxCell->drxQ[ulIndex].inActvTmrQ), 
665                &(drxUe->inActvTmrEnt));
666
667          drxUe->drxInactvIndx = DRX_INVALID;
668          
669       }/* if ( delInUlScan == TRUE) */
670    }/*while(node) for uplink */
671
672    
673    /* Send the list to the scheduler to mark UE as inactive in UL*/
674     cellSch = RG_SCH_CMN_GET_CELL(cell);
675     cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
676    
677    /* Send the DL inactive list to the scheduler to mark UE as inactive */
678    cellSch = RG_SCH_CMN_GET_CELL(cell);
679    cellSch->apisDl->rgSCHDlInactvtUes(cell,&dlInactvLst);
680
681       RETVALUE(ROK);
682 }/*rgSCHDrxTtiHdlInActv*/
683
684  /** @brief This function handles the per TTI processing for DRX short cycle
685   * timer.
686   *
687   * @details
688   * Invoked by - rgSCHDrxTtiInd 
689   *
690   *     Function: rgSCHDrxTtiHdlShortCycle
691   *
692   *         Processing steps:
693   *         -  For downlink
694   *
695  *             in addition we have to mark the ues based on drx short cycle
696  *             expiry
697  *
698  *
699  * @param  RgSchCellCb    *cell
700  * @param  U16          dlIndex
701  * @param  U16          ulIndex
702  * @return ROK/RFAILED 
703  */
704
705 #ifdef ANSI
706 PUBLIC S16 rgSCHDrxTtiHdlShortCycle 
707 (
708 RgSchCellCb  *cell,
709 U16           dlIndex,
710 U16           ulIndex
711 )
712 #else
713 PUBLIC S16 rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex)
714 RgSchCellCb  *cell;
715 U16           dlIndex;
716 U16           ulIndex;
717 #endif
718 {
719    CmLList           *node;
720    RgSchDRXCellCb    *drxCell=NULLP;
721    RgSchUeCb         *ue=NULLP;
722    RgSchDrxUeCb      *drxUe=NULLP;
723
724    TRC2(rgSCHDrxTtiHdlShortCycle );
725
726 #if ( ERRCLASS & ERRCLS_INT_PAR )
727    if ( cell == (RgSchCellCb* )NULLP )
728    {
729       RETVALUE(RFAILED);
730    }
731 #endif
732
733    UNUSED(ulIndex);
734
735
736    drxCell = RG_SCH_DRX_GET_CELL(cell);
737
738    node = drxCell->drxQ[dlIndex].shortCycleQ.first;
739
740    while (node)
741    {
742       ue    = (RgSchUeCb*)node->node;
743       node  = node->next;
744       drxUe = RG_SCH_DRX_GET_UE(ue);
745
746       if ( --drxUe->drxShortCycleDistance != DRX_TMR_EXPRD)
747       {
748          continue;
749       }
750       
751       /* mark the UE's current cycle to be long */
752       drxUe->isLongCycle = TRUE;
753
754       /* remove from the shortCycleQ */
755
756       cmLListDelFrm(&(drxCell->drxQ[dlIndex].shortCycleQ), 
757             &(drxUe->shortCycleEnt));
758       drxUe->shortCycleIndx = DRX_INVALID;
759
760       /* Remove from onDuration queue inserted based on short cycle
761        * and calculate onDuration based on long cycle.*/
762       rgSCHDrxMvToNxtOnDurOcc(cell,ue,RG_SCH_DRX_DL_DELTA,TRUE);
763    }/*while(node)...*/
764
765    RETVALUE(ROK);
766 }/*rgSCHDrxTtiHdlShortCycle*/
767
768
769  /** @brief This function handles the HARQ timer's processing per TTI.
770   *
771   * @details
772   * Invoked by - rgSCHDrxTtiInd 
773   *
774   *     Function: rgSCHDrxTtiHdlDlHarq 
775   *
776   *         Processing steps:
777   *         - In addition per TTI DRX module must look at Downlink HARQ queues
778  *             maintained to track HARQ RTT timer and drx-RetransmissionTimer.
779  *             Every TTI at the scheduling index we shall check these queues and
780  *             process accordingly. 
781  *
782  *
783  *             - Though these timers are related to downlink HARQ processing, they
784  *             have an impact on uplink scheduling. The reason is that the UE,
785  *             if active for downlink scheduling implies that it is reading
786  *             PDCCHs i.e. we can still send uplink allocations to the UE. Hence
787  *             every TTI Uplink too would look at the harqRTTQ and harqRetxQ. 
788  *
789  *
790  *
791  * @param  RgSchCellCb *cellCb
792  * @param  U16          dlIndex
793  * @param  U16          ulIndex
794   * @return ROK/RFAILED 
795   */
796
797 #ifdef ANSI
798 PRIVATE S16 rgSCHDrxTtiHdlDlHarq 
799 (
800 RgSchCellCb          *cell,
801 U16                   dlIndex,
802 U16                   ulIndex
803 )
804 #else /* ANSI */
805 PRIVATE S16 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex)
806 RgSchCellCb          *cell;
807 U16                   dlIndex;
808 U16                   ulIndex;
809 #endif /* ANSI */
810 {
811
812 #if ( ERRCLASS & ERRCLS_INT_PAR)
813    if ( cell == (RgSchCellCb *)NULLP )
814    {
815       RETVALUE(RFAILED);
816    }
817 #endif /*ERRCLASS & ERRCLS_INT_PAR*/
818
819
820    TRC2(rgSCHDrxTtiHdlDlHarq );
821    
822    rgSCHDrxTtiHdlDlHarqRTT(cell, dlIndex);
823
824    rgSCHDrxTtiHdlUlHarqRTT(cell, ulIndex);
825
826    RETVALUE(ROK);
827 }
828
829  /** @brief This function is called by the common scheduler as part of
830   * finalization of allocations in downlink.
831   *
832   * @details
833   * Invoked by - 
834   *
835   *     Function: rgSchDrxStrtInActvTmr
836   *     
837   *     This function is responsible to starting drx-InactivityTimer 
838   *
839   *         Processing steps:
840   *
841   *
842   * @param  RgSchCellCb *cell
843   * @param  CmLListCp   *ueUlLst
844   * @param  U8           direction 
845   * @return Void 
846   */
847
848 #ifdef ANSI
849 PUBLIC Void rgSCHDrxStrtInActvTmr
850 (
851 RgSchCellCb  *cell,
852 CmLListCp    *ueLst,
853 U8            direction
854 )
855 #else
856 PUBLIC Void rgSCHDrxStrtInActvTmr(cell, ueLst, direction)
857 RgSchCellCb  *cell;
858 CmLListCp    *ueLst;
859 U8            direction;
860 #endif
861 {
862    CmLList         *node;
863    CmLList         *delNode;
864    RgSchUeCb       *ueCb;
865    RgSchDrxUeCb    *ueDrxCb;
866 #ifndef LTE_TDD
867    U16             index1;
868 #endif
869    U16             inActvTmrExpIndx;
870 #ifndef LTE_TDD
871    U16             curTimeInSf; /* current time in number of subframes */
872 #endif
873 #ifdef LTE_TDD
874    U16             delta;
875 #endif /*LTE_TDD*/
876    CmLListCp         dlInactvLst; /* list of UE's becoming DL-inactive */
877    CmLListCp         ulInactvLst; /* list of UE's becoming UL-inactive */
878    RgSchCmnCell      *cellSch = NULLP;
879    Bool              delInUlScan = FALSE;
880
881
882    TRC2(rgSCHDrxStrtInActvTmr);
883
884
885    if ( direction == RG_SCH_DRX_UL)
886    {
887 #ifndef LTE_TDD
888       curTimeInSf = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
889          (cell->crntTime.slot) +RG_SCH_DRX_UL_DELTA;
890 #endif
891
892 #ifdef LTE_TDD
893       delta = RG_SCH_DRX_UL_DELTA;
894 #endif /*LTE_TDD */
895    }
896    else
897    {
898 #ifndef LTE_TDD
899       curTimeInSf = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
900          (cell->crntTime.slot) + RG_SCH_DRX_DL_DELTA; 
901 #endif
902
903 #ifdef LTE_TDD
904       delta = RG_SCH_DRX_DL_DELTA;
905 #endif /*LTE_TDD */
906    }
907
908
909    /* Initialize DL inactive list */
910    cmLListInit(&dlInactvLst);
911
912    /* Initialize UL inactive list */
913    cmLListInit(&ulInactvLst);
914    
915    delInUlScan = cell->drxCb->delInUlScan; 
916
917 #ifndef LTE_TDD
918    index1 = (curTimeInSf) % RG_SCH_MAX_DRXQ_SIZE;
919 #endif
920
921    node = ueLst->first;
922
923    while(node)
924    {
925       ueCb    = (RgSchUeCb *)node->node;
926       ueDrxCb = ueCb->drxCb;
927
928       /* Stop inactivity timer */
929       if ( ueDrxCb->drxInactvIndx != DRX_INVALID )
930       {
931          cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->drxInactvIndx].inActvTmrQ),
932                &(ueDrxCb->inActvTmrEnt));
933       }
934 #ifdef LTE_TDD
935
936       rgSCHDrxCalcNxtTmrExpry(cell,
937             ueCb,
938             delta,
939             ueDrxCb->inactvtyTmrLen,
940             &(ueDrxCb->drxInactDistance),
941             &inActvTmrExpIndx
942             );
943
944 #else /*LTE_TDD*/
945       inActvTmrExpIndx = (index1 + ueDrxCb->inactvtyTmrLen) 
946          % RG_SCH_MAX_DRXQ_SIZE;
947
948       ueDrxCb->drxInactDistance = ueDrxCb->inactvtyTmrLen 
949          / RG_SCH_MAX_DRXQ_SIZE;
950 #endif /*LTE_TDD*/
951
952       cmLListAdd2Tail(&(cell->drxCb->drxQ[inActvTmrExpIndx].inActvTmrQ),
953             &(ueDrxCb->inActvTmrEnt));
954
955       ueDrxCb->inActvTmrEnt.node = (PTR)ueCb;
956
957       ueDrxCb->drxInactvIndx     = inActvTmrExpIndx;
958
959       /* Update DRX InActive both masks */
960       ueDrxCb->drxUlInactvMask &= ~RG_SCH_DRX_INACTVTMR_BITMASK;
961       ueDrxCb->drxDlInactvMask &= ~RG_SCH_DRX_INACTVTMR_BITMASK;
962
963       /* Update UE's Inactive masks */
964       ueCb->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
965       ueCb->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
966
967       if ( delInUlScan == TRUE) 
968       {
969          if ( ueDrxCb->inactvtyTmrLen == RGR_DRX_PRD_1PSF)
970          {
971             ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
972             ueDrxCb->drxDlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
973
974             /* if no other condition is keeping ue inactive,
975              * inactivate ue 
976              */
977             if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(ueDrxCb) )
978             {
979                ueCb->dl.dlInactvMask |= RG_DRX_INACTIVE;
980
981                /* Add to DL inactive list */
982                cmLListAdd2Tail(&dlInactvLst,&(ueCb->dlDrxInactvLnk));
983                ueCb->dlDrxInactvLnk.node = (PTR)ueCb;
984             }
985          }/*if ( ueDrxCb->inactvyTmrLen...*/
986
987       }/*delInUlScan==TRUE*/
988       else
989       {
990          if ( ueDrxCb->inactvtyTmrLen == RGR_DRX_PRD_1PSF ) 
991          {
992             ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
993             ueDrxCb->drxUlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
994             /* if no other condition is keeping ue inactive,
995              * inactivate ue 
996              */
997             if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(ueDrxCb) )
998             {
999                ueCb->ul.ulInactvMask |= RG_DRX_INACTIVE;
1000
1001                if ( !RG_SCH_CMN_UL_IS_UE_ACTIVE(ueCb))
1002                {
1003                   /* Add to UL inactive list */
1004                   cmLListAdd2Tail(&ulInactvLst,&(ueCb->ulDrxInactvLnk));
1005                   ueCb->ulDrxInactvLnk.node = (PTR)ueCb;
1006                }
1007             }/*if ( !RG_SCH_DRX....)*/
1008          }/*if (ueDrxCb->inactv...*/
1009       }
1010
1011       /* move the link list forward */
1012       delNode = node;
1013       node = node->next;
1014
1015       cmLListDelFrm(ueLst, delNode);
1016       delNode->node = NULLP;
1017
1018    }/*node*/
1019
1020    /* Send the list to the scheduler to mark UE as inactive in UL*/
1021    cellSch = RG_SCH_CMN_GET_CELL(cell);
1022    cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
1023
1024    /* Send the DL inactive list to the scheduler to mark UE as inactive */
1025    cellSch = RG_SCH_CMN_GET_CELL(cell);
1026    cellSch->apisDl->rgSCHDlInactvtUes(cell,&dlInactvLst);
1027
1028    RETVOID; 
1029 }/*rgSCHDrxStrtInActvTmr*/
1030
1031  /** @brief This function is called by the downlink HARQ module on receiving a
1032   * negative feedback from the UE for a PDSCH transmission. 
1033   *
1034   * @details
1035   * Invoked by - rgSCHDhmHqTrnsFail
1036   *
1037   *     Function: rgSCHDrxStartHarqRTTTmr
1038   *
1039   *         Processing steps:
1040  *
1041   *
1042   * @param  RgSchCellCb       *cell
1043   * @param  RgSchDlHqProcCb   *dlHq
1044   * @param  U8                tbCnt
1045   * @return Void 
1046   */
1047 #ifdef ANSI
1048 PUBLIC Void rgSCHDrxStartHarqRTTTmr
1049 (
1050 RgSchCellCb            *cell,
1051 RgSchDlHqProcCb        *hqP,
1052 U8                     tbCnt
1053 )
1054 #else
1055 PUBLIC Void rgSCHDrxStartHarqRTTTmr(cell, hqP, tbCnt)
1056 RgSchCellCb             *cell;
1057 RgSchDlHqProcCb         *hqP;
1058 U8                      tbCnt;
1059 #endif
1060 {
1061    RgSchDRXCellCb      *drxCell =NULLP;
1062    RgSchDrxDlHqProcCb  *drxHq   =NULLP;
1063    U16                  harqRTTExpIndx;
1064    U8                   fdbkDelta;
1065 #ifdef LTE_TDD   
1066    U8                   firstDlTxOcassion;
1067    U8                   drxRetxTmrStartSf;
1068 #endif    
1069    TRC2(rgSCHDrxStartHarqRTTTmr);
1070
1071
1072    drxCell = RG_SCH_DRX_GET_CELL(cell);
1073    drxHq   = RG_SCH_DRX_GET_DL_HQ(hqP);
1074
1075 #ifdef LTE_TDD
1076     /* ccpu00134196-[Add]-DRX retx timer changes */
1077    firstDlTxOcassion = rgSchDrxHarqRetxFirstPsf[cell->ulDlCfgIdx]
1078                            [hqP->tbInfo[tbCnt].fdbkTime.subframe];
1079                             
1080    harqRTTExpIndx = ((hqP->tbInfo[tbCnt].fdbkTime.sfn * 10) +
1081          hqP->tbInfo[tbCnt].fdbkTime.subframe + firstDlTxOcassion)
1082       % RG_SCH_MAX_DRXQ_SIZE;
1083
1084    fdbkDelta = RGSCH_CALC_SF_DIFF(cell->crntTime,  hqP->tbInfo[tbCnt].fdbkTime);
1085 #else /*LTE_TDD*/
1086
1087    /* For FDD HARQ RTT expiry index is 8 subframes from the time 
1088     * corresponding PDSCH was scheduled. We are adding 1 subframe 
1089     * so that UE is scheduled for retransmission in the next subframe*/
1090    /* ccpu00134196-[Add]-DRX retx timer changes */
1091    harqRTTExpIndx = ((hqP->tbInfo[tbCnt].timingInfo.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1092          hqP->tbInfo[tbCnt].timingInfo.slot + RG_SCH_MIN_HARQ_RTT)
1093       % RG_SCH_MAX_DRXQ_SIZE;
1094
1095    fdbkDelta = RGSCH_CALC_SF_DIFF(cell->crntTime,  hqP->tbInfo[tbCnt].timingInfo);
1096 #endif /*LTE_TDD*/
1097    /* ccpu00134196-[Add]-DRX retx timer changes */ 
1098    /* ensure that the insertion into the queue happens at an index
1099       greater than the dl index, ie, do +1 */
1100    /* Instead of depending on TTI details of current time and HARQ RTT Expire 
1101     * time, Handling this check with deltas, because with TTIs it is not possible
1102     * to handle wrap-around condition*/
1103 #ifdef LTE_TDD
1104    if(fdbkDelta + RG_SCH_DRX_DL_DELTA >= firstDlTxOcassion)
1105    {
1106       /* The retx timer length should be reduced.  
1107          This means based on the platforms delta between the DL HARQ 
1108          processing and DL scheduling, drx retx timer lengths of 1ms/2ms 
1109          may not be possible */ 
1110       drxRetxTmrStartSf = (hqP->tbInfo[tbCnt].fdbkTime.subframe + 
1111                                  firstDlTxOcassion) % RGSCH_NUM_SUB_FRAMES;
1112       U8 i;
1113       /* We are here because the Retx Timer start is moved by atleast one 
1114          position. Hence the timer will be reduced by minimum one */ 
1115       drxHq->retxTmrReduction = 1;
1116
1117       /* Now check the consecutive subframes starting from the actual 
1118          starting position of the retx tmr till the new position. Reduce the
1119          timer value only if the sf is a Pdcch sf */
1120       for(i = 1; i <= fdbkDelta + RG_SCH_DRX_DL_DELTA-firstDlTxOcassion+ 1; i++)
1121       {
1122          if (rgSchTddUlDlSubfrmTbl[cell->ulDlCfgIdx]
1123                     [(drxRetxTmrStartSf+i)%RGSCH_NUM_SUB_FRAMES] 
1124                   != RG_SCH_TDD_UL_SUBFRAME)
1125           {
1126              drxHq->retxTmrReduction++;
1127           }
1128       }
1129 #else                  
1130    if(fdbkDelta + RG_SCH_DRX_DL_DELTA >= RG_SCH_MIN_HARQ_RTT)
1131    {
1132       drxHq->retxTmrReduction = 
1133          fdbkDelta + RG_SCH_DRX_DL_DELTA - RG_SCH_MIN_HARQ_RTT+ 1;
1134 #endif      
1135       /* KW_FIX */
1136       harqRTTExpIndx = (harqRTTExpIndx + drxHq->retxTmrReduction) % 
1137          RG_SCH_MAX_DRXQ_SIZE;
1138    }
1139    else
1140    {
1141       drxHq->retxTmrReduction = 0;
1142    }
1143    cmLListAdd2Tail (&(drxCell->drxQ[harqRTTExpIndx].harqRTTQ),
1144          &(drxHq->harqRTTEnt));
1145
1146    drxHq->harqRTTEnt.node = (PTR)hqP;
1147    drxHq->rttIndx         = harqRTTExpIndx;
1148
1149    RETVOID;
1150
1151 }/*rgSCHDrxStartHarqRTTTmr*/
1152
1153
1154 /** @brief This function is called by the Configuration module to give a
1155  * trigger to DRX module for UE configuration. 
1156  *
1157  * @details
1158  *
1159  *     Function: rgSCHDrxUeCfg 
1160  *
1161  *         Processing steps:
1162  *         - Copy configuration information into drxUe structure.
1163  *         - Calculate the first occurance of onDuration based on values
1164  *         provided in the configuration structure. 
1165  *         - Append the UE to the onDurationQ at that index. 
1166  *         - The UE must be appened to the list based on the timing calculated
1167  *         above (nxtSfn, nxtSubframe). 
1168  *
1169  * @param  RgSchCellCb  *cell Cell control block.
1170  * @param  RgSchUeCb    *ue   UE control block.
1171  * @param  RgrUeCfg     *ueCfg RGR UE configuration information.
1172  * @return 
1173  * -# ROK
1174  * -# RFAILED
1175  */
1176 #ifdef ANSI
1177 PUBLIC S16 rgSCHDrxUeCfg 
1178 (
1179  RgSchCellCb *cell,
1180  RgSchUeCb   *ue,
1181  RgrUeCfg    *ueCfg
1182  )
1183 #else
1184 PUBLIC S16 rgSCHDrxUeCfg (cell, ue, ueCfg)
1185  RgSchCellCb *cell;
1186  RgSchUeCb   *ue;
1187  RgrUeCfg    *ueCfg;
1188 #endif
1189 {
1190    S16               ret       = ROK;
1191    RgSchDrxUeCb      *ueDrxCb;
1192    CmLteTimingInfo   nxtOnDur;
1193    U16               onDurIndx;
1194    U16               nxtOnDurTime;
1195    U16               curTime;
1196    U8                cellIdx;
1197
1198
1199    TRC2(rgSCHDrxUeCfg);
1200
1201
1202 #if ( ERRCLASS & ERRCLS_INT_PAR )   
1203    if ( cell == (RgSchCellCb* )NULLP) 
1204    {
1205       RETVALUE(RFAILED);
1206    }
1207
1208    if ((ue == (RgSchUeCb* )NULLP)
1209          ||
1210          (ueCfg == (RgrUeCfg* )NULLP))
1211    {
1212       RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId, "rgSCHDrxUeCfg():"
1213                "Invalid params.cell or ue or ueCfg is NULL ");
1214       RETVALUE(RFAILED);
1215    }
1216 #endif
1217
1218
1219    /* allocate and initialize drxCb */
1220    ret = rgSCHUtlAllocSBuf(cell->instIdx, (Data**)&ue->drxCb, 
1221          (sizeof(RgSchDrxUeCb)));
1222
1223    if(ret != ROK)
1224    {
1225       RLOG_ARG1(L_ERROR,DBG_CELLID,cell->cellId,
1226                "Memory allocation FAILED for DRX UECB CRBTI:%d",ue->ueId);
1227       RETVALUE(ret);
1228    }
1229
1230    ueDrxCb = ue->drxCb;
1231
1232    /* initialize the masks */
1233    ueDrxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1234    ueDrxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1235    ue->dl.dlInactvMask     |= RG_DRX_INACTIVE;
1236    ue->ul.ulInactvMask     |= RG_DRX_INACTIVE;
1237
1238    for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1239    {
1240       ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1241       ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1242    }   
1243
1244    /* Copy the configuration values into the UE's DRX CB. */
1245    rgSCHDrxCpyUeCfg (ueDrxCb, &ueCfg->ueDrxCfg);
1246 #ifdef EMTC_ENABLE
1247    if(ue->isEmtcUe)
1248    {
1249       rgSCHEmtcDrxCpyUeCfg(ue ,&ueCfg->ueDrxCfg);
1250    }
1251 #endif
1252
1253    /* set all indexes to default values */
1254    ueDrxCb->onDurIndx       = DRX_INVALID;
1255    ueDrxCb->onDurExpIndx    = DRX_INVALID;
1256    ueDrxCb->drxInactvIndx   = DRX_INVALID;
1257    ueDrxCb->shortCycleIndx  = DRX_INVALID;
1258
1259    /* set all distances to timer expiry */
1260    ueDrxCb->onDurExpDistance      = DRX_TMR_EXPRD;
1261    ueDrxCb->drxInactDistance      = DRX_TMR_EXPRD;
1262    ueDrxCb->drxShortCycleDistance = DRX_TMR_EXPRD;
1263    ueDrxCb->distance              = DRX_TMR_EXPRD;
1264
1265    /* Mark the UE in long/short  cycle initially  as per configuration*/
1266    if(FALSE == ueDrxCb->isShortCycleCfgd)
1267    {
1268       ueDrxCb->isLongCycle = TRUE;
1269    }
1270    else
1271    {
1272       ueDrxCb->isLongCycle = FALSE;
1273    }
1274
1275    /* Calculate the next occurance from this point */
1276    rgSCHDrxGetNxtOnDur (cell, ueDrxCb, &nxtOnDur,RG_SCH_NO_DELTA);
1277
1278
1279    nxtOnDurTime = ((nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur.slot);
1280    curTime      = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1281                      cell->crntTime.slot);
1282
1283    onDurIndx         = nxtOnDurTime % RG_SCH_MAX_DRXQ_SIZE;
1284    
1285    ueDrxCb->distance = (nxtOnDurTime - curTime) / RG_SCH_MAX_DRXQ_SIZE;
1286    if (ueDrxCb->distance < 0)
1287    {
1288       RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId, "DRXUE. Invalid "
1289          "value for distance, %d CRNTI:%d", ueDrxCb->distance,ue->ueId);
1290    }
1291    //printf("The onduartion index is: %d\n",(int)onDurIndx);
1292    cmLListAdd2Tail(&(cell->drxCb->drxQ[onDurIndx].onDurationQ), 
1293          &(ueDrxCb->onDurationEnt));
1294
1295    ueDrxCb->onDurationEnt.node = (PTR)ue;
1296    ueDrxCb->onDurIndx          = onDurIndx;
1297
1298    /* Starting Short Cycle Timer */
1299    if(TRUE == ueDrxCb->isShortCycleCfgd)
1300    {
1301       ueDrxCb->drxShortCycleDistance = (ueDrxCb->shortCycleTmrLen *
1302                ueDrxCb->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
1303       ueDrxCb->shortCycleIndx  = (curTime + (ueDrxCb->shortCycleTmrLen *
1304                ueDrxCb->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE; 
1305       cmLListAdd2Tail(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1306                &(ueDrxCb->shortCycleEnt));
1307       ueDrxCb->shortCycleEnt.node = (PTR)ue;
1308    }
1309
1310    RETVALUE(ret);
1311 } /* end of rgSCHDrxUeCfg */
1312
1313 /** @brief This function gets the next occurance of onDurationTimer from the
1314  * current time. 
1315  *
1316  * @details rgSCHDrxGetNxtOnDur
1317  *
1318  *     Function: rgSCHDrxGetNxtOnDur
1319  *
1320  *         Processing steps: -
1321  *         Calculation of first occurance of onDuration is to be done as
1322  *         follows. 
1323  *         Assume DRX configuration came at subframe (x, y) the periodicity is
1324  *         offset = (perd, offset). 
1325  *         The (sfn, subframe) satisfying the following condition is the first
1326  *         occurance from this point. 
1327  *
1328  *         (sfn * 10  + subframe) mod perd = offset 
1329  *
1330           - 
1331  *
1332  *
1333  * @param  RgSchCellCb     *cell
1334  * @param  RgSchDrxUeCb    *drxCb
1335  * @param  CmLteTimingInfo *nxtOnDur
1336  * @param  U8              delta
1337  * @return ROK/RFAILED 
1338  */
1339 #ifdef ANSI
1340 PRIVATE S16 rgSCHDrxGetNxtOnDur
1341 (
1342  RgSchCellCb         *cell,
1343  RgSchDrxUeCb        *drxCb,
1344  CmLteTimingInfo     *nxtOnDur,
1345  U8                   delta
1346  )
1347 #else
1348 PRIVATE S16 rgSCHDrxGetNxtOnDur (cell, drxCb, nxtOnDur, delta)
1349  RgSchCellCb         *cell;
1350  RgSchDrxUeCb        *drxCb;
1351  CmLteTimingInfo     *nxtOnDur;
1352  U8                   delta;
1353 #endif
1354 {
1355    U16               curTime;
1356    U16               curDist;
1357    U16               cycleLen;
1358    U32               numOfCycles;
1359    U32               nxtDist;
1360
1361    TRC3(rgSCHDrxGetNxtOnDur);
1362
1363 #if ( ERRCLASS & ERRCLS_INT_PAR ) 
1364    if ( cell == (RgSchCellCb* )NULLP ) 
1365    {
1366       RETVALUE(RFAILED);
1367    }
1368
1369    if( (drxCb == (RgSchDrxUeCb* )NULLP)
1370            ||
1371        (nxtOnDur == (CmLteTimingInfo* )NULLP)
1372       )
1373    {
1374       RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
1375                         "rgSCHDrxGetNxOnDur():Invalid params."
1376                         "cell/drxCb/nxtOnDur is NULL");
1377       RETVALUE(RFAILED);
1378    }
1379 #endif
1380
1381    
1382    if (TRUE == drxCb->isLongCycle)
1383    {
1384       cycleLen = drxCb->longDrxCycle;
1385    }
1386    else
1387    {
1388       cycleLen = drxCb->shortDrxCycle;
1389    }
1390
1391    curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) + cell->crntTime.slot); 
1392
1393    curTime  += delta;  /*TODO: see if we need to take care of wrap arounds */
1394
1395    if ( curTime <= drxCb->drxStartOffset )
1396    {
1397       /* offset is the nextOnDur */
1398       nxtOnDur->sfn = drxCb->drxStartOffset / RGSCH_NUM_SUB_FRAMES_5G;
1399       nxtOnDur->slot = (U8)(drxCb->drxStartOffset % RGSCH_NUM_SUB_FRAMES_5G);
1400       nxtDist = ((nxtOnDur->sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur->slot); 
1401    }
1402    else
1403    {
1404       curDist = curTime - drxCb->drxStartOffset;
1405       
1406       numOfCycles = curDist / cycleLen;
1407
1408       if (0 == (curDist % cycleLen))
1409       {
1410          /* Perfect match pick up the current time */
1411          /*nxtOnDur should be set to equal to currentTime + DELTA */
1412          nxtOnDur->sfn      = (U16)curTime / RGSCH_NUM_SUB_FRAMES_5G;
1413          nxtOnDur->slot = (U16)curTime % RGSCH_NUM_SUB_FRAMES_5G;
1414          nxtDist = ((nxtOnDur->sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur->slot); 
1415
1416       }
1417       else
1418       {
1419          nxtDist            = drxCb->drxStartOffset + (numOfCycles + 1) * 
1420                               cycleLen;
1421          nxtOnDur->sfn      = (U16)nxtDist / RGSCH_NUM_SUB_FRAMES_5G;
1422          nxtOnDur->slot = (U16)nxtDist % RGSCH_NUM_SUB_FRAMES_5G;
1423
1424       }
1425    }
1426
1427    /*If next On Duration is less than DL DELTA ahead, we will miss it and
1428     * hence need to move to the On-Duration after that.*/
1429    if((nxtDist - (curTime - delta)) <= RG_SCH_DRX_MAX_DELTA)
1430    {
1431       nxtDist = nxtDist + cycleLen;
1432       nxtOnDur->sfn      = (U16)nxtDist / RGSCH_NUM_SUB_FRAMES_5G;
1433       nxtOnDur->slot = (U16)nxtDist % RGSCH_NUM_SUB_FRAMES_5G;
1434    }
1435    RETVALUE(ROK);
1436 } /* end of rgSCHDrxGetNxtOnDur */ 
1437
1438 /** @brief This function is a utility function to copy the UE configuration from
1439  * the RGR structure to the UE control block. 
1440  *
1441  * @details
1442  *   -Invoked by rgSCHDrxUeCfg
1443  *
1444  *     Function: rgSCHDrxCpyUeCfg
1445  *
1446  *         Processing steps:
1447  *         - Copies configuration values
1448  *
1449  * @param  RgSchDrxUeCb *ueCb
1450  * @param  RgrUeDrxCfg  *drxCfg
1451  * @return ROK/RFAILED 
1452  */
1453 #ifdef ANSI
1454 PRIVATE S16 rgSCHDrxCpyUeCfg
1455 (
1456  RgSchDrxUeCb  *ueCb,
1457  RgrUeDrxCfg   *drxCfg
1458 )
1459 #else
1460 PRIVATE S16 rgSCHDrxCpyUeCfg (ueCb, drxCfg)
1461  RgSchDrxUeCb  *ueCb;
1462  RgrUeDrxCfg   *drxCfg;
1463 #endif
1464 {
1465    TRC3(rgSCHDrxCpyUeCfg);
1466
1467 #if ( ERRCLASS & ERRCLS_INT_PAR ) 
1468    if ( (ueCb == (RgSchDrxUeCb* )NULLP ) 
1469            ||
1470         (drxCfg == (RgrUeDrxCfg* )NULLP)
1471       )
1472    {
1473       RETVALUE(RFAILED);
1474    }
1475 #endif
1476
1477       
1478    /* Copy all values to UE control block */
1479 #ifdef LTEMAC_R9
1480    ueCb->cqiMask              = drxCfg->cqiMask;
1481 #endif /*LTEMAC_R9*/
1482    ueCb->onDurTmrLen          = drxCfg->drxOnDurTmr;
1483    ueCb->inactvtyTmrLen       = drxCfg->drxInactvTmr;
1484    ueCb->drxRetransTmrLen     = drxCfg->drxRetxTmr;
1485    ueCb->longDrxCycle         = drxCfg->drxLongCycleOffst.longDrxCycle;
1486    ueCb->drxStartOffset       = drxCfg->drxLongCycleOffst.drxStartOffst;
1487    ueCb->isShortCycleCfgd     = drxCfg->drxShortDrx.pres;
1488    ueCb->shortDrxCycle        = drxCfg->drxShortDrx.shortDrxCycle;
1489    ueCb->shortCycleTmrLen     = drxCfg->drxShortDrx.drxShortCycleTmr;
1490    
1491    RETVALUE(ROK);
1492 } /* end of rgSCHDrxCpyUeCfg */ 
1493
1494 #ifdef RGR_V2
1495 /** @brief This function is called by the configuration module when a UE is
1496  * reconfigured for DRX parameters. 
1497  *
1498  * @details
1499  * Invoked By - rgSCHCfgRgrUeCfg
1500  *
1501  * Function: rgSCHDrxUeReCfg 
1502  * As per MAC specifications the new values of timers shall be applied only once
1503  * they are restarted, hence no processing is required for modified timer values. 
1504  *
1505  *         Processing steps:
1506  *         - if offset and/or drxCycleLenght changes then recalculate the next
1507  *         onDurationIndex
1508  *          - remove the UE from current index
1509  *          - add the UE to the new index. 
1510  *         - if short cycle is enabled 
1511  *          - set isShortCycleCfgd = TRUE
1512  *
1513  * @param   RgSchCellCb    *cell
1514  * @param   RgSchUeCb      *ue
1515  * @param   RgrUeRecfg     *ueReCfg
1516  * @return  ROK/RFAILED
1517  */
1518 #ifdef ANSI
1519 PUBLIC S16 rgSCHDrxUeReCfg 
1520 (
1521  RgSchCellCb *cell, 
1522  RgSchUeCb   *ue, 
1523  RgrUeRecfg  *ueReCfg
1524  )
1525 #else
1526 PUBLIC S16 rgSCHDrxUeReCfg (cell, ue, ueReCfg)
1527  RgSchCellCb *cell; 
1528  RgSchUeCb   *ue; 
1529  RgrUeRecfg  *ueReCfg;
1530 #endif
1531 {
1532       /* DRX_INFI_LOOP */
1533    RgSchCmnCell      *cellSch = NULLP;
1534    CmLListCp         dlInactvLst; /* list of UE's becoming DL-inactive */
1535
1536    S16               ret       = ROK;
1537    Inst              instIdx   = cell->instIdx;
1538    RgSchDrxUeCb      *ueDrxCb;
1539    CmLteTimingInfo   nxtOnDur;
1540    U16               nxtOnDurTime;
1541    U16               onDurIndx;
1542    U16               curTime;
1543    U16               shrtCycleExpIndx;
1544    U16               onDurExpTime;
1545    U16               cycleLen;
1546    U16               curIndx;
1547    U8                cellIdx;
1548
1549    TRC2(rgSCHDrxUeReCfg);
1550
1551
1552   /* drx was disabled but now enabled for this ue */ 
1553   if ( (ue->isDrxEnabled == FALSE) 
1554              &&
1555        (ueReCfg->ueDrxRecfg.isDrxEnabled == TRUE)
1556      )
1557   {
1558      /* allocated and initialize drxCb */
1559      ret = rgSCHUtlAllocSBuf(instIdx, (Data**)&ue->drxCb,
1560                               (sizeof(RgSchDrxUeCb)));
1561
1562      if ( ret != ROK )
1563      {
1564         RLOG_ARG1(L_ERROR,DBG_CELLID,cell->cellId,
1565            "rgSCHdrxUeReCfg():""Memory allocation FAILED for DRX UE Cb CRNTI:%d",
1566                   ue->ueId);
1567         RETVALUE(ret);
1568      }
1569
1570      ue->isDrxEnabled = TRUE;    /* sachin */
1571      /* initialize the masks */
1572      ue->drxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1573      ue->drxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1574      ue->dl.dlInactvMask     |= RG_DRX_INACTIVE;
1575      ue->ul.ulInactvMask     |= RG_DRX_INACTIVE;
1576
1577      for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1578      {
1579         ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1580         ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1581      }   
1582
1583      /* set all indexes to default values */
1584      ue->drxCb->onDurIndx       = DRX_INVALID;
1585      ue->drxCb->onDurExpIndx    = DRX_INVALID;
1586      ue->drxCb->drxInactvIndx   = DRX_INVALID;
1587      ue->drxCb->shortCycleIndx  = DRX_INVALID;
1588
1589      /* set all distances to timer expiry */
1590      ue->drxCb->onDurExpDistance      = DRX_TMR_EXPRD;
1591      ue->drxCb->drxInactDistance      = DRX_TMR_EXPRD;
1592      ue->drxCb->drxShortCycleDistance = DRX_TMR_EXPRD;
1593      ue->drxCb->distance              = DRX_TMR_EXPRD;
1594      
1595   }
1596   if( ue->drxCb == NULLP ) 
1597   { 
1598      RETVALUE(RFAILED); 
1599   }
1600    ueDrxCb = ue->drxCb;
1601    
1602    /*drx was enabled but now disabled for this UE */
1603    if ( (ue->isDrxEnabled == TRUE )
1604             &&
1605         (ueReCfg->ueDrxRecfg.isDrxEnabled == FALSE)
1606       )
1607    {
1608       /* remove UE from all DRX Queues */
1609       (Void)rgSCHDrxUeDel(cell,ue);
1610
1611       /* free drxCb */
1612       /* ccpu00117052 - MOD - Passing double pointer
1613       for proper NULLP assignment*/
1614       rgSCHUtlFreeSBuf(instIdx,(Data **)(&((ue->drxCb))),
1615                               sizeof(RgSchDrxUeCb));
1616
1617       /* Resetting the DRX Bit set in Inactv Mask */
1618       ue->dl.dlInactvMask     &= ~RG_DRX_INACTIVE;
1619       ue->ul.ulInactvMask     &= ~RG_DRX_INACTIVE;
1620
1621       ue->isDrxEnabled = FALSE;
1622
1623    }/*isDrxEnabled == FALSE */
1624    else
1625    {
1626       /* If Application is updating DRX params */
1627       if (ueReCfg->ueRecfgTypes & RGR_UE_DRX_RECFG )
1628       {
1629          rgSCHDrxCpyUeCfg (ueDrxCb, &ueReCfg->ueDrxRecfg);
1630 #ifdef EMTC_ENABLE
1631          if(ue->isEmtcUe)
1632          {
1633             rgSCHEmtcDrxCpyUeCfg(ue, &ueReCfg->ueDrxRecfg);
1634          }
1635 #endif
1636
1637       }
1638
1639       /* Removing the UE from existing index of shortcycle, if any*/ 
1640       if(ueDrxCb->shortCycleIndx != DRX_INVALID)
1641       {
1642          cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1643                &(ueDrxCb->shortCycleEnt)); 
1644
1645          ueDrxCb->shortCycleEnt.node = (PTR) NULLP;
1646          ueDrxCb->shortCycleIndx     = DRX_INVALID;
1647       }
1648       
1649       /* Mark for intiating long/short cycle as per received config */
1650       if(FALSE == ue->drxCb->isShortCycleCfgd)
1651       {
1652          ue->drxCb->isLongCycle = TRUE;
1653       }
1654       else
1655       {
1656          ue->drxCb->isLongCycle = FALSE;
1657       }  
1658
1659       /* Calculate the next occurance from this point */
1660       rgSCHDrxGetNxtOnDur (cell, ueDrxCb, &nxtOnDur,RG_SCH_NO_DELTA);
1661
1662       /* remove the UE from the current onDuration Queue */ 
1663       if ( ueDrxCb->onDurIndx != DRX_INVALID )
1664       {
1665          cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurIndx].onDurationQ),
1666                              &(ueDrxCb->onDurationEnt)); 
1667       }
1668
1669
1670       nxtOnDurTime = (nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur.slot;
1671       curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1672                    cell->crntTime.slot);
1673
1674       /* If Onduration timer of old configuration is already running then waiting till it expires */
1675       if((ueDrxCb->onDurExpIndx != DRX_INVALID) && (ueDrxCb->onDurExpDistance != DRX_TMR_EXPRD))
1676       {
1677          curIndx = (curTime + RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
1678          RLOG_ARG3(L_DEBUG,DBG_CELLID,cell->cellId,
1679                "OLD ONDUR RUNNING-EXPIRES at %d curIdx-%d nxtOnDurTime-%d",
1680                ueDrxCb->onDurExpIndx, 
1681                curIndx,
1682                nxtOnDurTime);  
1683
1684          /* Manipulating the time when old onDuration timer can expire */ 
1685          if(curIndx >= ueDrxCb->onDurExpIndx)
1686          {
1687             onDurExpTime = curTime + ((ueDrxCb->onDurExpDistance+1) * RG_SCH_MAX_DRXQ_SIZE)+ (ueDrxCb->onDurExpIndx - curIndx + RG_SCH_DRX_DL_DELTA); 
1688          }
1689          else
1690          {
1691             onDurExpTime = curTime + (ueDrxCb->onDurExpDistance * RG_SCH_MAX_DRXQ_SIZE)+ (ueDrxCb->onDurExpIndx - curIndx + RG_SCH_DRX_DL_DELTA); 
1692          }         
1693
1694          if(nxtOnDurTime <= onDurExpTime)
1695          {
1696             if(ueDrxCb->isLongCycle)
1697             {
1698                cycleLen = ueDrxCb->longDrxCycle;
1699             }
1700             else
1701             {
1702                cycleLen = ueDrxCb->shortDrxCycle;
1703             }
1704             /* Moving to the possible occassion of onduration after current onduration expiry:
1705              * If both are aligning then going for next cycle */
1706             nxtOnDurTime += ((onDurExpTime - nxtOnDurTime)/cycleLen + 1 ) *cycleLen ;
1707          }
1708       }   
1709       /* Add the UE to the index which corresponds to the next onduration start*/
1710       onDurIndx = nxtOnDurTime % RG_SCH_MAX_DRXQ_SIZE;
1711
1712       ueDrxCb->distance = (nxtOnDurTime - curTime) / RG_SCH_MAX_DRXQ_SIZE;
1713       if (ueDrxCb->distance < 0)
1714       {
1715          RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId,"DRXUE. Invalid "
1716             "value for distance, %d CRNTI:%d", ueDrxCb->distance,ue->ueId);
1717       }
1718     
1719       cmLListAdd2Tail(&(cell->drxCb->drxQ[onDurIndx].onDurationQ), 
1720             &(ueDrxCb->onDurationEnt));
1721
1722       ueDrxCb->onDurationEnt.node = (PTR)ue;
1723       ueDrxCb->onDurIndx        = onDurIndx;
1724
1725       /* DRX_INFI_LOOP */
1726       cmLListInit(&dlInactvLst);
1727       /* Add to DL inactive list */
1728       cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
1729       ue->dlDrxInactvLnk.node = (PTR)ue;
1730       /* Send the list to the scheduler to mark UE as inactive */
1731       cellSch = RG_SCH_CMN_GET_CELL(cell);
1732       cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
1733       /* DRX_INFI_LOOP */
1734
1735       /* Starting short cycle timer as per the existence of old onDuration timer */
1736       if(TRUE == ueDrxCb->isShortCycleCfgd)
1737       {
1738          /* Expiring short DRX cycle Tmr once the number of short DRX cycles done */
1739          ueDrxCb->drxShortCycleDistance = (nxtOnDurTime + ueDrxCb->onDurTmrLen + (ueDrxCb->shortCycleTmrLen -1 )*
1740                ueDrxCb->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
1741          shrtCycleExpIndx = (nxtOnDurTime + ueDrxCb->onDurTmrLen + ((ueDrxCb->shortCycleTmrLen -1)*
1742                ueDrxCb->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE; 
1743          cmLListAdd2Tail(&(cell->drxCb->drxQ[shrtCycleExpIndx].shortCycleQ),
1744                &(ueDrxCb->shortCycleEnt));
1745          ueDrxCb->shortCycleEnt.node = (PTR)ue;
1746          ueDrxCb->shortCycleIndx     = shrtCycleExpIndx;
1747       }   
1748    }
1749
1750    RETVALUE(ROK);
1751
1752 } /* end of rgSCHDrxUeReCfg */
1753 #endif
1754
1755 /** @brief This function Loop through the list of HARQ processes for this 
1756  *  UE and delete from  the harqRTTQ and harqRetxQ
1757  *
1758  *     Function: rgSCHDrxUeHqReset
1759  *         Invoked by rgSCHDrxUeDel
1760  *
1761  *         Processing steps:
1762            Loop through the list of HARQ processes for this UE and delete from
1763  *         the harqRTTQ and harqRetxQ. 
1764  *
1765  * @param  RgSchCellCb  *cell
1766  * @return ROK/RFAILED
1767  */
1768 #ifdef ANSI
1769 PUBLIC Void rgSCHDrxUeHqReset
1770 (
1771  RgSchCellCb   *cell,
1772  RgSchUeCb     *ue,
1773  RgSchDlHqEnt  *hqE,
1774  U8            cellIdx
1775  )
1776 #else
1777 PUBLIC Void rgSCHDrxUeHqReset(cell, ue, hqE, cellIdx)
1778  RgSchCellCb   *cell; 
1779  RgSchUeCb     *ue;
1780  RgSchDlHqEnt  *hqE;
1781  U8            cellIdx;
1782 #endif
1783
1784    RgSchDlHqProcCb     *hqP;
1785    RgSchDrxDlHqProcCb  *drxHq   =NULLP;
1786    U8                  i;
1787
1788    TRC2(rgSCHDrxUeHqReset);
1789
1790    for(i=0; i < hqE->numHqPrcs; i++)
1791    {
1792       hqP     = &hqE->procs[i];
1793       drxHq   = RG_SCH_DRX_GET_DL_HQ(hqP);
1794
1795       if(drxHq->rttIndx != DRX_INVALID)
1796       {
1797          cmLListDelFrm (&(cell->drxCb->drxQ[drxHq->rttIndx].harqRTTQ),
1798                &(drxHq->harqRTTEnt));
1799
1800          drxHq->rttIndx = DRX_INVALID;
1801       }
1802
1803       if(drxHq->reTxIndx != DRX_INVALID)
1804       {
1805          cmLListDelFrm (&(cell->drxCb->drxQ[drxHq->reTxIndx].harqRetxQ),
1806                &(drxHq->harqRetxEnt));
1807
1808          drxHq->reTxIndx = DRX_INVALID;
1809       }
1810    }
1811
1812    ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1813    ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1814 }
1815
1816 /** @brief This function Deletes DRX specific context for a UE.
1817  *
1818  * @details This funciton is invoked by the Configuration module on RGR UE Deletion.
1819  * This function removes the UE's context from all of the DRX Queues. 
1820  * In addition it deletes context of UE's HARQ Processes present in the harqRTTQ
1821  * and harqRetxQ
1822  *    
1823  * 
1824  *     Function: rgSCHDrxUeDel
1825  *         Invoked by rgSCHCfgRgrUeDel
1826  *
1827  *         Processing steps:
1828  *         - Remove the UE from the following queues
1829  *          - onDurationQ - using onDurIndx
1830  *          - onDurationExpQ - using onDurExpIndx
1831  *          - inActvTmrQ - using drxInactvIndx
1832  *          - shortCycleQ - using shortCycleIndx
1833  *         - Loop through the list of HARQ processes for this UE and delete from
1834  *         the harqRTTQ and harqRetxQ. 
1835  *
1836  * @param  RgSchCellCb  *cell
1837  * @param  RgSchUeCb    *ue
1838  * @return ROK/RFAILED
1839  */
1840 #ifdef ANSI
1841 PUBLIC S16 rgSCHDrxUeDel
1842 (
1843  RgSchCellCb   *cell,
1844  RgSchUeCb      *ue
1845  )
1846 #else
1847 PUBLIC S16 rgSCHDrxUeDel (cell, ue)
1848  RgSchCellCb   *cell; 
1849  RgSchUeCb     *ue;
1850 #endif
1851 {
1852    RgSchDrxUeCb       *ueDrxCb;
1853    RgSchDlHqEnt       *hqE = NULLP;
1854    U8                  cellIdx;
1855    RgSchUeCellInfo    *cellInfo = NULLP;
1856 #ifdef EMTC_ENABLE
1857    RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
1858 #endif
1859    TRC2(rgSCHDrxUeDel);
1860
1861
1862    /* ccpu00129899: Moved the drx-enabled check to the caller */   
1863    ueDrxCb = ue->drxCb;
1864
1865    /* Remove UE from all queues */
1866    if ( ueDrxCb->onDurIndx != DRX_INVALID )
1867    {
1868       cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurIndx].onDurationQ),
1869             &(ueDrxCb->onDurationEnt));
1870
1871       ueDrxCb->onDurIndx = DRX_INVALID;
1872    }
1873
1874    if ( ueDrxCb->onDurExpIndx != DRX_INVALID )
1875    {
1876       cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurExpIndx].onDurationExpQ),
1877             &(ueDrxCb->onDurationExpEnt)); 
1878
1879       ueDrxCb->onDurExpIndx = DRX_INVALID;
1880    }
1881
1882    if ( ueDrxCb->drxInactvIndx != DRX_INVALID )
1883    {
1884       cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->drxInactvIndx].inActvTmrQ),
1885             &(ueDrxCb->inActvTmrEnt)); 
1886
1887       ueDrxCb->drxInactvIndx = DRX_INVALID;
1888    }
1889
1890    if ( ueDrxCb->shortCycleIndx != DRX_INVALID )
1891    {
1892       cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1893             &(ueDrxCb->shortCycleEnt)); 
1894
1895       ueDrxCb->shortCycleIndx = DRX_INVALID;
1896    }
1897
1898    for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1899    {
1900       cellInfo = ue->cellInfo[cellIdx];
1901
1902       if(cellInfo)
1903       {   
1904          hqE = cellInfo->hqEnt;
1905          rgSCHDrxUeHqReset(cell, ue, hqE, cellIdx);
1906       }
1907    }
1908 #ifdef EMTC_ENABLE
1909    if(ue->isEmtcUe)
1910    {
1911        rgSCHDrxUeUlHqReset(cell, ue, &(ueUl->hqEnt));
1912    }
1913 #endif
1914    /* Resetting the DRX Bit set in Inactv Mask */
1915    ue->dl.dlInactvMask     &= ~RG_DRX_INACTIVE;
1916    ue->ul.ulInactvMask     &= ~RG_DRX_INACTIVE;
1917    ueDrxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1918    ueDrxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1919
1920    RETVALUE(ROK);
1921 }/*rgSCHDrxUeDel*/
1922
1923 /** @brief This function is called at the time of RGR cell configuration.
1924  *
1925  * @details
1926  *     Invoked by - rgSCHCfgRgrCellCfg
1927  *
1928  *     Function: rgSCHDrxCellCfg 
1929  *
1930  *         Processing steps:
1931  *         - Initializes the following drxQ (cmMemset would do).
1932  *
1933  *
1934  * @param RgSchCellCb   *cell
1935  * @param RgrCellCfg    *cellCfg
1936  * @return ROK/RFAILED
1937  */
1938 #ifdef ANSI
1939 PUBLIC S16 rgSCHDrxCellCfg 
1940 (
1941  RgSchCellCb   *cell,
1942  RgrCellCfg    *cellCfg
1943  )
1944 #else
1945 PUBLIC S16 rgSCHDrxCellCfg (cell, cellCfg)
1946  RgSchCellCb   *cell; 
1947  RgrCellCfg    *cellCfg;
1948 #endif
1949 {
1950
1951    S16               ret       = ROK;
1952    Inst              instIdx   = cell->instIdx;
1953
1954    TRC2(rgSCHDrxCellCfg);
1955
1956
1957 #if ( ERRCLASS & ERRCLS_INT_PAR )
1958   /*KWORK_FIX :Removed check for cell being NULL*/ 
1959    if( (cellCfg == (RgrCellCfg* )NULLP))
1960    {
1961       RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
1962                 "rgSCHDrxCellCfg():Invalid Params. cell/cellCfg is NULL");
1963       RETVALUE(RFAILED);
1964    }
1965 #endif
1966
1967    /* allocate and initialize drxCb */
1968    ret = rgSCHUtlAllocSBuf(instIdx, (Data**)&cell->drxCb, 
1969          (sizeof(RgSchDRXCellCb)));
1970
1971    if(ret != ROK)
1972    {
1973       RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,"rgSCHDrxCellCfg():"
1974                "Memory allocation FAILED for DRX cell Cb");
1975       RETVALUE(ret);
1976    }
1977
1978    /* delInUlScan determines which index scans the queue last.
1979     * We look at onDurationQ both from ulIndex & dlIndex pov.
1980     * Consider, onDuration starts at index 5, and current index is 2,
1981     * while dlIndex is 2 & ulIndex is 3 i.e dl is looking 2 SF ahead
1982     * and ul is looking 3 SF ahead. In this case, dl will scan the queue
1983     * last and therefore DL will delete ueCb from onDuration q. 
1984     * The reverse is true for the other case.*/
1985    
1986    if ( RG_SCH_DRX_UL_DELTA > RG_SCH_DRX_DL_DELTA )
1987    {
1988       cell->drxCb->delInUlScan = FALSE;
1989    }
1990    else
1991    {
1992       cell->drxCb->delInUlScan = TRUE;
1993    }
1994
1995    RETVALUE(ret);
1996 } /* end of rgSchDrxCellCfg */
1997
1998
1999
2000 /** @brief This function to delete DRX specific context in the cell control
2001  * block.
2002  *
2003  * @details
2004  *    Invoked by - rgSCHCfgRgrCellDel
2005  *
2006  *     Function: rgSCHDrxCellDel 
2007  *
2008  *         Processing steps:
2009  *         - De-Inits RgSchDRXCellCb (Nothing to be done)
2010  *         - Assumption: The API is invoked after deletion of UEs from the cell.
2011  *
2012  * @param  RgSchCellCb  *cell
2013  * @return Void
2014  */
2015 #ifdef ANSI
2016 PUBLIC Void rgSCHDrxCellDel 
2017 (
2018  RgSchCellCb *cell
2019  )
2020 #else
2021 PUBLIC Void rgSCHDrxCellDel (cell)
2022  RgSchCellCb *cell;
2023 #endif
2024 {
2025    Inst              instIdx      = cell->instIdx;
2026
2027    TRC2(rgSCHCfgRgrCellDel);
2028
2029    
2030    if (cell->drxCb)
2031    {
2032       /* ccpu00117052 - MOD - Passing double pointer
2033       for proper NULLP assignment*/
2034       rgSCHUtlFreeSBuf(instIdx, (Data **)(&(cell->drxCb)),
2035             sizeof(RgSchDRXCellCb));
2036    }
2037    RETVOID;
2038 } /* end of rgSchDrxCellDel */
2039
2040 /** @brief This function is called when an SR is received from the UE. In this
2041  * case the UE should be marked as ACTIVE till we send a UL allocation to the
2042  * UE.
2043  *
2044  * @details
2045  *    Invoked by - rgSCHCmnSrRcvd
2046  *    Must be called after calling the specific scheduler.
2047  *
2048  *     Function: rgSCHDrxSrInd 
2049  *
2050  *         Processing steps:
2051  *         - Mark the UE as ACTIVE 
2052  *           ueCb->drxUlInactvMask |= (DRX_SR_ACTIVE);
2053  *         - Optionally call schedulers to add this UE to their scheduling
2054  *         queues. 
2055  *         - Set drxUe->srRcvd = TRUE
2056  *
2057  *         Note : the specification state that the UE shall start be active
2058  *         listening for UL grant, this implies we could potentially exploit
2059  *         this to send DL transmissions as well. However we have currently
2060  *         chosen not to do so.
2061  *
2062  * @param   RgSchCellCb  *cell
2063  * @param   RgSchUeCb    *ue
2064  * @return  ROK/RFAILED
2065  */
2066 #ifdef ANSI
2067 PUBLIC S16 rgSCHDrxSrInd 
2068 (
2069  RgSchCellCb   *cell, 
2070  RgSchUeCb     *ue
2071  )
2072 #else
2073 PUBLIC S16 rgSCHDrxSrInd (cell, ue)
2074  RgSchCellCb   *cell; 
2075  RgSchUeCb     *ue;
2076 #endif
2077 {
2078    RgSchDrxUeCb      *drxCb;
2079
2080    TRC2(rgSCHDrxSrInd);
2081
2082
2083 #if ( ERRCLASS & ERRCLS_INT_PAR )
2084    if ( cell == (RgSchCellCb* )NULLP)
2085    {
2086       RETVALUE(ROK);
2087    }
2088
2089    if( (ue == (RgSchUeCb* )NULLP))
2090    {
2091       RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
2092                  "rgSCHDrxSrInd():Invalid Params. cell/ue is NULL");
2093       RETVALUE(RFAILED);
2094    }
2095  #endif
2096    /* KWork fix - shifted this down */
2097    
2098
2099    drxCb = RG_SCH_DRX_GET_UE(ue);
2100
2101    /* Mark the UE as active for UL only */
2102    drxCb->drxUlInactvMask  &= ~RG_SCH_DRX_SR_BITMASK;
2103    drxCb->srRcvd = TRUE;
2104    /* Update UE's inactive mask and if required move UE to ACTIVE state */
2105    RG_SCH_CMN_UL_UPDT_INACTV_MASK( cell, ue, RG_DRX_INACTIVE);
2106
2107    RETVALUE(ROK);
2108 } /* rgSCHDrxSrInd */
2109
2110
2111 /** @brief This function handles ACTIVITY due to RACH using a dedicated preamble
2112  * (PDCCH order) OR Handover. A UE shall remain marked as active from the time
2113  * we successfully send out a RAR upto the time it receives a PDCCH indicating a
2114  * new transmission. 
2115  *
2116  * @details
2117  *    Invoked by - rgSCHCmnHdlHoPo
2118  *
2119  *     Function: rgSCHDrxDedRa 
2120  *
2121  *         Processing steps:
2122  *         - MARK the UE as active
2123  *         - set the raRcvd = TRUE for this UE.
2124  *
2125  *         @code
2126  *         ueCb->drxDlInactvMask |= (DRX_RA_ACTIVE);
2127  *         ueCb->drxUlInactvMask |= (DRX_RA_ACTIVE);
2128  *         ueCb->raRcvd = TRUE;
2129  *         @endcode
2130  *
2131  * @param  RgSchCellCb  *cellCb
2132  * @param  RgSchUeCb    *ueCb
2133  * @return Void 
2134  */
2135 #ifdef ANSI
2136 PUBLIC Void rgSCHDrxDedRa 
2137 (
2138 RgSchCellCb   *cellCb, 
2139 RgSchUeCb     *ueCb
2140  )
2141 #else
2142 PUBLIC Void rgSCHDrxDedRa (cellCb, ueCb)
2143 RgSchCellCb   *cellCb; 
2144 RgSchUeCb     *ueCb;
2145 #endif
2146 {
2147    RgSchDrxUeCb      *drxCb;
2148
2149    TRC2(rgSCHDrxDedRa);
2150
2151
2152    drxCb = RG_SCH_DRX_GET_UE(ueCb);
2153
2154    /* Mark the UE as active for UL & DL */
2155    drxCb->drxUlInactvMask  &= ~RG_SCH_DRX_RA_BITMASK;
2156    /* Update UE's inactive mask and if required move UE to ACTIVE state */
2157    RG_SCH_CMN_UL_UPDT_INACTV_MASK(cellCb, ueCb, RG_DRX_INACTIVE);
2158    
2159    drxCb->drxDlInactvMask  &= ~RG_SCH_DRX_RA_BITMASK;
2160    /* Update UE's inactive mask and if required move UE to ACTIVE state */
2161    RG_SCH_CMN_DL_UPDT_INACTV_MASK(cellCb, ueCb, RG_DRX_INACTIVE);
2162
2163    drxCb->raRcvd = TRUE;
2164
2165    RETVOID;
2166 } /* end of rgSCHDrxDedRa */
2167
2168
2169 /** @brief This function calculates the next onDuration Occurence
2170  * and removes & queue it again in onDurationQ
2171  *
2172  * @details
2173  *    Invoked by - 
2174  *
2175  *     Function: rgSCHDrxMvToNxtOnDurOcc
2176  *
2177  *         Processing steps:
2178  *
2179  *
2180  * @param  RgSchCellCb     *cell
2181  * @param  RgSchUeCb       *ueCb
2182  * @param  U16              idx  - if calcFrmOffst is TRUE,
2183  *                                 idx is delta to be added
2184  * @param  Bool             calcFrmOffst
2185  * @return Void 
2186  */
2187 #ifdef ANSI
2188 PRIVATE Void rgSCHDrxMvToNxtOnDurOcc 
2189 (
2190 RgSchCellCb      *cell,
2191 RgSchUeCb        *ueCb,
2192 U16               idx,
2193 Bool              calcFrmOffst
2194 )
2195 #else
2196 PRIVATE Void rgSCHDrxMvToNxtOnDurOcc (cell, ueCb, idx, calcFrmOffst)
2197 RgSchCellCb      *cell;
2198 RgSchUeCb        *ueCb; 
2199 U16               idx;
2200 Bool              calcFrmOffst;
2201 #endif
2202 {
2203    U16             nxtOnDurIndex;
2204    U16             curTime;
2205    RgSchDrxUeCb    *drxUe;
2206    RgSchDRXCellCb  *drxCell;
2207    CmLteTimingInfo  nxtOnDur; /* to be used when calcFrmOffset is set */
2208    U16              nxtOnDurInSf; /* next On Duration in no of subframes */
2209
2210    drxCell = cell->drxCb;
2211    drxUe   = ueCb->drxCb;
2212
2213    TRC2(rgSCHDrxMvToNxtOnDurOcc)
2214
2215    if(calcFrmOffst == FALSE)
2216    {
2217       if (drxUe->isLongCycle)
2218       {
2219          nxtOnDurIndex = ((idx + drxUe->longDrxCycle)
2220                % RG_SCH_MAX_DRXQ_SIZE  );
2221          drxUe->distance = drxUe->longDrxCycle/RG_SCH_MAX_DRXQ_SIZE;
2222       }
2223       else
2224       {
2225          nxtOnDurIndex = ((idx + drxUe->shortDrxCycle)% RG_SCH_MAX_DRXQ_SIZE);
2226
2227          drxUe->distance = drxUe->shortDrxCycle / RG_SCH_MAX_DRXQ_SIZE;
2228       }
2229    }
2230    else
2231    {
2232       rgSCHDrxGetNxtOnDur(cell,drxUe,&nxtOnDur,(U8)idx);
2233       
2234       nxtOnDurInSf = ((nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) + 
2235                          nxtOnDur.slot);
2236       
2237       curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
2238             cell->crntTime.slot);
2239
2240       nxtOnDurIndex   = nxtOnDurInSf % RG_SCH_MAX_DRXQ_SIZE;
2241       drxUe->distance = (nxtOnDurInSf-curTime) / RG_SCH_MAX_DRXQ_SIZE;
2242       if (drxUe->distance < 0)
2243       {
2244          RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId,"DRXUE. Invalid "
2245             "value for distance, %d CRNTI:%d", drxUe->distance,ueCb->ueId);
2246       }
2247    }
2248
2249    /* First remove from existing location */
2250    if ( drxUe->onDurIndx != DRX_INVALID )
2251    {
2252       cmLListDelFrm(&(drxCell->drxQ[drxUe->onDurIndx].onDurationQ),
2253             &(drxUe->onDurationEnt));
2254    }
2255
2256    /* Add at new location */
2257    cmLListAdd2Tail(&(drxCell->drxQ[nxtOnDurIndex].onDurationQ),
2258          &(drxUe->onDurationEnt));
2259
2260    drxUe->onDurationEnt.node = (PTR)ueCb;
2261    drxUe->onDurIndx          = nxtOnDurIndex;
2262
2263    RETVOID;
2264 }/*rgSCHDrxMvToNxtOnDurOcc*/
2265
2266 #ifdef LTE_TDD
2267 /** @brief This function calculates the next SFN,subframe a given  
2268  *  timer is going to expire. Works for all TDD configurations. 
2269  *
2270  * @details
2271  *
2272  *     Function: rgSCHDrxGetNxtTmrExpry 
2273  *         We need to count only PDCCH frames in a given TDD
2274  *         configuration. This is true for onDuration, inActivity
2275  *         & drx-retransmission timers.
2276  *         
2277  *         Processing steps (assume timer starts at (12,2) and duration
2278  *                           is 23 DL subframes): 
2279  *              - based on TDD configuration, move to the next SFN and 
2280  *                count the number of DL subframes consumed. In our example,
2281  *                moving to (12,9) will consume 6 DL subframes assuming TDD 
2282  *                config of 2.
2283  *              - From this point on, determine how many exact Radio Frames
2284  *                will be consumed for the remaining DL subframes. In our 
2285  *                example, remaining DL subframes are (23-6) are 17. 
2286  *                For config 2, the following holds true
2287  *                  8 DLSF are in 1 RF
2288  *                  1 DLSF in 1/8 DLSF
2289  *                  17 DLSF in 17/8 i.e 2 RF + 1 subframe
2290  *                  In order to consume 17 DLSF, we need to move forward
2291  *                  2 RFs + 1 subframe. Adding 2 RF's gives us (14,9)
2292  *              - For the remaining subframe, we need to figure out the next 
2293  *                available DL subframe. For TDD_configuration, the first DL 
2294  *                subframe is at index 0. So, the timer will run till (15,0) 
2295  *                and will expire on (15,1)
2296  *
2297  * @param  RgSchUeCb       *ue          Ue control block.
2298  * @param  U16             curTime      current Time 
2299  * @param  U32             duration     Timer duration 
2300  * @param  CmLteTimingInfo *tmrExpryIdx Timer expry (SFN,sf)
2301  * @return ROK/RFAILED
2302  */
2303 #ifdef ANSI
2304 PRIVATE S16 rgSCHDrxGetNxtTmrExpry 
2305 (
2306  RgSchCellCb        *cell,
2307  U16                curTime,
2308  U32                duration, 
2309  CmLteTimingInfo    *tmrExpryIdx
2310 )
2311 #else
2312 PRIVATE S16 rgSCHDrxGetNxtTmrExpry (cell,curTime,duration,tmrExpryIdx)
2313  RgSchCellCb         *cell;
2314  U16                 curTime;
2315  U32                 duration;
2316  CmLteTimingInfo     *tmrExpryIdx;
2317 #endif
2318 {
2319    U32             dlSfTillNxtSFN;  /*!< DL subframes till next SFN */
2320    U8              tddCfgMode;      /*!< tdd config mode */
2321    Bool            isDwPtsCnted;    /*!< is DwPts counted as PDCCH sf */
2322    CmLteTimingInfo crntTime;        /*!< current SFN & sf */
2323
2324
2325    TRC2(rgSCHDrxGetNxtTmrExpry);
2326
2327 #if ( ERRCLASS & ERRCLS_INT_PAR )
2328    if ( (cell == (RgSchCellCb* )NULLP) 
2329          ||
2330          (tmrExpryIdx == (CmLteTimingInfo* )NULLP)
2331       )
2332    {
2333       RETVALUE(RFAILED);
2334    }
2335 #endif
2336
2337    
2338    isDwPtsCnted = cell->isDwPtsCnted ;
2339
2340    tddCfgMode        = cell->ulDlCfgIdx;
2341    crntTime.sfn      = curTime / RGSCH_NUM_SUB_FRAMES_5G;
2342    crntTime.slot = curTime % RGSCH_NUM_SUB_FRAMES_5G; 
2343
2344
2345
2346    /* First calculate the number of DL subframes till next SFN */
2347
2348    dlSfTillNxtSFN = rgSchDrxDLSfTillNxtSFN[isDwPtsCnted][tddCfgMode]
2349       [(crntTime.slot % RGSCH_NUM_SUB_FRAMES)];
2350
2351
2352    if ( dlSfTillNxtSFN >= duration )
2353    {
2354       /* the timer would expire on the same RF */
2355       U32 diff = dlSfTillNxtSFN - duration;
2356
2357       tmrExpryIdx->sfn = crntTime.sfn; 
2358
2359       if ( diff == 0 )
2360       {
2361          tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2362             [0];
2363       }
2364       else
2365       {
2366          U8 arrayIdx;
2367          /* to know the DL sf index based on diff */
2368          arrayIdx = rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode]; 
2369
2370          tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2371             [arrayIdx - diff];
2372       }
2373    }/* if ( dlSfTillNxtSFN >= duration...*/
2374    else
2375    {
2376       U32             remSf;           /*!< remaining subframes */
2377       U32             numRf;           /*!< num of complete radio frames */
2378       U32             numRemSfs;       /*!< num of remaining subframes */
2379
2380       remSf = duration - dlSfTillNxtSFN;
2381
2382       /* move to (currSFN,9) having consued dlSfTillNxtSFN DL subframes */
2383       tmrExpryIdx->sfn      = crntTime.sfn;
2384       tmrExpryIdx->subframe = (U8)9;
2385
2386       numRf      = (1 * remSf)/rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2387       numRemSfs  = (1 * remSf)%rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2388
2389       tmrExpryIdx->sfn = tmrExpryIdx->sfn + numRf;
2390
2391       /* we are now at (X,9) having consumed dlSfTillNxtSFN + numRf * num of DL
2392        * subframes in 1 RF */
2393
2394       if ( numRemSfs == 0 )
2395       {
2396          /* we are at subframe 9 i.e. the timer is going to expire using exact
2397           * radio frames. However, not all TDD_configurations have 9 as their
2398           * last DL subframe. We might have passed the last DL subfrme. 
2399           * Therefore, move back */
2400          tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2401                                                                   [numRemSfs];
2402       }
2403       else
2404       {
2405          /* a reminder implies we have to move past this SFN as we are at the 
2406           * last subframe on that SFN */
2407          tmrExpryIdx->sfn++; 
2408          tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2409                                                                   [numRemSfs];
2410       }
2411    }/*else if diff > duration */
2412
2413    /* timer will expire 1 + tmrExpryIdx */
2414
2415    if ( ( tmrExpryIdx->subframe + 1) == 10 )
2416    {
2417       tmrExpryIdx->sfn++;
2418       tmrExpryIdx->subframe = 0;
2419    }
2420    else
2421    {
2422       tmrExpryIdx->subframe++;
2423    }
2424
2425    /* check to see if it sfn has crossed its max */
2426    if ( tmrExpryIdx->sfn > RG_SCH_CMN_MAX_SFN_NUM )
2427    {
2428       tmrExpryIdx->sfn = tmrExpryIdx->sfn - (RG_SCH_CMN_MAX_SFN_NUM + 1);
2429    }
2430
2431    RETVALUE(ROK);
2432 }/*rgSCHDrxGetNxtTmrExpry*/
2433
2434 /** @brief This function calculates the next onDuration Occurence
2435  *         for TDD
2436  * @details
2437  *    Invoked by - 
2438  *
2439  *     Function: rgSCHDrxCalcNxtTmrExpry
2440  *
2441  *         Processing steps: a wrapper function to call
2442  *         rgSCHDrxGetNxtTmrExpry
2443  *
2444  * @param  RgSchCellCb      *cell
2445  * @param  RgSchUeCb        *ue
2446  * @param  U16               delta
2447  * @param  U32               tmrLen 
2448  * @param  U16              *distance
2449  * @param  S16              *idx
2450  * @return ROK/RFAILED
2451  */
2452 #ifdef ANSI
2453 PRIVATE Void rgSCHDrxCalcNxtTmrExpry
2454 (
2455  RgSchCellCb     *cell,
2456  RgSchUeCb       *ue,
2457  U16              delta,
2458  U32              tmrLen,
2459  S16             *distance,
2460  U16             *idx
2461 )
2462 #else
2463 PRIVATE Void rgSCHDrxCalcNxtTmrExpry (cell,ue,delta,tmrLen,distance,idx)
2464  RgSchCellCb     *cell;
2465  RgSchUeCb       *ue;
2466  U16              delta;
2467  U32              tmrLen;
2468  S16             *distance;
2469  U16             *idx;
2470 #endif
2471 {
2472    U16             curTimeInSf;  /*current time in no of subframes*/
2473    CmLteTimingInfo tmrExpry;
2474    U16             tmrExpryInSf; /*timer expry in no of subframes*/
2475
2476    TRC2(rgSCHDrxCalcNxtTmrExpry)
2477    
2478    curTimeInSf = cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G +
2479                    cell->crntTime.slot;
2480
2481    /* add delta to curTime */
2482    curTimeInSf += delta;
2483
2484    rgSCHDrxGetNxtTmrExpry(ue->cell,curTimeInSf,tmrLen,&tmrExpry);
2485
2486    /* convert timre Expry in terms of subframes */
2487    tmrExpryInSf = tmrExpry.sfn * RGSCH_NUM_SUB_FRAMES_5G +
2488                    tmrExpry.subframe;
2489
2490   
2491    *idx = (tmrExpryInSf) % RG_SCH_MAX_DRXQ_SIZE;
2492
2493    if ( distance != NULLP ) /* hqReTx don't use the concept of distance.
2494                                They can send NULLP for distance.
2495                              */
2496    {
2497       if ( tmrExpryInSf > curTimeInSf )
2498       {
2499          *distance = (tmrExpryInSf - curTimeInSf) /
2500                    RG_SCH_MAX_DRXQ_SIZE;
2501       }
2502       else
2503       {
2504          /* in case the RF is at its max and wraps around */
2505
2506          *distance = ((tmrExpryInSf + (RG_SCH_CMN_MAX_NUM_OF_SFN - 1)) 
2507                                      -
2508                                     curTimeInSf) / RG_SCH_MAX_DRXQ_SIZE;
2509       }
2510       if (*distance < 0)
2511       {
2512          RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId, "DRXUE. Invalid "
2513             "value for distance, %d CRNTI:%d", *distance,ue->ueId);
2514       }      
2515    }
2516   
2517    RETVOID;
2518 }/*rgSCHDrxCalcNxtTmrExpry*/
2519
2520 /* ccpu00134670- Validating onduration timer versus DRX cycle*/
2521 /***********************************************************
2522  *
2523  *     Func : rgSCHCfgVldtTddDrxCycCfg
2524  *
2525  *
2526  *     Desc : Validates DRX Cycle Length  configuration against received 
2527  *            onDuration timer from RRC.
2528  *
2529  *     Ret  : S16
2530  *            ROK - Success
2531  *
2532  *            RFAILED - Failed
2533  *
2534  *     Notes:
2535  *
2536  *     File :
2537  *
2538  **********************************************************/
2539 #ifdef ANSI
2540 PUBLIC S16 rgSCHCfgVldtTddDrxCycCfg
2541 (
2542 RgSchCellCb  *cell,
2543 U16           drxCycle,
2544 U8            onDurTmr, 
2545 U16           offSet
2546 )
2547 #else
2548 PUBLIC S16 rgSCHCfgVldtTddDrxCycCfg(cell, drxCycle, onDurTmr, offSet)
2549 RgSchCellCb  *cell;
2550 U16           drxCycle;
2551 U8            onDurTmr;
2552 U16           offSet; 
2553 #endif
2554 {
2555    U16             startTime;
2556    U16             endTimeInSf;
2557    CmLteTimingInfo endTime; 
2558    TRC2(rgSCHCfgVldtTddDrxCycCfg)
2559
2560    startTime = offSet;
2561    do
2562    {
2563       rgSCHDrxGetNxtTmrExpry(cell, startTime, onDurTmr, &endTime);
2564     
2565       endTimeInSf = (endTime.sfn* RGSCH_NUM_SUB_FRAMES)+endTime.subframe;
2566      
2567       if(((RGSCH_MAX_SUBFRM_5G + endTimeInSf- startTime) % RGSCH_MAX_SUBFRM_5G) >= 
2568           drxCycle)
2569       {
2570           RETVALUE(RFAILED);
2571       }
2572       
2573       startTime = (startTime + drxCycle);
2574    /* Going for next iteration if the DRX cycle is not multiple of 10. If it is
2575       multiple of 10(Number of Subframes in a SFN) then subframe, at which 
2576       onduration timer can start, will be always same, Otherwise the possible 
2577       subframe numbers, where the onDuration timer can start, is 5. Hence 4 
2578       more iterations are required. */
2579    }while((drxCycle % RGSCH_NUM_SUB_FRAMES) && 
2580        (startTime < (drxCycle * RGSCH_NUM_SUB_FRAMES/2)));
2581    
2582    RETVALUE(ROK);
2583 }
2584
2585 #endif /*LTE_TDD */
2586
2587 /** @brief This function is called to handle onDurationTimer per TTI processing.
2588  *
2589  * @details
2590  *    Invoked by - rgSCHDrxTtiInd 
2591  *
2592  *     Function:  rgSCHDrxTtiHdlOnDurUl
2593  *
2594  *         Processing steps:
2595  *
2596  *           - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
2597  *
2598  *             - For Uplink we shall look at an index that is 
2599  *               n + RG_SCH_DRX_UL_DELTA as
2600  *             we are concerned with the PDCCH and not the actual PUSCH.
2601  *
2602  *
2603  * @param  RgSchCellCb  *cellCb
2604  * @param  U16          ulIndex
2605  * @return Void 
2606  */
2607
2608 #ifdef ANSI
2609 PRIVATE Void rgSCHDrxTtiHdlOnDurUl
2610 (
2611 RgSchCellCb        *cell,
2612 U16                ulIndex
2613 )
2614 #else
2615 PRIVATE Void rgSCHDrxTtiHdlOnDurUl(cell, ulIndex)
2616 RgSchCellCb   *cell;
2617 U16           ulIndex;
2618 #endif
2619 {
2620    CmLList           *node;
2621    RgSchDRXCellCb    *drxCell  = NULLP;
2622    RgSchUeCb         *ue       = NULLP;
2623    RgSchDrxUeCb      *drxUe    = NULLP;
2624    CmLListCp         ulInactvLst; /* list of UE's becoming DL-inactive */
2625    RgSchCmnCell      *cellSch = NULLP;
2626    Bool              delInUlScan = FALSE;
2627    
2628    TRC2(rgSCHDrxTtiHdlOnDurUl)
2629   
2630    drxCell     = (cell->drxCb);
2631    delInUlScan = drxCell->delInUlScan;
2632    /***********************************************************
2633     *    Scanning OnDurationQ in UL
2634     ***********************************************************/
2635
2636    /* For Uplink we shall look at an index that is n + RG_SCH_DRX_UL_DELTA as
2637       we are concerned with the PDCCH and not the actual PUSCH.*/
2638
2639    node = drxCell->drxQ[ulIndex].onDurationQ.first;
2640
2641    while (node)
2642    {
2643       ue    = (RgSchUeCb*)node->node;
2644       node  = node->next;
2645       drxUe = RG_SCH_DRX_GET_UE(ue);
2646
2647
2648       if ( delInUlScan == FALSE)
2649       {
2650          drxUe->distance--;
2651       }
2652
2653       if ( drxUe->distance != DRX_TMR_EXPRD )
2654       {
2655          continue;
2656       }
2657
2658       /* reset the bit mask to indicate that onduration has started */
2659       drxUe->drxUlInactvMask  &= ~RG_SCH_DRX_ONDUR_BITMASK;
2660
2661       /* if no other condition is keeping UE as inactive,
2662        * activate UE
2663        */
2664       RG_SCH_CMN_UL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2665
2666       if ( delInUlScan == TRUE )
2667       {
2668          /*calculate next on duration occurence 
2669           * and it to the onDuration Queue*/
2670          rgSCHDrxMvToNxtOnDurOcc(cell,ue,ulIndex,FALSE);
2671       }/*delInUlScan == FALSE */
2672    }/*while(node)*/
2673    
2674    /***********************************************************
2675     *    Scanning OnDurationExpQ in UL
2676     ***********************************************************/
2677
2678    node = drxCell->drxQ[ulIndex].onDurationExpQ.first;
2679
2680    /* Initialize UL inactive list */
2681    cmLListInit(&ulInactvLst);
2682
2683    while (node)
2684    {
2685       ue = (RgSchUeCb*)node->node;
2686       node = node->next;
2687       drxUe = RG_SCH_DRX_GET_UE(ue);
2688
2689       if ( delInUlScan == FALSE )
2690       {
2691          drxUe->onDurExpDistance--;
2692       }
2693
2694       if ( drxUe->onDurExpDistance != DRX_TMR_EXPRD )
2695       {
2696          continue;
2697       }
2698
2699       /*UE is inactive as onduration has expired */
2700       drxUe->drxUlInactvMask  |= RG_SCH_DRX_ONDUR_BITMASK;
2701
2702       if( !RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
2703       {
2704          /* set the inactive bit to indicate UE has now become inactive */  
2705          ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
2706
2707          /* Add to DL inactive list */
2708          cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
2709          ue->ulDrxInactvLnk.node = (PTR)ue;
2710       }
2711
2712       if ( delInUlScan == TRUE)
2713       {
2714          /*Remove from DRX queue*/
2715          cmLListDelFrm(&(drxCell->drxQ[ulIndex].onDurationExpQ),
2716                &(drxUe->onDurationExpEnt));
2717
2718          drxUe->onDurExpIndx = DRX_INVALID;
2719       }
2720
2721    }/*while(node)*/
2722
2723    /* Send the list to the scheduler to mark UE as inactive in UL*/
2724    cellSch = RG_SCH_CMN_GET_CELL(cell);
2725    cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
2726    
2727    RETVOID;
2728 }
2729
2730 /** @brief This function is called to handle onDurationTimer per TTI processing.
2731  *
2732  * @details
2733  *    Invoked by - rgSCHDrxTtiInd 
2734  *
2735  *     Function:  rgSCHDrxTtiHdlOnDurDl
2736  *
2737  *         Processing steps:
2738  *
2739  *           - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
2740  *
2741  *           - For Downlink we shall look at an index that is 
2742  *             n + RG_SCH_DRX_DL_DELTA. 
2743  *
2744  *
2745  * @param  RgSchCellCb  *cellCb
2746  * @param  U16          dlIndex
2747  * @return Void
2748  */
2749
2750 #ifdef ANSI
2751 PRIVATE Void rgSCHDrxTtiHdlOnDurDl
2752 (
2753 RgSchCellCb    *cell,
2754 U16                dlIndex
2755 )
2756 #else
2757 PRIVATE Void rgSCHDrxTtiHdlOnDurDl(cell, dlIndex)
2758 RgSchCellCb   *cell;
2759 U16           dlIndex;
2760 #endif
2761 {
2762    CmLList           *node;
2763    RgSchDRXCellCb    *drxCell  = NULLP;
2764    RgSchUeCb         *ue       = NULLP;
2765    RgSchDrxUeCb      *drxUe    = NULLP;
2766    RgSchCmnCell      *cellSch = NULLP;
2767    U16               expiryIndex;
2768    CmLListCp         dlInactvLst; /* list of UE's becoming DL-inactive */
2769    Bool              delInUlScan = FALSE;
2770
2771    /* The DL loop, if onDurationTimer has started, will add the UeCb
2772     * in the onDurationTmrExprQ. If !delInUlScan, then calculate the next
2773     * OnDuration occurence, q it there and remove it from the current location.
2774     */
2775    TRC2(rgSCHDrxTtiHdlOnDurDl)
2776    /***********************************************************
2777     *    Scanning OnDurationQ in DL
2778     ***********************************************************/
2779    drxCell     = (cell->drxCb);
2780    
2781    delInUlScan = drxCell->delInUlScan;
2782    //printf("CELL  Timer  [SFN : %d],[SF : %d]\n",cell->crntTime.sfn,cell->crntTime.slot);
2783    
2784    node = drxCell->drxQ[dlIndex].onDurationQ.first;
2785
2786
2787    while (node)
2788    {
2789       ue = (RgSchUeCb* )node->node;
2790
2791       node = node->next;
2792
2793       drxUe = RG_SCH_DRX_GET_UE(ue);
2794
2795       if ( delInUlScan == TRUE)
2796       {
2797          drxUe->distance--;
2798       }
2799
2800       if ( drxUe->distance != DRX_TMR_EXPRD )
2801       {
2802          continue;
2803       }
2804
2805
2806       /* UE is active as onduration is to start */
2807       drxUe->drxDlInactvMask &= ~RG_SCH_DRX_ONDUR_BITMASK;
2808
2809       /* set the UE as DRX active*/ 
2810
2811       /* Update UE's inactive mask and if required move UE to ACTIVE state */
2812       RG_SCH_CMN_DL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2813       /*ACC-TDD */      
2814       /* Temporary fix to delete stale entry */
2815       if (drxUe->onDurExpIndx != DRX_INVALID)
2816       {
2817          RLOG_ARG4(L_DEBUG,DBG_CELLID,cell->cellId, 
2818                "UEID:%d PreExisted[%d:%d]in onDurExpQ new[%d]",
2819                ue->ueId, 
2820                drxUe->onDurExpIndx, 
2821                drxUe->onDurExpDistance, 
2822                dlIndex);
2823          cmLListDelFrm(&(drxCell->drxQ[drxUe->onDurExpIndx].onDurationExpQ),
2824                &(drxUe->onDurationExpEnt));
2825
2826          drxUe->onDurExpIndx = DRX_INVALID;
2827       }
2828       /*start the onduration expiry timer*/
2829 #ifdef LTE_TDD
2830       rgSCHDrxCalcNxtTmrExpry(cell,
2831             ue,
2832             RG_DL_DELTA,
2833             drxUe->onDurTmrLen,
2834             &(drxUe->onDurExpDistance),
2835             &(expiryIndex)
2836             );
2837 #else /*LTE_TDD */
2838       expiryIndex = ((dlIndex + drxUe->onDurTmrLen) %
2839             RG_SCH_MAX_DRXQ_SIZE);
2840       drxUe->onDurExpDistance = (drxUe->onDurTmrLen)/
2841          RG_SCH_MAX_DRXQ_SIZE;
2842 #endif /*LTE_TDD */
2843
2844       cmLListAdd2Tail(&(drxCell->drxQ[expiryIndex].onDurationExpQ),
2845             &(drxUe->onDurationExpEnt));
2846       //printf("DRXOnDuration Timer Started at [SFN : %d],[SF : %d]\n",cell->crntTime.sfn,cell->crntTime.slot);
2847       drxUe->onDurationExpEnt.node = (PTR)ue;
2848       drxUe->onDurExpIndx          = expiryIndex;
2849
2850       //printf("DRxOnDuration will Expire = [%d]\n",(cell->crntTime.sfn*10+cell->crntTime.slot+drxUe->onDurTmrLen));
2851
2852       if ( delInUlScan == FALSE )
2853       {
2854          /*calculate next on duration occurence 
2855           * and it to the onDuration Queue*/
2856          rgSCHDrxMvToNxtOnDurOcc(cell,ue,dlIndex,FALSE);
2857       }/*delInUlScan == FALSE */
2858
2859    }/*while(node)*/
2860
2861    /***********************************************************
2862     *    Scanning OnDurationExpQ in DL
2863     ***********************************************************/
2864
2865    /* Mark UE as Inactive based on OnDuration Expiry */
2866    node = drxCell->drxQ[dlIndex].onDurationExpQ.first;
2867
2868    /* Initialize DL inactive list */
2869    cmLListInit(&dlInactvLst);
2870
2871    while (node)
2872    {
2873       ue    = (RgSchUeCb*)node->node;
2874       node  = node->next;
2875       drxUe = RG_SCH_DRX_GET_UE(ue);
2876
2877       if ( delInUlScan == TRUE )
2878       {
2879          drxUe->onDurExpDistance--;
2880       }
2881
2882       if ( drxUe->onDurExpDistance != DRX_TMR_EXPRD )
2883       {
2884          continue;
2885       }
2886
2887
2888       /* UE is inactive as onduration has expired */
2889       drxUe->drxDlInactvMask |= (RG_SCH_DRX_ONDUR_BITMASK);
2890
2891       if( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
2892       {
2893          /* set the inactive bit to indicate UE has now become inactive */  
2894          ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
2895
2896          /* Add to DL inactive list */
2897          cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
2898          ue->dlDrxInactvLnk.node = (PTR)ue;
2899       }
2900
2901       if ( delInUlScan == FALSE )
2902       {
2903          /*Remove from DRX queue*/
2904          cmLListDelFrm(&(drxCell->drxQ[dlIndex].onDurationExpQ),
2905                &(drxUe->onDurationExpEnt));
2906
2907          drxUe->onDurExpIndx = DRX_INVALID;
2908       }
2909
2910    }
2911
2912    /* Send the list to the scheduler to mark UE as inactive */
2913    cellSch = RG_SCH_CMN_GET_CELL(cell);
2914    cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
2915
2916    RETVOID;
2917 }/*rgSCHDrxTtiHdlOnDurDl*/
2918
2919  /** @brief This function handles the Dl HARQ timer's processing per TTI.
2920   *
2921   * @details
2922   * Invoked by - rgSCHDrxTtiHdlDlHarq 
2923   *
2924   *     Function: rgSCHDrxTtiHdlDlHarqRTT 
2925   *
2926   *         Processing steps:
2927   *         - In addition per TTI DRX module must look at Downlink HARQ queues
2928  *             maintained to track HARQ RTT timer and drx-RetransmissionTimer.
2929  *             Every TTI at the scheduling index we shall check these queues and
2930  *             process accordingly. 
2931  *
2932  * @param  RgSchCellCb *cellCb
2933  * @param  U16          dlIndex
2934  * @return Void 
2935  */
2936
2937 #ifdef ANSI
2938 PRIVATE Void rgSCHDrxTtiHdlDlHarqRTT
2939 (
2940 RgSchCellCb          *cell,
2941 U16                   dlIndex
2942 )
2943 #else /* ANSI */
2944 PRIVATE Void rgSCHDrxTtiHdlDlHarqRTT(cell, dlIndex)
2945 RgSchCellCb          *cell;
2946 U16                   dlIndex;
2947 #endif /* ANSI */
2948 {
2949    CmLList             *node;
2950    RgSchDrxDlHqProcCb  *drxHq;
2951    RgSchDlHqProcCb     *dlHq;
2952    RgSchDRXCellCb      *drxCell;
2953    RgSchDrxUeCb        *drxUe;
2954    U16                 reTxExpIndx;
2955    Bool                delInUlScan;
2956    RgSchUeCb           *ue;
2957    CmLListCp           dlInactvLst; /* list of UE's becoming DL-inactive */
2958    RgSchCmnCell        *cellSch = RG_SCH_CMN_GET_CELL(cell);
2959    U8                  cellIdx;
2960    U32                 dlInactvMask;
2961
2962    TRC2(rgSCHDrxTtiHdlDlHarqRTT);
2963
2964    drxCell     = cell->drxCb;
2965    delInUlScan = drxCell->delInUlScan;
2966
2967    /***********************************************************
2968     *    Scanning harqRTTQ in DL 
2969     ***********************************************************/
2970
2971    cmLListInit(&dlInactvLst);
2972    node = drxCell->drxQ[dlIndex].harqRTTQ.first;
2973
2974    while (node)
2975    {
2976       dlHq = (RgSchDlHqProcCb*)node->node;
2977       node = node->next;
2978       ue   = dlHq->hqE->ue;
2979 #ifdef EMTC_ENABLE
2980       if(TRUE == ue->isEmtcUe)
2981       {
2982          continue;
2983       }
2984 #endif
2985       drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2986       drxUe = RG_SCH_DRX_GET_UE(ue);
2987       cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2988       /* add the UE to the cell's retransmission queuee before starting 
2989        * reTx timer, because this will not depend on retx timer trigger*/
2990       rgSCHUtlDlProcAddToRetx(dlHq->hqE->cell, dlHq);
2991
2992       if ( delInUlScan == FALSE)
2993       {
2994          cmLListDelFrm (&(drxCell->drxQ[dlIndex].harqRTTQ),
2995                &(drxHq->harqRTTEnt));
2996
2997          drxHq->rttIndx = DRX_INVALID;
2998       }
2999       /* ccpu00134565: Starting retransmission timer only if timerLen is
3000        * having non-zero value after reduction, Adding to Retx queue is 
3001        * independent of starting retransmission timer. Hence if part will
3002        * take care of starting retx timer only*/
3003       if (drxUe->drxRetransTmrLen > drxHq->retxTmrReduction)
3004       {
3005          /* add the harq proc to the re-tx queue--*/
3006 #ifdef LTE_TDD
3007          /* ccpu00134196-[Add]-DRX retx timer changes */
3008          rgSCHDrxCalcNxtTmrExpry(cell,
3009               ue,
3010               RG_DL_DELTA,
3011               drxUe->drxRetransTmrLen-drxHq->retxTmrReduction,
3012               NULLP, /*retransQ does not maintain distance*/
3013               &reTxExpIndx
3014               );
3015
3016 #else /*LTE_TDD*/
3017          /* ccpu00134196-[Add]-DRX retx timer changes */
3018          reTxExpIndx =  ((dlIndex +
3019                   drxUe->drxRetransTmrLen-drxHq->retxTmrReduction) % 
3020                   RG_SCH_MAX_DRXQ_SIZE);
3021 #endif /*LTE_TDD*/
3022          /* TODO. Workaround to avoid duplicate entry */ 
3023          if(drxHq->reTxIndx == DRX_INVALID)
3024          {
3025             cmLListAdd2Tail (&(drxCell->drxQ[reTxExpIndx].harqRetxQ),
3026                   &(drxHq->harqRetxEnt));
3027
3028             drxHq->harqRetxEnt.node = (PTR)dlHq;
3029             drxHq->reTxIndx         = reTxExpIndx;
3030          }
3031          else
3032          {
3033             RLOG_ARG4(L_ERROR,DBG_CELLID,cell->cellId,"CRNTI:%d "
3034                "Adding Retx Node to expire at RetxIndx: %d at dlIndex %d "
3035                "drxHq->reTxIndx %d", ue->ueId, reTxExpIndx, dlIndex, 
3036                drxHq->reTxIndx); 
3037             continue;
3038          }
3039          /*mark the ue as active for downlink--*/
3040          drxUe->drxDlInactvMask  &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3041          drxUe->drxDlInactvMaskPerCell[cellIdx]  &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3042                                               
3043          /* Update UE's inactive mask and if required move UE to ACTIVE state */
3044          RG_SCH_CMN_DL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
3045       }
3046    }/*while(node)*/
3047    
3048    /***********************************************************
3049     *    Scanning harqRetxQ in DL 
3050     ***********************************************************/
3051
3052    node = drxCell->drxQ[dlIndex].harqRetxQ.first;
3053    while (node)
3054    {
3055       dlHq = (RgSchDlHqProcCb*)node->node;
3056       ue   = dlHq->hqE->ue;
3057       drxUe = RG_SCH_DRX_GET_UE(ue);
3058       node = node->next;
3059       drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
3060       cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
3061
3062       /*mark the ue as in-active for downlink*/
3063       drxUe->drxDlInactvMaskPerCell[cellIdx]  |= (RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3064
3065       dlInactvMask = RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId;
3066
3067       for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
3068       {
3069          dlInactvMask &= drxUe->drxDlInactvMaskPerCell[cellIdx];
3070       }   
3071
3072       drxUe->drxDlInactvMask |= dlInactvMask;
3073
3074       /* if no other condition is keeping ue active,
3075        * inactivate the Ue 
3076        */
3077       if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
3078       {
3079           ue->dl.dlInactvMask |= (RG_DRX_INACTIVE);
3080
3081          /* Add to DL inactive list */
3082          cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
3083          ue->dlDrxInactvLnk.node = (PTR)ue;
3084       }
3085
3086       /*remove the harq proc from this queue*/
3087       if ( delInUlScan == FALSE)
3088       {
3089          cmLListDelFrm (&(drxCell->drxQ[dlIndex].harqRetxQ),
3090                &(drxHq->harqRetxEnt));
3091          drxHq->reTxIndx = DRX_INVALID;
3092       }
3093    }
3094    /*Call schedulers to inactivate ue*/
3095    cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
3096
3097    RETVOID;
3098 }
3099
3100  /** @brief This function handles the Ul HARQ timer's processing per TTI.
3101   *
3102   * @details
3103   * Invoked by - rgSCHDrxTtiHdlDlHarq 
3104   *
3105   *     Function: rgSCHDrxTtiHdlUlHarqRTT 
3106   *
3107   *         Processing steps:
3108   *         - In addition per TTI DRX module must look at Downlink HARQ queues
3109  *             maintained to track HARQ RTT timer and drx-RetransmissionTimer.
3110  *             Every TTI at the scheduling index we shall check these queues and
3111  *             process accordingly. 
3112  *
3113  *             - Though these timers are related to downlink HARQ processing, they
3114  *             have an impact on uplink scheduling. The reason is that the UE,
3115  *             if active for downlink scheduling implies that it is reading
3116  *             PDCCHs i.e. we can still send uplink allocations to the UE. Hence
3117  *             every TTI Uplink too would look at the harqRTTQ and harqRetxQ. 
3118  *
3119  *
3120  *
3121  * @param  RgSchCellCb *cellCb
3122  * @param  U16          ulIndex
3123   * @return Void 
3124   */
3125
3126 #ifdef ANSI
3127 PRIVATE Void rgSCHDrxTtiHdlUlHarqRTT
3128 (
3129 RgSchCellCb          *cell,
3130 U16                   ulIndex
3131 )
3132 #else /* ANSI */
3133 PRIVATE Void rgSCHDrxTtiHdlUlHarqRTT(cell, ulIndex)
3134 RgSchCellCb          *cell;
3135 U16                   ulIndex;
3136 #endif /* ANSI */
3137 {
3138    CmLList             *node;
3139    RgSchDrxDlHqProcCb  *drxHq;
3140    RgSchDlHqProcCb     *dlHq;
3141    RgSchDRXCellCb      *drxCell;
3142    RgSchDrxUeCb        *drxUe;
3143    Bool              delInUlScan;
3144    RgSchUeCb          *ue;
3145    CmLListCp         ulInactvLst; /* list of UE's becoming DL-inactive */
3146    RgSchCmnCell      *cellSch = RG_SCH_CMN_GET_CELL(cell);
3147    U8                cellIdx;
3148    U32               ulInactvMask;
3149
3150
3151    TRC2(rgSCHDrxTtiHdlUlHarqRTT);
3152    
3153    drxCell     = cell->drxCb;
3154    delInUlScan = drxCell->delInUlScan;
3155
3156    cmLListInit(&ulInactvLst);
3157
3158    /***********************************************************
3159     *    Scanning harqRTTQ in UL 
3160     ***********************************************************/
3161
3162    /*
3163       Though these timers are related to downlink HARQ processing, they
3164       have an impact on uplink scheduling. The reason is that the UE,
3165       if active for downlink scheduling implies that it is reading
3166       PDCCHs i.e. we can still send uplink allocations to the UE. Hence
3167       every TTI Uplink too would look at the harqRTTQ and harqRetxQ. 
3168       */
3169
3170    node = drxCell->drxQ[ulIndex].harqRTTQ.first;
3171    while (node)
3172    {
3173       dlHq = (RgSchDlHqProcCb*)node->node;
3174       ue   = dlHq->hqE->ue;
3175       drxUe = RG_SCH_DRX_GET_UE(ue);
3176       node = node->next;
3177       drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
3178       cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
3179
3180       if ( delInUlScan == TRUE )
3181       {
3182          /* remove the harq proc from this queue--*/
3183          cmLListDelFrm (&(drxCell->drxQ[ulIndex].harqRTTQ), 
3184                &(drxHq->harqRTTEnt));
3185
3186          drxHq->rttIndx = DRX_INVALID;
3187       }
3188
3189       /* mark the ue as active for uplink--*/
3190       drxUe->drxUlInactvMask  &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3191       drxUe->drxUlInactvMaskPerCell[cellIdx]  &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3192
3193       /* Update UE's inactive mask and if required move UE to ACTIVE state */
3194       RG_SCH_CMN_UL_UPDT_INACTV_MASK( cell, ue, RG_DRX_INACTIVE);
3195    }
3196
3197    /***********************************************************
3198     *    Scanning harqRetxQ in UL 
3199     ***********************************************************/
3200    node = drxCell->drxQ[ulIndex].harqRetxQ.first;
3201    while (node)
3202    {
3203       dlHq  = (RgSchDlHqProcCb*)node->node;
3204       ue    = dlHq->hqE->ue;
3205       drxUe = RG_SCH_DRX_GET_UE(ue);
3206       drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
3207       cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
3208
3209       /*mark the ue as in-active for uplink*/
3210
3211       drxUe->drxUlInactvMaskPerCell[cellIdx]  |= (RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3212
3213       ulInactvMask = RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId;
3214
3215       for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
3216       {
3217          ulInactvMask &= drxUe->drxUlInactvMaskPerCell[cellIdx];
3218       }   
3219
3220       drxUe->drxUlInactvMask |= ulInactvMask; 
3221
3222       if(!RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
3223       {
3224          ue->ul.ulInactvMask |= (RG_DRX_INACTIVE);
3225
3226          cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
3227          ue->ulDrxInactvLnk.node  = (PTR)ue;
3228       }
3229
3230       /* remove the harq proc from this queue*/
3231       if ( delInUlScan == TRUE)
3232       {
3233          cmLListDelFrm (&(drxCell->drxQ[ulIndex].harqRetxQ),
3234                &(drxHq->harqRetxEnt));
3235          drxHq->reTxIndx = DRX_INVALID;
3236       }
3237
3238       node = node->next;
3239    }
3240    cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
3241
3242    RETVOID;
3243
3244 }
3245
3246 /**********************************************************************
3247  
3248          End of file
3249 **********************************************************************/