1 /*******************************************************************************
2 ################################################################################
3 # Copyright (c) [2017-2019] [Radisys] #
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 #
9 # http://www.apache.org/licenses/LICENSE-2.0 #
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 *******************************************************************************/
19 /************************************************************************
25 Desc: C source code for DRX realted functions
29 **********************************************************************/
31 /** @file rg_sch_drx.c
32 @brief This file implements the DRX processing .
35 static const char* RLOG_MODULE_NAME="MAC";
36 static int RLOG_MODULE_ID=4096;
37 static int RLOG_FILE_ID=163;
39 /* header include files -- defines (.h) */
40 #include "common_def.h"
46 #include "rg_sch_inf.h"
47 #ifdef LTEMAC_PH3_HDFDD
48 #include "rg_sch_hdfdd.h"
49 #endif /*LTEMAC_PH3_HDFDD*/
51 #include "rg_sch_err.h"
52 #include "rg_sch_cmn.h"
53 #include "rl_interface.h"
54 #include "rl_common.h"
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*/
66 #include "rg_sch.x" /* typedefs for Scheduler */
67 #include "rg_sch_cmn.x"
70 * @file rg_sch_drx.c This file gives the describes the design for DRX feature.
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.
78 * ACTIVE time MIN (onDuration) MAX (infinity)
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.
86 * <-ACTIVE-><---IN-ACTIVE------><-ACTIVE-><---IN-ACTIVE--
88 * |__|__|__|--------|__|__|__|__|__|__|__|--------|__|__|__|__|__|
89 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
94 /******************************************************************************
95 * Structure definitions for TDD *
96 ******************************************************************************/
98 /** @brief : No of DL subframes in a particular TDD configuration
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.
112 static uint8_t rgSchDrxDlSfTddCfg[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG] =
118 /** @brief : No of DL subframes till next SFN from a particular subframe
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
127 static uint8_t rgSchDrxDLSfTillNxtSFN[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG]
128 [RGSCH_NUM_SUB_FRAMES]=
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}
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}
149 }; /*rgSchDrxDLSfTillNxtSFN*/
152 /** @brief : Lookup table for DL subframe given the number of subframes
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
160 static uint8_t rgSchDrxDLSftoDLSfIdx[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG]
161 [RGSCH_NUM_SUB_FRAMES]=
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
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},
197 /******************************************************************************
198 * Start of Function declarations *
199 ******************************************************************************/
200 static Void rgSCHDrxTtiHdlOnDurUl ARGS((
204 static Void rgSCHDrxTtiHdlOnDurDl ARGS((
208 static Void rgSCHDrxTtiHdlDlHarqRTT ARGS((
212 static Void rgSCHDrxTtiHdlUlHarqRTT ARGS((
216 static S16 rgSCHDrxTtiHdlOnDur ARGS((RgSchCellCb *cellCb, uint16_t dlIndex,
218 static S16 rgSCHDrxTtiHdlInActv ARGS((RgSchCellCb *cellCb, uint16_t dlIndex,
220 static S16 rgSCHDrxTtiHdlShortCycle ARGS((RgSchCellCb *cell, uint16_t dlIndex,
222 static S16 rgSCHDrxTtiHdlDlHarq ARGS((RgSchCellCb *cellCb, uint16_t dlIndex,
224 static S16 rgSCHDrxCpyUeCfg ARGS((RgSchDrxUeCb *drxCb,
225 RgrUeDrxCfg* ueDrxCfg));
227 static S16 rgSCHDrxGetNxtOnDur ARGS((RgSchCellCb* cell,RgSchDrxUeCb* drxCb,
228 CmLteTimingInfo* nxtOnDur,
231 static Void rgSCHDrxMvToNxtOnDurOcc ARGS((RgSchCellCb* cell,
236 static Void rgSCHDrxCalcNxtTmrExpry ARGS((RgSchCellCb *cell,
243 static S16 rgSCHDrxGetNxtTmrExpry ARGS((RgSchCellCb *cell,uint16_t curTime,
245 CmLteTimingInfo* tmrExpryIdx));
248 S16 rgSCHEmtcDrxCpyUeCfg
253 S16 rgSCHDrxTtiHdlUlHarq
259 Void rgSCHDrxUeUlHqReset
268 /** @brief This function handles the per TTI handling of the DRX module.
269 * Invoked by rgSCHTti @sa rgSCHTti.
271 * @details This function goes through the drxQ and marks the UE as ACTIVE or
272 * INACTIVE based on the timers and thier status.
274 * Function: rgSCHDrxTtiInd
277 * - Processing is divided into respective timer handling.
278 * - Calculate the DL and UL indices as follows
280 * dlIndex = (cell->crntTime.sfn * 10 + cell->crntTime.slot +
281 * RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
283 * ulIndex = (cell->crntTime.sfn * 10 + cell->crntTime.slot +
284 * RG_SCH_DRX_UL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
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
291 * - Call rgSchDrxTtiHdlUlHarq to handle Uplink HARQ processing -
292 * related to ACTIVITY when a UE is expecting a grant for an uplink
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.
300 * @param RgSchCellCb *cell
301 * @param [out] CmLListCp *dlInactvLst List to which the DL in-active UEs are
305 Void rgSCHDrxTtiInd(RgSchCellCb *cell)
310 dlIndex = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot +
311 RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
313 ulIndex = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot +
314 RG_SCH_DRX_UL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
317 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex);
318 /* checks the Ul-Retransmission timer */
322 rgSCHDrxTtiHdlUlHarq (cell, dlIndex, ulIndex);
325 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex);
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);
333 rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex);
334 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex);
335 /* checks the Ul-Retransmission timer */
339 rgSCHDrxTtiHdlUlHarq (cell, dlIndex, ulIndex);
342 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex);
343 rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex);
351 /** @brief This function is called to handle onDurationTimer per TTI processing.
354 * Invoked by - rgSCHDrxTtiInd
356 * Function: rgSCHDrxTtiHdlOnDur
360 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
362 * - For Downlink we shall look at an index that is
363 * n + RG_SCH_DRX_DL_DELTA.
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.
371 * @param RgSchCellCb *cellCb
372 * @param uint16_t dlIndex
373 * @param uint16_t ulIndex
374 * @return ROK/RFAILED
377 static S16 rgSCHDrxTtiHdlOnDur(RgSchCellCb *cell,uint16_t dlIndex,uint16_t ulIndex)
380 #if ( ERRCLASS & ERRCLS_INT_PAR )
381 if ( cell == (RgSchCellCb* )NULLP )
387 rgSCHDrxTtiHdlOnDurDl(cell,dlIndex);
389 rgSCHDrxTtiHdlOnDurUl(cell, ulIndex);
393 }/*rgSCHDrxTtiHdlOnDur*/
396 /** @brief This function handles the processing for drxInactityTimer per TTI
399 * Invoked by - rgSCHDrxTtiInd
401 * Function: rgSCHDrxTtiHdlInActv
405 * - For Downlink we shall look at an index that is
406 * n + RG_SCH_DRX_DL_DELTA of the drxQ.
408 * - MARK UE AS INACTIVE BASED ON DRX-INACTIVITY TIMER EXPIRY
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.
416 * @param RgSchCellCb *cellCb
417 * @param uint16_t dlIndex
418 * @param uint16_t ulIndex
419 * @return ROK/RFAILED
422 S16 rgSCHDrxTtiHdlInActv(RgSchCellCb *cell,uint16_t dlIndex,uint16_t ulIndex)
425 RgSchDRXCellCb *drxCell=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;
434 #if ( ERRCLASS & ERRCLS_INT_PAR )
435 if ( cell == (RgSchCellCb* )NULLP)
442 drxCell = (cell->drxCb);
443 delInUlScan = drxCell->delInUlScan;
446 /***********************************************************
447 * Scanning inActvitiyQ in DL
448 ***********************************************************/
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
457 node = drxCell->drxQ[dlIndex].inActvTmrQ.first;
459 /* Initialize DL inactive list */
460 cmLListInit(&dlInactvLst);
462 /* Initialize UL inactive list */
463 cmLListInit(&ulInactvLst);
467 ue = (RgSchUeCb*)node->node;
469 drxUe = RG_SCH_DRX_GET_UE(ue);
471 if ( delInUlScan == TRUE)
473 drxUe->drxInactDistance--;
476 if ( drxUe->drxInactDistance != DRX_TMR_EXPRD )
481 /* UE is inactive as inactivity timer has expired */
482 drxUe->drxDlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
485 /* update the ue mask only if no condition in drx
486 * is keeping ue active
488 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
490 /* set the UE has DRX inactive */
491 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
493 /* Add to DL inactive list */
494 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
495 ue->dlDrxInactvLnk.node = (PTR)ue;
498 /*Remove from the queue if !delInUlScan */
499 if( delInUlScan == FALSE )
501 cmLListDelFrm(&(drxCell->drxQ[dlIndex].inActvTmrQ),
502 &(drxUe->inActvTmrEnt));
504 drxUe->drxInactvIndx = DRX_INVALID;
506 }/* if (delInUlScan == FALSE) */
508 if (drxUe->isShortCycleCfgd)
510 /* add shorty cycle expirty */
511 drxUe->isLongCycle = FALSE;
513 shrtCycleExpIndx = (dlIndex + (drxUe->shortCycleTmrLen *
514 drxUe->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
516 drxUe->drxShortCycleDistance = (drxUe->shortCycleTmrLen *
517 drxUe->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
519 /*Remove the UE from existing index*/
520 if (drxUe->shortCycleIndx != DRX_INVALID)
522 cmLListDelFrm(&(drxCell->drxQ[drxUe->shortCycleIndx].shortCycleQ),
523 &(drxUe->shortCycleEnt));
526 cmLListAdd2Tail(&(drxCell->drxQ[shrtCycleExpIndx].shortCycleQ),
527 &(drxUe->shortCycleEnt));
529 drxUe->shortCycleEnt.node = (PTR)ue;
530 drxUe->shortCycleIndx = shrtCycleExpIndx;
532 /*Calculate onDuration again & move the
533 * ueCb to the next Onduration occurence
536 /*we maybe at any position in the RF timeline,
537 * need to calculate onDuration from the starting
540 rgSCHDrxMvToNxtOnDurOcc(cell,ue,RG_SCH_DRX_DL_DELTA,TRUE);
542 }/*isShortCycleCfgd */
545 /* use the long cycle */
546 drxUe->isLongCycle = TRUE;
552 /***********************************************************
553 * Scanning inActvitiyQ in UL
554 ***********************************************************/
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
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.*/
567 node = drxCell->drxQ[ulIndex].inActvTmrQ.first;
572 ue = (RgSchUeCb*)node->node;
574 drxUe = RG_SCH_DRX_GET_UE(ue);
576 if ( delInUlScan == FALSE)
578 drxUe->drxInactDistance--;
581 if ( drxUe->drxInactDistance != DRX_TMR_EXPRD )
586 /* Need to mark the UE as inactive due to expiry of
587 * DRX inactivity timer */
589 /* UE is inactive as inactivity timer has expired */
590 drxUe->drxUlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
592 /* update the ue mask only if no other condition in
593 * drx is keeping ue active */
595 if (!RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
597 /* set the inactivity bit */
598 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
600 /* Add to Ul inactive list */
601 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
602 ue->ulDrxInactvLnk.node = (PTR)ue;
605 if ( delInUlScan == TRUE)
607 /* remove from queue */
608 cmLListDelFrm(&(drxCell->drxQ[ulIndex].inActvTmrQ),
609 &(drxUe->inActvTmrEnt));
611 drxUe->drxInactvIndx = DRX_INVALID;
613 }/* if ( delInUlScan == TRUE) */
614 }/*while(node) for uplink */
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);
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);
626 }/*rgSCHDrxTtiHdlInActv*/
628 /** @brief This function handles the per TTI processing for DRX short cycle
632 * Invoked by - rgSCHDrxTtiInd
634 * Function: rgSCHDrxTtiHdlShortCycle
639 * in addition we have to mark the ues based on drx short cycle
643 * @param RgSchCellCb *cell
644 * @param uint16_t dlIndex
645 * @param uint16_t ulIndex
646 * @return ROK/RFAILED
649 S16 rgSCHDrxTtiHdlShortCycle(RgSchCellCb *cell,uint16_t dlIndex,uint16_t ulIndex)
652 RgSchDRXCellCb *drxCell=NULLP;
654 RgSchDrxUeCb *drxUe=NULLP;
656 #if ( ERRCLASS & ERRCLS_INT_PAR )
657 if ( cell == (RgSchCellCb* )NULLP )
666 drxCell = RG_SCH_DRX_GET_CELL(cell);
668 node = drxCell->drxQ[dlIndex].shortCycleQ.first;
672 ue = (RgSchUeCb*)node->node;
674 drxUe = RG_SCH_DRX_GET_UE(ue);
676 if ( --drxUe->drxShortCycleDistance != DRX_TMR_EXPRD)
681 /* mark the UE's current cycle to be long */
682 drxUe->isLongCycle = TRUE;
684 /* remove from the shortCycleQ */
686 cmLListDelFrm(&(drxCell->drxQ[dlIndex].shortCycleQ),
687 &(drxUe->shortCycleEnt));
688 drxUe->shortCycleIndx = DRX_INVALID;
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);
696 }/*rgSCHDrxTtiHdlShortCycle*/
699 /** @brief This function handles the HARQ timer's processing per TTI.
702 * Invoked by - rgSCHDrxTtiInd
704 * Function: rgSCHDrxTtiHdlDlHarq
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.
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.
721 * @param RgSchCellCb *cellCb
722 * @param uint16_t dlIndex
723 * @param uint16_t ulIndex
724 * @return ROK/RFAILED
727 static S16 rgSCHDrxTtiHdlDlHarq(RgSchCellCb *cell,uint16_t dlIndex,uint16_t ulIndex)
730 #if ( ERRCLASS & ERRCLS_INT_PAR)
731 if ( cell == (RgSchCellCb *)NULLP )
735 #endif /*ERRCLASS & ERRCLS_INT_PAR*/
738 rgSCHDrxTtiHdlDlHarqRTT(cell, dlIndex);
740 rgSCHDrxTtiHdlUlHarqRTT(cell, ulIndex);
745 /** @brief This function is called by the common scheduler as part of
746 * finalization of allocations in downlink.
751 * Function: rgSchDrxStrtInActvTmr
753 * This function is responsible to starting drx-InactivityTimer
758 * @param RgSchCellCb *cell
759 * @param CmLListCp *ueUlLst
760 * @param uint8_t direction
764 Void rgSCHDrxStrtInActvTmr(RgSchCellCb *cell,CmLListCp *ueLst,uint8_t direction)
769 RgSchDrxUeCb *ueDrxCb;
773 uint16_t inActvTmrExpIndx;
775 uint16_t curTimeInSf; /* current time in number of subframes */
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;
785 if ( direction == RG_SCH_DRX_UL)
788 curTimeInSf = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
789 (cell->crntTime.slot) +RG_SCH_DRX_UL_DELTA;
793 delta = RG_SCH_DRX_UL_DELTA;
799 curTimeInSf = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
800 (cell->crntTime.slot) + RG_SCH_DRX_DL_DELTA;
804 delta = RG_SCH_DRX_DL_DELTA;
809 /* Initialize DL inactive list */
810 cmLListInit(&dlInactvLst);
812 /* Initialize UL inactive list */
813 cmLListInit(&ulInactvLst);
815 delInUlScan = cell->drxCb->delInUlScan;
818 index1 = (curTimeInSf) % RG_SCH_MAX_DRXQ_SIZE;
825 ueCb = (RgSchUeCb *)node->node;
826 ueDrxCb = ueCb->drxCb;
828 /* Stop inactivity timer */
829 if ( ueDrxCb->drxInactvIndx != DRX_INVALID )
831 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->drxInactvIndx].inActvTmrQ),
832 &(ueDrxCb->inActvTmrEnt));
836 rgSCHDrxCalcNxtTmrExpry(cell,
839 ueDrxCb->inactvtyTmrLen,
840 &(ueDrxCb->drxInactDistance),
845 inActvTmrExpIndx = (index1 + ueDrxCb->inactvtyTmrLen)
846 % RG_SCH_MAX_DRXQ_SIZE;
848 ueDrxCb->drxInactDistance = ueDrxCb->inactvtyTmrLen
849 / RG_SCH_MAX_DRXQ_SIZE;
852 cmLListAdd2Tail(&(cell->drxCb->drxQ[inActvTmrExpIndx].inActvTmrQ),
853 &(ueDrxCb->inActvTmrEnt));
855 ueDrxCb->inActvTmrEnt.node = (PTR)ueCb;
857 ueDrxCb->drxInactvIndx = inActvTmrExpIndx;
859 /* Update DRX InActive both masks */
860 ueDrxCb->drxUlInactvMask &= ~RG_SCH_DRX_INACTVTMR_BITMASK;
861 ueDrxCb->drxDlInactvMask &= ~RG_SCH_DRX_INACTVTMR_BITMASK;
863 /* Update UE's Inactive masks */
864 ueCb->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
865 ueCb->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
867 if ( delInUlScan == TRUE)
869 if ( ueDrxCb->inactvtyTmrLen == RGR_DRX_PRD_1PSF)
871 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
872 ueDrxCb->drxDlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
874 /* if no other condition is keeping ue inactive,
877 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(ueDrxCb) )
879 ueCb->dl.dlInactvMask |= RG_DRX_INACTIVE;
881 /* Add to DL inactive list */
882 cmLListAdd2Tail(&dlInactvLst,&(ueCb->dlDrxInactvLnk));
883 ueCb->dlDrxInactvLnk.node = (PTR)ueCb;
885 }/*if ( ueDrxCb->inactvyTmrLen...*/
887 }/*delInUlScan==TRUE*/
890 if ( ueDrxCb->inactvtyTmrLen == RGR_DRX_PRD_1PSF )
892 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
893 ueDrxCb->drxUlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
894 /* if no other condition is keeping ue inactive,
897 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(ueDrxCb) )
899 ueCb->ul.ulInactvMask |= RG_DRX_INACTIVE;
901 if ( !RG_SCH_CMN_UL_IS_UE_ACTIVE(ueCb))
903 /* Add to UL inactive list */
904 cmLListAdd2Tail(&ulInactvLst,&(ueCb->ulDrxInactvLnk));
905 ueCb->ulDrxInactvLnk.node = (PTR)ueCb;
907 }/*if ( !RG_SCH_DRX....)*/
908 }/*if (ueDrxCb->inactv...*/
911 /* move the link list forward */
915 cmLListDelFrm(ueLst, delNode);
916 delNode->node = NULLP;
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);
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);
929 }/*rgSCHDrxStrtInActvTmr*/
931 /** @brief This function is called by the downlink HARQ module on receiving a
932 * negative feedback from the UE for a PDSCH transmission.
935 * Invoked by - rgSCHDhmHqTrnsFail
937 * Function: rgSCHDrxStartHarqRTTTmr
942 * @param RgSchCellCb *cell
943 * @param RgSchDlHqProcCb *dlHq
944 * @param uint8_t tbCnt
947 Void rgSCHDrxStartHarqRTTTmr(RgSchCellCb *cell,RgSchDlHqProcCb *hqP,uint8_t tbCnt)
949 RgSchDRXCellCb *drxCell =NULLP;
950 RgSchDrxDlHqProcCb *drxHq =NULLP;
951 uint16_t harqRTTExpIndx;
954 uint8_t firstDlTxOcassion;
955 uint8_t drxRetxTmrStartSf;
958 drxCell = RG_SCH_DRX_GET_CELL(cell);
959 drxHq = RG_SCH_DRX_GET_DL_HQ(hqP);
962 /* ccpu00134196-[Add]-DRX retx timer changes */
963 firstDlTxOcassion = rgSchDrxHarqRetxFirstPsf[cell->ulDlCfgIdx]
964 [hqP->tbInfo[tbCnt].fdbkTime.subframe];
966 harqRTTExpIndx = ((hqP->tbInfo[tbCnt].fdbkTime.sfn * 10) +
967 hqP->tbInfo[tbCnt].fdbkTime.subframe + firstDlTxOcassion)
968 % RG_SCH_MAX_DRXQ_SIZE;
970 fdbkDelta = RGSCH_CALC_SF_DIFF(cell->crntTime, hqP->tbInfo[tbCnt].fdbkTime);
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;
981 fdbkDelta = RGSCH_CALC_SF_DIFF(cell->crntTime, hqP->tbInfo[tbCnt].timingInfo);
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*/
990 if(fdbkDelta + RG_SCH_DRX_DL_DELTA >= firstDlTxOcassion)
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;
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;
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++)
1008 if (rgSchTddUlDlSubfrmTbl[cell->ulDlCfgIdx]
1009 [(drxRetxTmrStartSf+i)%RGSCH_NUM_SUB_FRAMES]
1010 != RG_SCH_TDD_UL_SUBFRAME)
1012 drxHq->retxTmrReduction++;
1016 if(fdbkDelta + RG_SCH_DRX_DL_DELTA >= RG_SCH_MIN_HARQ_RTT)
1018 drxHq->retxTmrReduction =
1019 fdbkDelta + RG_SCH_DRX_DL_DELTA - RG_SCH_MIN_HARQ_RTT+ 1;
1022 harqRTTExpIndx = (harqRTTExpIndx + drxHq->retxTmrReduction) %
1023 RG_SCH_MAX_DRXQ_SIZE;
1027 drxHq->retxTmrReduction = 0;
1029 cmLListAdd2Tail (&(drxCell->drxQ[harqRTTExpIndx].harqRTTQ),
1030 &(drxHq->harqRTTEnt));
1032 drxHq->harqRTTEnt.node = (PTR)hqP;
1033 drxHq->rttIndx = harqRTTExpIndx;
1037 }/*rgSCHDrxStartHarqRTTTmr*/
1040 /** @brief This function is called by the Configuration module to give a
1041 * trigger to DRX module for UE configuration.
1045 * Function: rgSCHDrxUeCfg
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).
1055 * @param RgSchCellCb *cell Cell control block.
1056 * @param RgSchUeCb *ue UE control block.
1057 * @param RgrUeCfg *ueCfg RGR UE configuration information.
1062 S16 rgSCHDrxUeCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeCfg *ueCfg)
1065 RgSchDrxUeCb *ueDrxCb;
1066 CmLteTimingInfo nxtOnDur;
1068 uint16_t nxtOnDurTime;
1073 #if ( ERRCLASS & ERRCLS_INT_PAR )
1074 if ( cell == (RgSchCellCb* )NULLP)
1079 if ((ue == (RgSchUeCb* )NULLP)
1081 (ueCfg == (RgrUeCfg* )NULLP))
1083 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId, "rgSCHDrxUeCfg():"
1084 "Invalid params.cell or ue or ueCfg is NULL ");
1090 /* allocate and initialize drxCb */
1091 ret = rgSCHUtlAllocSBuf(cell->instIdx, (Data**)&ue->drxCb,
1092 (sizeof(RgSchDrxUeCb)));
1096 RLOG_ARG1(L_ERROR,DBG_CELLID,cell->cellId,
1097 "Memory allocation FAILED for DRX UECB CRBTI:%d",ue->ueId);
1101 ueDrxCb = ue->drxCb;
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;
1109 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1111 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1112 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1115 /* Copy the configuration values into the UE's DRX CB. */
1116 rgSCHDrxCpyUeCfg (ueDrxCb, &ueCfg->ueDrxCfg);
1120 rgSCHEmtcDrxCpyUeCfg(ue ,&ueCfg->ueDrxCfg);
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;
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;
1136 /* Mark the UE in long/short cycle initially as per configuration*/
1137 if(FALSE == ueDrxCb->isShortCycleCfgd)
1139 ueDrxCb->isLongCycle = TRUE;
1143 ueDrxCb->isLongCycle = FALSE;
1146 /* Calculate the next occurance from this point */
1147 rgSCHDrxGetNxtOnDur (cell, ueDrxCb, &nxtOnDur,RG_SCH_NO_DELTA);
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);
1154 onDurIndx = nxtOnDurTime % RG_SCH_MAX_DRXQ_SIZE;
1156 ueDrxCb->distance = (nxtOnDurTime - curTime) / RG_SCH_MAX_DRXQ_SIZE;
1157 if (ueDrxCb->distance < 0)
1159 RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId, "DRXUE. Invalid "
1160 "value for distance, %d CRNTI:%d", ueDrxCb->distance,ue->ueId);
1162 //printf("The onduartion index is: %d\n",(int)onDurIndx);
1163 cmLListAdd2Tail(&(cell->drxCb->drxQ[onDurIndx].onDurationQ),
1164 &(ueDrxCb->onDurationEnt));
1166 ueDrxCb->onDurationEnt.node = (PTR)ue;
1167 ueDrxCb->onDurIndx = onDurIndx;
1169 /* Starting Short Cycle Timer */
1170 if(TRUE == ueDrxCb->isShortCycleCfgd)
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;
1182 } /* end of rgSCHDrxUeCfg */
1184 /** @brief This function gets the next occurance of onDurationTimer from the
1187 * @details rgSCHDrxGetNxtOnDur
1189 * Function: rgSCHDrxGetNxtOnDur
1191 * Processing steps: -
1192 * Calculation of first occurance of onDuration is to be done as
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.
1199 * (sfn * 10 + subframe) mod perd = offset
1204 * @param RgSchCellCb *cell
1205 * @param RgSchDrxUeCb *drxCb
1206 * @param CmLteTimingInfo *nxtOnDur
1207 * @param uint8_t delta
1208 * @return ROK/RFAILED
1210 static S16 rgSCHDrxGetNxtOnDur(RgSchCellCb *cell,RgSchDrxUeCb *drxCb,CmLteTimingInfo *nxtOnDur,uint8_t delta)
1215 uint32_t numOfCycles;
1219 #if ( ERRCLASS & ERRCLS_INT_PAR )
1220 if ( cell == (RgSchCellCb* )NULLP )
1225 if( (drxCb == (RgSchDrxUeCb* )NULLP)
1227 (nxtOnDur == (CmLteTimingInfo* )NULLP)
1230 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
1231 "rgSCHDrxGetNxOnDur():Invalid params."
1232 "cell/drxCb/nxtOnDur is NULL");
1238 if (TRUE == drxCb->isLongCycle)
1240 cycleLen = drxCb->longDrxCycle;
1244 cycleLen = drxCb->shortDrxCycle;
1247 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) + cell->crntTime.slot);
1249 curTime += delta; /*TODO: see if we need to take care of wrap arounds */
1251 if ( curTime <= drxCb->drxStartOffset )
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);
1260 curDist = curTime - drxCb->drxStartOffset;
1262 numOfCycles = curDist / cycleLen;
1264 if (0 == (curDist % cycleLen))
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);
1275 nxtDist = drxCb->drxStartOffset + (numOfCycles + 1) *
1277 nxtOnDur->sfn = (uint16_t)nxtDist / RGSCH_NUM_SUB_FRAMES_5G;
1278 nxtOnDur->slot = (uint16_t)nxtDist % RGSCH_NUM_SUB_FRAMES_5G;
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)
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;
1292 } /* end of rgSCHDrxGetNxtOnDur */
1294 /** @brief This function is a utility function to copy the UE configuration from
1295 * the RGR structure to the UE control block.
1298 * -Invoked by rgSCHDrxUeCfg
1300 * Function: rgSCHDrxCpyUeCfg
1303 * - Copies configuration values
1305 * @param RgSchDrxUeCb *ueCb
1306 * @param RgrUeDrxCfg *drxCfg
1307 * @return ROK/RFAILED
1309 static S16 rgSCHDrxCpyUeCfg(RgSchDrxUeCb *ueCb,RgrUeDrxCfg *drxCfg)
1312 #if ( ERRCLASS & ERRCLS_INT_PAR )
1313 if ( (ueCb == (RgSchDrxUeCb* )NULLP )
1315 (drxCfg == (RgrUeDrxCfg* )NULLP)
1323 /* Copy all values to UE control block */
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;
1337 } /* end of rgSCHDrxCpyUeCfg */
1340 /** @brief This function is called by the configuration module when a UE is
1341 * reconfigured for DRX parameters.
1344 * Invoked By - rgSCHCfgRgrUeCfg
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.
1351 * - if offset and/or drxCycleLenght changes then recalculate the next
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
1358 * @param RgSchCellCb *cell
1359 * @param RgSchUeCb *ue
1360 * @param RgrUeRecfg *ueReCfg
1361 * @return ROK/RFAILED
1363 S16 rgSCHDrxUeReCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeRecfg *ueReCfg)
1366 RgSchCmnCell *cellSch = NULLP;
1367 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
1369 Inst instIdx = cell->instIdx;
1370 RgSchDrxUeCb *ueDrxCb;
1371 CmLteTimingInfo nxtOnDur;
1372 uint16_t nxtOnDurTime;
1375 uint16_t shrtCycleExpIndx;
1376 uint16_t onDurExpTime;
1382 /* drx was disabled but now enabled for this ue */
1383 if ( (ue->isDrxEnabled == FALSE)
1385 (ueReCfg->ueDrxRecfg.isDrxEnabled == TRUE)
1388 /* allocated and initialize drxCb */
1389 ret = rgSCHUtlAllocSBuf(instIdx, (Data**)&ue->drxCb,
1390 (sizeof(RgSchDrxUeCb)));
1394 RLOG_ARG1(L_ERROR,DBG_CELLID,cell->cellId,
1395 "rgSCHdrxUeReCfg():""Memory allocation FAILED for DRX UE Cb CRNTI:%d",
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;
1407 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1409 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1410 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
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;
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;
1426 if( ue->drxCb == NULLP )
1430 ueDrxCb = ue->drxCb;
1432 /*drx was enabled but now disabled for this UE */
1433 if ( (ue->isDrxEnabled == TRUE )
1435 (ueReCfg->ueDrxRecfg.isDrxEnabled == FALSE)
1438 /* remove UE from all DRX Queues */
1439 (Void)rgSCHDrxUeDel(cell,ue);
1442 /* ccpu00117052 - MOD - Passing double pointer
1443 for proper NULLP assignment*/
1444 rgSCHUtlFreeSBuf(instIdx,(Data **)(&((ue->drxCb))),
1445 sizeof(RgSchDrxUeCb));
1447 /* Resetting the DRX Bit set in Inactv Mask */
1448 ue->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
1449 ue->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
1451 ue->isDrxEnabled = FALSE;
1453 }/*isDrxEnabled == FALSE */
1456 /* If Application is updating DRX params */
1457 if (ueReCfg->ueRecfgTypes & RGR_UE_DRX_RECFG )
1459 rgSCHDrxCpyUeCfg (ueDrxCb, &ueReCfg->ueDrxRecfg);
1463 rgSCHEmtcDrxCpyUeCfg(ue, &ueReCfg->ueDrxRecfg);
1469 /* Removing the UE from existing index of shortcycle, if any*/
1470 if(ueDrxCb->shortCycleIndx != DRX_INVALID)
1472 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1473 &(ueDrxCb->shortCycleEnt));
1475 ueDrxCb->shortCycleEnt.node = (PTR) NULLP;
1476 ueDrxCb->shortCycleIndx = DRX_INVALID;
1479 /* Mark for intiating long/short cycle as per received config */
1480 if(FALSE == ue->drxCb->isShortCycleCfgd)
1482 ue->drxCb->isLongCycle = TRUE;
1486 ue->drxCb->isLongCycle = FALSE;
1489 /* Calculate the next occurance from this point */
1490 rgSCHDrxGetNxtOnDur (cell, ueDrxCb, &nxtOnDur,RG_SCH_NO_DELTA);
1492 /* remove the UE from the current onDuration Queue */
1493 if ( ueDrxCb->onDurIndx != DRX_INVALID )
1495 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurIndx].onDurationQ),
1496 &(ueDrxCb->onDurationEnt));
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);
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))
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,
1514 /* Manipulating the time when old onDuration timer can expire */
1515 if(curIndx >= ueDrxCb->onDurExpIndx)
1517 onDurExpTime = curTime + ((ueDrxCb->onDurExpDistance+1) * RG_SCH_MAX_DRXQ_SIZE)+ (ueDrxCb->onDurExpIndx - curIndx + RG_SCH_DRX_DL_DELTA);
1521 onDurExpTime = curTime + (ueDrxCb->onDurExpDistance * RG_SCH_MAX_DRXQ_SIZE)+ (ueDrxCb->onDurExpIndx - curIndx + RG_SCH_DRX_DL_DELTA);
1524 if(nxtOnDurTime <= onDurExpTime)
1526 if(ueDrxCb->isLongCycle)
1528 cycleLen = ueDrxCb->longDrxCycle;
1532 cycleLen = ueDrxCb->shortDrxCycle;
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 ;
1539 /* Add the UE to the index which corresponds to the next onduration start*/
1540 onDurIndx = nxtOnDurTime % RG_SCH_MAX_DRXQ_SIZE;
1542 ueDrxCb->distance = (nxtOnDurTime - curTime) / RG_SCH_MAX_DRXQ_SIZE;
1543 if (ueDrxCb->distance < 0)
1545 RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId,"DRXUE. Invalid "
1546 "value for distance, %d CRNTI:%d", ueDrxCb->distance,ue->ueId);
1549 cmLListAdd2Tail(&(cell->drxCb->drxQ[onDurIndx].onDurationQ),
1550 &(ueDrxCb->onDurationEnt));
1552 ueDrxCb->onDurationEnt.node = (PTR)ue;
1553 ueDrxCb->onDurIndx = onDurIndx;
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);
1565 /* Starting short cycle timer as per the existence of old onDuration timer */
1566 if(TRUE == ueDrxCb->isShortCycleCfgd)
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;
1582 } /* end of rgSCHDrxUeReCfg */
1585 /** @brief This function Loop through the list of HARQ processes for this
1586 * UE and delete from the harqRTTQ and harqRetxQ
1588 * Function: rgSCHDrxUeHqReset
1589 * Invoked by rgSCHDrxUeDel
1592 Loop through the list of HARQ processes for this UE and delete from
1593 * the harqRTTQ and harqRetxQ.
1595 * @param RgSchCellCb *cell
1596 * @return ROK/RFAILED
1598 Void rgSCHDrxUeHqReset(RgSchCellCb *cell,RgSchUeCb *ue,RgSchDlHqEnt *hqE,uint8_t cellIdx)
1600 RgSchDlHqProcCb *hqP;
1601 RgSchDrxDlHqProcCb *drxHq =NULLP;
1604 for(i=0; i < hqE->numHqPrcs; i++)
1606 hqP = &hqE->procs[i];
1607 drxHq = RG_SCH_DRX_GET_DL_HQ(hqP);
1609 if(drxHq->rttIndx != DRX_INVALID)
1611 cmLListDelFrm (&(cell->drxCb->drxQ[drxHq->rttIndx].harqRTTQ),
1612 &(drxHq->harqRTTEnt));
1614 drxHq->rttIndx = DRX_INVALID;
1617 if(drxHq->reTxIndx != DRX_INVALID)
1619 cmLListDelFrm (&(cell->drxCb->drxQ[drxHq->reTxIndx].harqRetxQ),
1620 &(drxHq->harqRetxEnt));
1622 drxHq->reTxIndx = DRX_INVALID;
1626 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1627 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1630 /** @brief This function Deletes DRX specific context for a UE.
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
1638 * Function: rgSCHDrxUeDel
1639 * Invoked by rgSCHCfgRgrUeDel
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.
1650 * @param RgSchCellCb *cell
1651 * @param RgSchUeCb *ue
1652 * @return ROK/RFAILED
1654 S16 rgSCHDrxUeDel(RgSchCellCb *cell,RgSchUeCb *ue)
1656 RgSchDrxUeCb *ueDrxCb;
1657 RgSchDlHqEnt *hqE = NULLP;
1659 RgSchUeCellInfo *cellInfo = NULLP;
1661 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
1665 /* ccpu00129899: Moved the drx-enabled check to the caller */
1666 ueDrxCb = ue->drxCb;
1668 /* Remove UE from all queues */
1669 if ( ueDrxCb->onDurIndx != DRX_INVALID )
1671 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurIndx].onDurationQ),
1672 &(ueDrxCb->onDurationEnt));
1674 ueDrxCb->onDurIndx = DRX_INVALID;
1677 if ( ueDrxCb->onDurExpIndx != DRX_INVALID )
1679 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurExpIndx].onDurationExpQ),
1680 &(ueDrxCb->onDurationExpEnt));
1682 ueDrxCb->onDurExpIndx = DRX_INVALID;
1685 if ( ueDrxCb->drxInactvIndx != DRX_INVALID )
1687 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->drxInactvIndx].inActvTmrQ),
1688 &(ueDrxCb->inActvTmrEnt));
1690 ueDrxCb->drxInactvIndx = DRX_INVALID;
1693 if ( ueDrxCb->shortCycleIndx != DRX_INVALID )
1695 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1696 &(ueDrxCb->shortCycleEnt));
1698 ueDrxCb->shortCycleIndx = DRX_INVALID;
1701 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1703 cellInfo = ue->cellInfo[cellIdx];
1707 hqE = cellInfo->hqEnt;
1708 rgSCHDrxUeHqReset(cell, ue, hqE, cellIdx);
1714 rgSCHDrxUeUlHqReset(cell, ue, &(ueUl->hqEnt));
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;
1726 /** @brief This function is called at the time of RGR cell configuration.
1729 * Invoked by - rgSCHCfgRgrCellCfg
1731 * Function: rgSCHDrxCellCfg
1734 * - Initializes the following drxQ (memset would do).
1737 * @param RgSchCellCb *cell
1738 * @param RgrCellCfg *cellCfg
1739 * @return ROK/RFAILED
1741 S16 rgSCHDrxCellCfg(RgSchCellCb *cell,RgrCellCfg *cellCfg)
1745 Inst instIdx = cell->instIdx;
1747 #if ( ERRCLASS & ERRCLS_INT_PAR )
1748 /*KWORK_FIX :Removed check for cell being NULL*/
1749 if( (cellCfg == (RgrCellCfg* )NULLP))
1751 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
1752 "rgSCHDrxCellCfg():Invalid Params. cell/cellCfg is NULL");
1757 /* allocate and initialize drxCb */
1758 ret = rgSCHUtlAllocSBuf(instIdx, (Data**)&cell->drxCb,
1759 (sizeof(RgSchDRXCellCb)));
1763 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,"rgSCHDrxCellCfg():"
1764 "Memory allocation FAILED for DRX cell Cb");
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.*/
1776 if ( RG_SCH_DRX_UL_DELTA > RG_SCH_DRX_DL_DELTA )
1778 cell->drxCb->delInUlScan = FALSE;
1782 cell->drxCb->delInUlScan = TRUE;
1786 } /* end of rgSchDrxCellCfg */
1790 /** @brief This function to delete DRX specific context in the cell control
1794 * Invoked by - rgSCHCfgRgrCellDel
1796 * Function: rgSCHDrxCellDel
1799 * - De-Inits RgSchDRXCellCb (Nothing to be done)
1800 * - Assumption: The API is invoked after deletion of UEs from the cell.
1802 * @param RgSchCellCb *cell
1805 Void rgSCHDrxCellDel(RgSchCellCb *cell)
1807 Inst instIdx = cell->instIdx;
1811 /* ccpu00117052 - MOD - Passing double pointer
1812 for proper NULLP assignment*/
1813 rgSCHUtlFreeSBuf(instIdx, (Data **)(&(cell->drxCb)),
1814 sizeof(RgSchDRXCellCb));
1817 } /* end of rgSchDrxCellDel */
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
1824 * Invoked by - rgSCHCmnSrRcvd
1825 * Must be called after calling the specific scheduler.
1827 * Function: rgSCHDrxSrInd
1830 * - Mark the UE as ACTIVE
1831 * ueCb->drxUlInactvMask |= (DRX_SR_ACTIVE);
1832 * - Optionally call schedulers to add this UE to their scheduling
1834 * - Set drxUe->srRcvd = TRUE
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.
1841 * @param RgSchCellCb *cell
1842 * @param RgSchUeCb *ue
1843 * @return ROK/RFAILED
1845 S16 rgSCHDrxSrInd(RgSchCellCb *cell,RgSchUeCb *ue)
1847 RgSchDrxUeCb *drxCb;
1849 #if ( ERRCLASS & ERRCLS_INT_PAR )
1850 if ( cell == (RgSchCellCb* )NULLP)
1855 if( (ue == (RgSchUeCb* )NULLP))
1857 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
1858 "rgSCHDrxSrInd():Invalid Params. cell/ue is NULL");
1862 /* KWork fix - shifted this down */
1865 drxCb = RG_SCH_DRX_GET_UE(ue);
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);
1874 } /* rgSCHDrxSrInd */
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
1883 * Invoked by - rgSCHCmnHdlHoPo
1885 * Function: rgSCHDrxDedRa
1888 * - MARK the UE as active
1889 * - set the raRcvd = TRUE for this UE.
1892 * ueCb->drxDlInactvMask |= (DRX_RA_ACTIVE);
1893 * ueCb->drxUlInactvMask |= (DRX_RA_ACTIVE);
1894 * ueCb->raRcvd = TRUE;
1897 * @param RgSchCellCb *cellCb
1898 * @param RgSchUeCb *ueCb
1901 Void rgSCHDrxDedRa(RgSchCellCb *cellCb, RgSchUeCb *ueCb)
1903 RgSchDrxUeCb *drxCb;
1905 drxCb = RG_SCH_DRX_GET_UE(ueCb);
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);
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);
1916 drxCb->raRcvd = TRUE;
1919 } /* end of rgSCHDrxDedRa */
1922 /** @brief This function calculates the next onDuration Occurence
1923 * and removes & queue it again in onDurationQ
1928 * Function: rgSCHDrxMvToNxtOnDurOcc
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
1940 static Void rgSCHDrxMvToNxtOnDurOcc(RgSchCellCb *cell,RgSchUeCb *ueCb,uint16_t idx,Bool calcFrmOffst)
1942 uint16_t nxtOnDurIndex;
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 */
1949 drxCell = cell->drxCb;
1950 drxUe = ueCb->drxCb;
1953 if(calcFrmOffst == FALSE)
1955 if (drxUe->isLongCycle)
1957 nxtOnDurIndex = ((idx + drxUe->longDrxCycle)
1958 % RG_SCH_MAX_DRXQ_SIZE );
1959 drxUe->distance = drxUe->longDrxCycle/RG_SCH_MAX_DRXQ_SIZE;
1963 nxtOnDurIndex = ((idx + drxUe->shortDrxCycle)% RG_SCH_MAX_DRXQ_SIZE);
1965 drxUe->distance = drxUe->shortDrxCycle / RG_SCH_MAX_DRXQ_SIZE;
1970 rgSCHDrxGetNxtOnDur(cell,drxUe,&nxtOnDur,(uint8_t)idx);
1972 nxtOnDurInSf = ((nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1975 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1976 cell->crntTime.slot);
1978 nxtOnDurIndex = nxtOnDurInSf % RG_SCH_MAX_DRXQ_SIZE;
1979 drxUe->distance = (nxtOnDurInSf-curTime) / RG_SCH_MAX_DRXQ_SIZE;
1980 if (drxUe->distance < 0)
1982 RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId,"DRXUE. Invalid "
1983 "value for distance, %d CRNTI:%d", drxUe->distance,ueCb->ueId);
1987 /* First remove from existing location */
1988 if ( drxUe->onDurIndx != DRX_INVALID )
1990 cmLListDelFrm(&(drxCell->drxQ[drxUe->onDurIndx].onDurationQ),
1991 &(drxUe->onDurationEnt));
1994 /* Add at new location */
1995 cmLListAdd2Tail(&(drxCell->drxQ[nxtOnDurIndex].onDurationQ),
1996 &(drxUe->onDurationEnt));
1998 drxUe->onDurationEnt.node = (PTR)ueCb;
1999 drxUe->onDurIndx = nxtOnDurIndex;
2002 }/*rgSCHDrxMvToNxtOnDurOcc*/
2005 /** @brief This function calculates the next SFN,subframe a given
2006 * timer is going to expire. Works for all TDD configurations.
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.
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
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)
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
2041 static S16 rgSCHDrxGetNxtTmrExpry(RgSchCellCb *cell, uint16_t curTime, uint32_t duration,CmLteTimingInfo *tmrExpryIdx)
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 */
2049 #if ( ERRCLASS & ERRCLS_INT_PAR )
2050 if ( (cell == (RgSchCellCb* )NULLP)
2052 (tmrExpryIdx == (CmLteTimingInfo* )NULLP)
2060 isDwPtsCnted = cell->isDwPtsCnted ;
2062 tddCfgMode = cell->ulDlCfgIdx;
2063 crntTime.sfn = curTime / RGSCH_NUM_SUB_FRAMES_5G;
2064 crntTime.slot = curTime % RGSCH_NUM_SUB_FRAMES_5G;
2068 /* First calculate the number of DL subframes till next SFN */
2070 dlSfTillNxtSFN = rgSchDrxDLSfTillNxtSFN[isDwPtsCnted][tddCfgMode]
2071 [(crntTime.slot % RGSCH_NUM_SUB_FRAMES)];
2074 if ( dlSfTillNxtSFN >= duration )
2076 /* the timer would expire on the same RF */
2077 uint32_t diff = dlSfTillNxtSFN - duration;
2079 tmrExpryIdx->sfn = crntTime.sfn;
2083 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2089 /* to know the DL sf index based on diff */
2090 arrayIdx = rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2092 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2095 }/* if ( dlSfTillNxtSFN >= duration...*/
2098 uint32_t remSf; /*!< remaining subframes */
2099 uint32_t numRf; /*!< num of complete radio frames */
2100 uint32_t numRemSfs; /*!< num of remaining subframes */
2102 remSf = duration - dlSfTillNxtSFN;
2104 /* move to (currSFN,9) having consued dlSfTillNxtSFN DL subframes */
2105 tmrExpryIdx->sfn = crntTime.sfn;
2106 tmrExpryIdx->subframe = (uint8_t)9;
2108 numRf = (1 * remSf)/rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2109 numRemSfs = (1 * remSf)%rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2111 tmrExpryIdx->sfn = tmrExpryIdx->sfn + numRf;
2113 /* we are now at (X,9) having consumed dlSfTillNxtSFN + numRf * num of DL
2114 * subframes in 1 RF */
2116 if ( numRemSfs == 0 )
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]
2127 /* a reminder implies we have to move past this SFN as we are at the
2128 * last subframe on that SFN */
2130 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2133 }/*else if diff > duration */
2135 /* timer will expire 1 + tmrExpryIdx */
2137 if ( ( tmrExpryIdx->subframe + 1) == 10 )
2140 tmrExpryIdx->subframe = 0;
2144 tmrExpryIdx->subframe++;
2147 /* check to see if it sfn has crossed its max */
2148 if ( tmrExpryIdx->sfn > RG_SCH_CMN_MAX_SFN_NUM )
2150 tmrExpryIdx->sfn = tmrExpryIdx->sfn - (RG_SCH_CMN_MAX_SFN_NUM + 1);
2154 }/*rgSCHDrxGetNxtTmrExpry*/
2156 /** @brief This function calculates the next onDuration Occurence
2161 * Function: rgSCHDrxCalcNxtTmrExpry
2163 * Processing steps: a wrapper function to call
2164 * rgSCHDrxGetNxtTmrExpry
2166 * @param RgSchCellCb *cell
2167 * @param RgSchUeCb *ue
2168 * @param uint16_t delta
2169 * @param uint32_t tmrLen
2170 * @param uint16_t *distance
2172 * @return ROK/RFAILED
2174 static Void rgSCHDrxCalcNxtTmrExpry(RgSchCellCb *cell, RgSchUeCb *ue, uint16_t delta, uint32_t tmrLen, S16 *distance, uint16_t *idx)
2176 uint16_t curTimeInSf; /*current time in no of subframes*/
2177 CmLteTimingInfo tmrExpry;
2178 uint16_t tmrExpryInSf; /*timer expry in no of subframes*/
2180 curTimeInSf = cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G +
2181 cell->crntTime.slot;
2183 /* add delta to curTime */
2184 curTimeInSf += delta;
2186 rgSCHDrxGetNxtTmrExpry(ue->cell,curTimeInSf,tmrLen,&tmrExpry);
2188 /* convert timre Expry in terms of subframes */
2189 tmrExpryInSf = tmrExpry.sfn * RGSCH_NUM_SUB_FRAMES_5G +
2193 *idx = (tmrExpryInSf) % RG_SCH_MAX_DRXQ_SIZE;
2195 if ( distance != NULLP ) /* hqReTx don't use the concept of distance.
2196 They can send NULLP for distance.
2199 if ( tmrExpryInSf > curTimeInSf )
2201 *distance = (tmrExpryInSf - curTimeInSf) /
2202 RG_SCH_MAX_DRXQ_SIZE;
2206 /* in case the RF is at its max and wraps around */
2208 *distance = ((tmrExpryInSf + (RG_SCH_CMN_MAX_NUM_OF_SFN - 1))
2210 curTimeInSf) / RG_SCH_MAX_DRXQ_SIZE;
2214 RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId, "DRXUE. Invalid "
2215 "value for distance, %d CRNTI:%d", *distance,ue->ueId);
2220 }/*rgSCHDrxCalcNxtTmrExpry*/
2222 /* ccpu00134670- Validating onduration timer versus DRX cycle*/
2223 /***********************************************************
2225 * Func : rgSCHCfgVldtTddDrxCycCfg
2228 * Desc : Validates DRX Cycle Length configuration against received
2229 * onDuration timer from RRC.
2240 **********************************************************/
2241 S16 rgSCHCfgVldtTddDrxCycCfg(RgSchCellCb *cell,uint16_t drxCycle,uint8_t onDurTmr, uint16_t offSet)
2244 uint16_t endTimeInSf;
2245 CmLteTimingInfo endTime;
2250 rgSCHDrxGetNxtTmrExpry(cell, startTime, onDurTmr, &endTime);
2252 endTimeInSf = (endTime.sfn* RGSCH_NUM_SUB_FRAMES)+endTime.subframe;
2254 if(((RGSCH_MAX_SUBFRM_5G + endTimeInSf- startTime) % RGSCH_MAX_SUBFRM_5G) >=
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)));
2274 /** @brief This function is called to handle onDurationTimer per TTI processing.
2277 * Invoked by - rgSCHDrxTtiInd
2279 * Function: rgSCHDrxTtiHdlOnDurUl
2283 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
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.
2290 * @param RgSchCellCb *cellCb
2291 * @param uint16_t ulIndex
2295 static Void rgSCHDrxTtiHdlOnDurUl(RgSchCellCb *cell,uint16_t ulIndex)
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;
2305 drxCell = (cell->drxCb);
2306 delInUlScan = drxCell->delInUlScan;
2307 /***********************************************************
2308 * Scanning OnDurationQ in UL
2309 ***********************************************************/
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.*/
2314 node = drxCell->drxQ[ulIndex].onDurationQ.first;
2318 ue = (RgSchUeCb*)node->node;
2320 drxUe = RG_SCH_DRX_GET_UE(ue);
2323 if ( delInUlScan == FALSE)
2328 if ( drxUe->distance != DRX_TMR_EXPRD )
2333 /* reset the bit mask to indicate that onduration has started */
2334 drxUe->drxUlInactvMask &= ~RG_SCH_DRX_ONDUR_BITMASK;
2336 /* if no other condition is keeping UE as inactive,
2339 RG_SCH_CMN_UL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2341 if ( delInUlScan == TRUE )
2343 /*calculate next on duration occurence
2344 * and it to the onDuration Queue*/
2345 rgSCHDrxMvToNxtOnDurOcc(cell,ue,ulIndex,FALSE);
2346 }/*delInUlScan == FALSE */
2349 /***********************************************************
2350 * Scanning OnDurationExpQ in UL
2351 ***********************************************************/
2353 node = drxCell->drxQ[ulIndex].onDurationExpQ.first;
2355 /* Initialize UL inactive list */
2356 cmLListInit(&ulInactvLst);
2360 ue = (RgSchUeCb*)node->node;
2362 drxUe = RG_SCH_DRX_GET_UE(ue);
2364 if ( delInUlScan == FALSE )
2366 drxUe->onDurExpDistance--;
2369 if ( drxUe->onDurExpDistance != DRX_TMR_EXPRD )
2374 /*UE is inactive as onduration has expired */
2375 drxUe->drxUlInactvMask |= RG_SCH_DRX_ONDUR_BITMASK;
2377 if( !RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
2379 /* set the inactive bit to indicate UE has now become inactive */
2380 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
2382 /* Add to DL inactive list */
2383 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
2384 ue->ulDrxInactvLnk.node = (PTR)ue;
2387 if ( delInUlScan == TRUE)
2389 /*Remove from DRX queue*/
2390 cmLListDelFrm(&(drxCell->drxQ[ulIndex].onDurationExpQ),
2391 &(drxUe->onDurationExpEnt));
2393 drxUe->onDurExpIndx = DRX_INVALID;
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);
2405 /** @brief This function is called to handle onDurationTimer per TTI processing.
2408 * Invoked by - rgSCHDrxTtiInd
2410 * Function: rgSCHDrxTtiHdlOnDurDl
2414 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
2416 * - For Downlink we shall look at an index that is
2417 * n + RG_SCH_DRX_DL_DELTA.
2420 * @param RgSchCellCb *cellCb
2421 * @param uint16_t dlIndex
2425 static Void rgSCHDrxTtiHdlOnDurDl(RgSchCellCb *cell,uint16_t dlIndex)
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;
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.
2440 /***********************************************************
2441 * Scanning OnDurationQ in DL
2442 ***********************************************************/
2443 drxCell = (cell->drxCb);
2445 delInUlScan = drxCell->delInUlScan;
2446 //printf("CELL Timer [SFN : %d],[SF : %d]\n",cell->crntTime.sfn,cell->crntTime.slot);
2448 node = drxCell->drxQ[dlIndex].onDurationQ.first;
2453 ue = (RgSchUeCb* )node->node;
2457 drxUe = RG_SCH_DRX_GET_UE(ue);
2459 if ( delInUlScan == TRUE)
2464 if ( drxUe->distance != DRX_TMR_EXPRD )
2470 /* UE is active as onduration is to start */
2471 drxUe->drxDlInactvMask &= ~RG_SCH_DRX_ONDUR_BITMASK;
2473 /* set the UE as DRX active*/
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);
2478 /* Temporary fix to delete stale entry */
2479 if (drxUe->onDurExpIndx != DRX_INVALID)
2481 RLOG_ARG4(L_DEBUG,DBG_CELLID,cell->cellId,
2482 "UEID:%d PreExisted[%d:%d]in onDurExpQ new[%d]",
2484 drxUe->onDurExpIndx,
2485 drxUe->onDurExpDistance,
2487 cmLListDelFrm(&(drxCell->drxQ[drxUe->onDurExpIndx].onDurationExpQ),
2488 &(drxUe->onDurationExpEnt));
2490 drxUe->onDurExpIndx = DRX_INVALID;
2492 /*start the onduration expiry timer*/
2494 rgSCHDrxCalcNxtTmrExpry(cell,
2498 &(drxUe->onDurExpDistance),
2502 expiryIndex = ((dlIndex + drxUe->onDurTmrLen) %
2503 RG_SCH_MAX_DRXQ_SIZE);
2504 drxUe->onDurExpDistance = (drxUe->onDurTmrLen)/
2505 RG_SCH_MAX_DRXQ_SIZE;
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;
2514 //printf("DRxOnDuration will Expire = [%d]\n",(cell->crntTime.sfn*10+cell->crntTime.slot+drxUe->onDurTmrLen));
2516 if ( delInUlScan == FALSE )
2518 /*calculate next on duration occurence
2519 * and it to the onDuration Queue*/
2520 rgSCHDrxMvToNxtOnDurOcc(cell,ue,dlIndex,FALSE);
2521 }/*delInUlScan == FALSE */
2525 /***********************************************************
2526 * Scanning OnDurationExpQ in DL
2527 ***********************************************************/
2529 /* Mark UE as Inactive based on OnDuration Expiry */
2530 node = drxCell->drxQ[dlIndex].onDurationExpQ.first;
2532 /* Initialize DL inactive list */
2533 cmLListInit(&dlInactvLst);
2537 ue = (RgSchUeCb*)node->node;
2539 drxUe = RG_SCH_DRX_GET_UE(ue);
2541 if ( delInUlScan == TRUE )
2543 drxUe->onDurExpDistance--;
2546 if ( drxUe->onDurExpDistance != DRX_TMR_EXPRD )
2552 /* UE is inactive as onduration has expired */
2553 drxUe->drxDlInactvMask |= (RG_SCH_DRX_ONDUR_BITMASK);
2555 if( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
2557 /* set the inactive bit to indicate UE has now become inactive */
2558 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
2560 /* Add to DL inactive list */
2561 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
2562 ue->dlDrxInactvLnk.node = (PTR)ue;
2565 if ( delInUlScan == FALSE )
2567 /*Remove from DRX queue*/
2568 cmLListDelFrm(&(drxCell->drxQ[dlIndex].onDurationExpQ),
2569 &(drxUe->onDurationExpEnt));
2571 drxUe->onDurExpIndx = DRX_INVALID;
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);
2581 }/*rgSCHDrxTtiHdlOnDurDl*/
2583 /** @brief This function handles the Dl HARQ timer's processing per TTI.
2586 * Invoked by - rgSCHDrxTtiHdlDlHarq
2588 * Function: rgSCHDrxTtiHdlDlHarqRTT
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.
2596 * @param RgSchCellCb *cellCb
2597 * @param uint16_t dlIndex
2601 static Void rgSCHDrxTtiHdlDlHarqRTT(RgSchCellCb *cell,uint16_t dlIndex)
2604 RgSchDrxDlHqProcCb *drxHq;
2605 RgSchDlHqProcCb *dlHq;
2606 RgSchDRXCellCb *drxCell;
2607 RgSchDrxUeCb *drxUe;
2608 uint16_t reTxExpIndx;
2611 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
2612 RgSchCmnCell *cellSch = RG_SCH_CMN_GET_CELL(cell);
2614 uint32_t dlInactvMask;
2616 drxCell = cell->drxCb;
2617 delInUlScan = drxCell->delInUlScan;
2619 /***********************************************************
2620 * Scanning harqRTTQ in DL
2621 ***********************************************************/
2623 cmLListInit(&dlInactvLst);
2624 node = drxCell->drxQ[dlIndex].harqRTTQ.first;
2628 dlHq = (RgSchDlHqProcCb*)node->node;
2632 if(TRUE == ue->isEmtcUe)
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);
2644 if ( delInUlScan == FALSE)
2646 cmLListDelFrm (&(drxCell->drxQ[dlIndex].harqRTTQ),
2647 &(drxHq->harqRTTEnt));
2649 drxHq->rttIndx = DRX_INVALID;
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)
2657 /* add the harq proc to the re-tx queue--*/
2659 /* ccpu00134196-[Add]-DRX retx timer changes */
2660 rgSCHDrxCalcNxtTmrExpry(cell,
2663 drxUe->drxRetransTmrLen-drxHq->retxTmrReduction,
2664 NULLP, /*retransQ does not maintain distance*/
2669 /* ccpu00134196-[Add]-DRX retx timer changes */
2670 reTxExpIndx = ((dlIndex +
2671 drxUe->drxRetransTmrLen-drxHq->retxTmrReduction) %
2672 RG_SCH_MAX_DRXQ_SIZE);
2674 /* TODO. Workaround to avoid duplicate entry */
2675 if(drxHq->reTxIndx == DRX_INVALID)
2677 cmLListAdd2Tail (&(drxCell->drxQ[reTxExpIndx].harqRetxQ),
2678 &(drxHq->harqRetxEnt));
2680 drxHq->harqRetxEnt.node = (PTR)dlHq;
2681 drxHq->reTxIndx = reTxExpIndx;
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,
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);
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);
2700 /***********************************************************
2701 * Scanning harqRetxQ in DL
2702 ***********************************************************/
2704 node = drxCell->drxQ[dlIndex].harqRetxQ.first;
2707 dlHq = (RgSchDlHqProcCb*)node->node;
2709 drxUe = RG_SCH_DRX_GET_UE(ue);
2711 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2712 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2714 /*mark the ue as in-active for downlink*/
2715 drxUe->drxDlInactvMaskPerCell[cellIdx] |= (RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2717 dlInactvMask = RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId;
2719 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
2721 dlInactvMask &= drxUe->drxDlInactvMaskPerCell[cellIdx];
2724 drxUe->drxDlInactvMask |= dlInactvMask;
2726 /* if no other condition is keeping ue active,
2729 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
2731 ue->dl.dlInactvMask |= (RG_DRX_INACTIVE);
2733 /* Add to DL inactive list */
2734 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
2735 ue->dlDrxInactvLnk.node = (PTR)ue;
2738 /*remove the harq proc from this queue*/
2739 if ( delInUlScan == FALSE)
2741 cmLListDelFrm (&(drxCell->drxQ[dlIndex].harqRetxQ),
2742 &(drxHq->harqRetxEnt));
2743 drxHq->reTxIndx = DRX_INVALID;
2746 /*Call schedulers to inactivate ue*/
2747 cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
2752 /** @brief This function handles the Ul HARQ timer's processing per TTI.
2755 * Invoked by - rgSCHDrxTtiHdlDlHarq
2757 * Function: rgSCHDrxTtiHdlUlHarqRTT
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.
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.
2773 * @param RgSchCellCb *cellCb
2774 * @param uint16_t ulIndex
2778 static Void rgSCHDrxTtiHdlUlHarqRTT(RgSchCellCb *cell,uint16_t ulIndex)
2781 RgSchDrxDlHqProcCb *drxHq;
2782 RgSchDlHqProcCb *dlHq;
2783 RgSchDRXCellCb *drxCell;
2784 RgSchDrxUeCb *drxUe;
2787 CmLListCp ulInactvLst; /* list of UE's becoming DL-inactive */
2788 RgSchCmnCell *cellSch = RG_SCH_CMN_GET_CELL(cell);
2790 uint32_t ulInactvMask;
2793 drxCell = cell->drxCb;
2794 delInUlScan = drxCell->delInUlScan;
2796 cmLListInit(&ulInactvLst);
2798 /***********************************************************
2799 * Scanning harqRTTQ in UL
2800 ***********************************************************/
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.
2810 node = drxCell->drxQ[ulIndex].harqRTTQ.first;
2813 dlHq = (RgSchDlHqProcCb*)node->node;
2815 drxUe = RG_SCH_DRX_GET_UE(ue);
2817 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2818 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2820 if ( delInUlScan == TRUE )
2822 /* remove the harq proc from this queue--*/
2823 cmLListDelFrm (&(drxCell->drxQ[ulIndex].harqRTTQ),
2824 &(drxHq->harqRTTEnt));
2826 drxHq->rttIndx = DRX_INVALID;
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);
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);
2837 /***********************************************************
2838 * Scanning harqRetxQ in UL
2839 ***********************************************************/
2840 node = drxCell->drxQ[ulIndex].harqRetxQ.first;
2843 dlHq = (RgSchDlHqProcCb*)node->node;
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)];
2849 /*mark the ue as in-active for uplink*/
2851 drxUe->drxUlInactvMaskPerCell[cellIdx] |= (RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2853 ulInactvMask = RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId;
2855 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
2857 ulInactvMask &= drxUe->drxUlInactvMaskPerCell[cellIdx];
2860 drxUe->drxUlInactvMask |= ulInactvMask;
2862 if(!RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
2864 ue->ul.ulInactvMask |= (RG_DRX_INACTIVE);
2866 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
2867 ue->ulDrxInactvLnk.node = (PTR)ue;
2870 /* remove the harq proc from this queue*/
2871 if ( delInUlScan == TRUE)
2873 cmLListDelFrm (&(drxCell->drxQ[ulIndex].harqRetxQ),
2874 &(drxHq->harqRetxEnt));
2875 drxHq->reTxIndx = DRX_INVALID;
2880 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
2886 /**********************************************************************
2889 **********************************************************************/