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