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