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