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 PRIVATE U8 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 PRIVATE U8 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 PRIVATE U8 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 U8 rgSchDrxHarqRetxFirstPsf[RGSCH_MAX_TDD_CFG][RGSCH_NUM_SUB_FRAMES] = {
187 {0, 0, 4, 0, 6, 0, 0, 4, 0, 6},
188 {0, 0, 4, 6, 0, 0, 0, 4, 6, 0},
189 {0, 0, 4, 0, 0, 0, 0, 4, 0, 0},
190 {0, 0, 4, 4, 4, 0, 0, 0, 0, 0},
191 {0, 0, 4, 4, 0, 0, 0, 0, 0, 0},
192 {0, 0, 4, 0, 0, 0, 0, 0, 0, 0},
193 {0, 0, 4, 6, 5, 0, 0, 4, 7, 0},
197 /******************************************************************************
198 * Start of Function declarations *
199 ******************************************************************************/
200 PRIVATE Void rgSCHDrxTtiHdlOnDurUl ARGS((
204 PRIVATE Void rgSCHDrxTtiHdlOnDurDl ARGS((
208 PRIVATE Void rgSCHDrxTtiHdlDlHarqRTT ARGS((
212 PRIVATE Void rgSCHDrxTtiHdlUlHarqRTT ARGS((
216 PRIVATE S16 rgSCHDrxTtiHdlOnDur ARGS((RgSchCellCb *cellCb, U16 dlIndex,
218 PRIVATE S16 rgSCHDrxTtiHdlInActv ARGS((RgSchCellCb *cellCb, U16 dlIndex,
220 PRIVATE S16 rgSCHDrxTtiHdlShortCycle ARGS((RgSchCellCb *cell, U16 dlIndex,
222 PRIVATE S16 rgSCHDrxTtiHdlDlHarq ARGS((RgSchCellCb *cellCb, U16 dlIndex,
224 PRIVATE S16 rgSCHDrxCpyUeCfg ARGS((RgSchDrxUeCb *drxCb,
225 RgrUeDrxCfg* ueDrxCfg));
227 PRIVATE S16 rgSCHDrxGetNxtOnDur ARGS((RgSchCellCb* cell,RgSchDrxUeCb* drxCb,
228 CmLteTimingInfo* nxtOnDur,
231 PRIVATE Void rgSCHDrxMvToNxtOnDurOcc ARGS((RgSchCellCb* cell,
236 PRIVATE Void rgSCHDrxCalcNxtTmrExpry ARGS((RgSchCellCb *cell,
243 PRIVATE S16 rgSCHDrxGetNxtTmrExpry ARGS((RgSchCellCb *cell,U16 curTime,
245 CmLteTimingInfo* tmrExpryIdx));
248 EXTERN S16 rgSCHEmtcDrxCpyUeCfg
253 EXTERN S16 rgSCHDrxTtiHdlUlHarq
259 EXTERN 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
311 Void rgSCHDrxTtiInd (cell)
318 TRC2(rgSCHDrxTtiInd );
321 dlIndex = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot +
322 RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
324 ulIndex = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot +
325 RG_SCH_DRX_UL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
328 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex);
329 /* checks the Ul-Retransmission timer */
333 rgSCHDrxTtiHdlUlHarq (cell, dlIndex, ulIndex);
336 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex);
338 /*Process Short cycle expiry before On duration timer so that long cycles
339 * On Duration can be processed if timer has expired*/
340 rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex);
341 rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex);
344 rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex);
345 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex);
346 /* checks the Ul-Retransmission timer */
350 rgSCHDrxTtiHdlUlHarq (cell, dlIndex, ulIndex);
353 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex);
354 rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex);
362 /** @brief This function is called to handle onDurationTimer per TTI processing.
365 * Invoked by - rgSCHDrxTtiInd
367 * Function: rgSCHDrxTtiHdlOnDur
371 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
373 * - For Downlink we shall look at an index that is
374 * n + RG_SCH_DRX_DL_DELTA.
377 * - For Uplink we shall look at an index that is
378 * n + RG_SCH_DRX_UL_DELTA as
379 * we are concerned with the PDCCH and not the actual PUSCH.
382 * @param RgSchCellCb *cellCb
385 * @return ROK/RFAILED
389 PRIVATE S16 rgSCHDrxTtiHdlOnDur
396 PRIVATE S16 rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex)
403 TRC2(rgSCHDrxTtiHdlOnDur);
405 #if ( ERRCLASS & ERRCLS_INT_PAR )
406 if ( cell == (RgSchCellCb* )NULLP )
412 rgSCHDrxTtiHdlOnDurDl(cell,dlIndex);
414 rgSCHDrxTtiHdlOnDurUl(cell, ulIndex);
418 }/*rgSCHDrxTtiHdlOnDur*/
421 /** @brief This function handles the processing for drxInactityTimer per TTI
424 * Invoked by - rgSCHDrxTtiInd
426 * Function: rgSCHDrxTtiHdlInActv
430 * - For Downlink we shall look at an index that is
431 * n + RG_SCH_DRX_DL_DELTA of the drxQ.
433 * - MARK UE AS INACTIVE BASED ON DRX-INACTIVITY TIMER EXPIRY
436 * - For Uplink we shall look at an index that is
437 * n + RG_SCH_DRX_UL_DELTA as
438 * we are concerned with the PDCCH and not the actual PUSCH.
441 * @param RgSchCellCb *cellCb
444 * @return ROK/RFAILED
448 S16 rgSCHDrxTtiHdlInActv
455 S16 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex)
462 RgSchDRXCellCb *drxCell=NULLP;
464 RgSchDrxUeCb *drxUe=NULLP;
465 U16 shrtCycleExpIndx;
466 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
467 CmLListCp ulInactvLst; /* list of UE's becoming UL-inactive */
468 RgSchCmnCell *cellSch = NULLP;
469 Bool delInUlScan = FALSE;
471 TRC2(rgSCHDrxTtiHdlInActv);
473 #if ( ERRCLASS & ERRCLS_INT_PAR )
474 if ( cell == (RgSchCellCb* )NULLP)
481 drxCell = (cell->drxCb);
482 delInUlScan = drxCell->delInUlScan;
485 /***********************************************************
486 * Scanning inActvitiyQ in DL
487 ***********************************************************/
489 /* The DL loop will scan for UE's whose inactivity timer has
490 * expired. It will switch the cycle to short or long based
491 * on the cycle configured.
492 * Furhter,if !delInUlScan, then will remove the UE from the
496 node = drxCell->drxQ[dlIndex].inActvTmrQ.first;
498 /* Initialize DL inactive list */
499 cmLListInit(&dlInactvLst);
501 /* Initialize UL inactive list */
502 cmLListInit(&ulInactvLst);
506 ue = (RgSchUeCb*)node->node;
508 drxUe = RG_SCH_DRX_GET_UE(ue);
510 if ( delInUlScan == TRUE)
512 drxUe->drxInactDistance--;
515 if ( drxUe->drxInactDistance != DRX_TMR_EXPRD )
520 /* UE is inactive as inactivity timer has expired */
521 drxUe->drxDlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
524 /* update the ue mask only if no condition in drx
525 * is keeping ue active
527 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
529 /* set the UE has DRX inactive */
530 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
532 /* Add to DL inactive list */
533 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
534 ue->dlDrxInactvLnk.node = (PTR)ue;
537 /*Remove from the queue if !delInUlScan */
538 if( delInUlScan == FALSE )
540 cmLListDelFrm(&(drxCell->drxQ[dlIndex].inActvTmrQ),
541 &(drxUe->inActvTmrEnt));
543 drxUe->drxInactvIndx = DRX_INVALID;
545 }/* if (delInUlScan == FALSE) */
547 if (drxUe->isShortCycleCfgd)
549 /* add shorty cycle expirty */
550 drxUe->isLongCycle = FALSE;
552 shrtCycleExpIndx = (dlIndex + (drxUe->shortCycleTmrLen *
553 drxUe->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
555 drxUe->drxShortCycleDistance = (drxUe->shortCycleTmrLen *
556 drxUe->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
558 /*Remove the UE from existing index*/
559 if (drxUe->shortCycleIndx != DRX_INVALID)
561 cmLListDelFrm(&(drxCell->drxQ[drxUe->shortCycleIndx].shortCycleQ),
562 &(drxUe->shortCycleEnt));
565 cmLListAdd2Tail(&(drxCell->drxQ[shrtCycleExpIndx].shortCycleQ),
566 &(drxUe->shortCycleEnt));
568 drxUe->shortCycleEnt.node = (PTR)ue;
569 drxUe->shortCycleIndx = shrtCycleExpIndx;
571 /*Calculate onDuration again & move the
572 * ueCb to the next Onduration occurence
575 /*we maybe at any position in the RF timeline,
576 * need to calculate onDuration from the starting
579 rgSCHDrxMvToNxtOnDurOcc(cell,ue,RG_SCH_DRX_DL_DELTA,TRUE);
581 }/*isShortCycleCfgd */
584 /* use the long cycle */
585 drxUe->isLongCycle = TRUE;
591 /***********************************************************
592 * Scanning inActvitiyQ in UL
593 ***********************************************************/
595 /* The UL loop will scan for UE's whose inactivity timer has
596 * expired and mark the UE's UL inactive.
597 * Furhter,if delInUlScan, then will remove the UE from the
601 /* For Uplink we shall look at an index that is n + RG_SCH_DRX_UL_DELTA as
602 we are concerned with the PDCCH and not the actual PUSCH.*/
606 node = drxCell->drxQ[ulIndex].inActvTmrQ.first;
611 ue = (RgSchUeCb*)node->node;
613 drxUe = RG_SCH_DRX_GET_UE(ue);
615 if ( delInUlScan == FALSE)
617 drxUe->drxInactDistance--;
620 if ( drxUe->drxInactDistance != DRX_TMR_EXPRD )
625 /* Need to mark the UE as inactive due to expiry of
626 * DRX inactivity timer */
628 /* UE is inactive as inactivity timer has expired */
629 drxUe->drxUlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
631 /* update the ue mask only if no other condition in
632 * drx is keeping ue active */
634 if (!RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
636 /* set the inactivity bit */
637 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
639 /* Add to Ul inactive list */
640 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
641 ue->ulDrxInactvLnk.node = (PTR)ue;
644 if ( delInUlScan == TRUE)
646 /* remove from queue */
647 cmLListDelFrm(&(drxCell->drxQ[ulIndex].inActvTmrQ),
648 &(drxUe->inActvTmrEnt));
650 drxUe->drxInactvIndx = DRX_INVALID;
652 }/* if ( delInUlScan == TRUE) */
653 }/*while(node) for uplink */
656 /* Send the list to the scheduler to mark UE as inactive in UL*/
657 cellSch = RG_SCH_CMN_GET_CELL(cell);
658 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
660 /* Send the DL inactive list to the scheduler to mark UE as inactive */
661 cellSch = RG_SCH_CMN_GET_CELL(cell);
662 cellSch->apisDl->rgSCHDlInactvtUes(cell,&dlInactvLst);
665 }/*rgSCHDrxTtiHdlInActv*/
667 /** @brief This function handles the per TTI processing for DRX short cycle
671 * Invoked by - rgSCHDrxTtiInd
673 * Function: rgSCHDrxTtiHdlShortCycle
678 * in addition we have to mark the ues based on drx short cycle
682 * @param RgSchCellCb *cell
685 * @return ROK/RFAILED
689 S16 rgSCHDrxTtiHdlShortCycle
696 S16 rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex)
703 RgSchDRXCellCb *drxCell=NULLP;
705 RgSchDrxUeCb *drxUe=NULLP;
707 TRC2(rgSCHDrxTtiHdlShortCycle );
709 #if ( ERRCLASS & ERRCLS_INT_PAR )
710 if ( cell == (RgSchCellCb* )NULLP )
719 drxCell = RG_SCH_DRX_GET_CELL(cell);
721 node = drxCell->drxQ[dlIndex].shortCycleQ.first;
725 ue = (RgSchUeCb*)node->node;
727 drxUe = RG_SCH_DRX_GET_UE(ue);
729 if ( --drxUe->drxShortCycleDistance != DRX_TMR_EXPRD)
734 /* mark the UE's current cycle to be long */
735 drxUe->isLongCycle = TRUE;
737 /* remove from the shortCycleQ */
739 cmLListDelFrm(&(drxCell->drxQ[dlIndex].shortCycleQ),
740 &(drxUe->shortCycleEnt));
741 drxUe->shortCycleIndx = DRX_INVALID;
743 /* Remove from onDuration queue inserted based on short cycle
744 * and calculate onDuration based on long cycle.*/
745 rgSCHDrxMvToNxtOnDurOcc(cell,ue,RG_SCH_DRX_DL_DELTA,TRUE);
749 }/*rgSCHDrxTtiHdlShortCycle*/
752 /** @brief This function handles the HARQ timer's processing per TTI.
755 * Invoked by - rgSCHDrxTtiInd
757 * Function: rgSCHDrxTtiHdlDlHarq
760 * - In addition per TTI DRX module must look at Downlink HARQ queues
761 * maintained to track HARQ RTT timer and drx-RetransmissionTimer.
762 * Every TTI at the scheduling index we shall check these queues and
763 * process accordingly.
766 * - Though these timers are related to downlink HARQ processing, they
767 * have an impact on uplink scheduling. The reason is that the UE,
768 * if active for downlink scheduling implies that it is reading
769 * PDCCHs i.e. we can still send uplink allocations to the UE. Hence
770 * every TTI Uplink too would look at the harqRTTQ and harqRetxQ.
774 * @param RgSchCellCb *cellCb
777 * @return ROK/RFAILED
781 PRIVATE S16 rgSCHDrxTtiHdlDlHarq
788 PRIVATE S16 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex)
795 #if ( ERRCLASS & ERRCLS_INT_PAR)
796 if ( cell == (RgSchCellCb *)NULLP )
800 #endif /*ERRCLASS & ERRCLS_INT_PAR*/
803 TRC2(rgSCHDrxTtiHdlDlHarq );
805 rgSCHDrxTtiHdlDlHarqRTT(cell, dlIndex);
807 rgSCHDrxTtiHdlUlHarqRTT(cell, ulIndex);
812 /** @brief This function is called by the common scheduler as part of
813 * finalization of allocations in downlink.
818 * Function: rgSchDrxStrtInActvTmr
820 * This function is responsible to starting drx-InactivityTimer
825 * @param RgSchCellCb *cell
826 * @param CmLListCp *ueUlLst
827 * @param U8 direction
832 Void rgSCHDrxStrtInActvTmr
839 Void rgSCHDrxStrtInActvTmr(cell, ueLst, direction)
848 RgSchDrxUeCb *ueDrxCb;
852 U16 inActvTmrExpIndx;
854 U16 curTimeInSf; /* current time in number of subframes */
859 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
860 CmLListCp ulInactvLst; /* list of UE's becoming UL-inactive */
861 RgSchCmnCell *cellSch = NULLP;
862 Bool delInUlScan = FALSE;
865 TRC2(rgSCHDrxStrtInActvTmr);
868 if ( direction == RG_SCH_DRX_UL)
871 curTimeInSf = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
872 (cell->crntTime.slot) +RG_SCH_DRX_UL_DELTA;
876 delta = RG_SCH_DRX_UL_DELTA;
882 curTimeInSf = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
883 (cell->crntTime.slot) + RG_SCH_DRX_DL_DELTA;
887 delta = RG_SCH_DRX_DL_DELTA;
892 /* Initialize DL inactive list */
893 cmLListInit(&dlInactvLst);
895 /* Initialize UL inactive list */
896 cmLListInit(&ulInactvLst);
898 delInUlScan = cell->drxCb->delInUlScan;
901 index1 = (curTimeInSf) % RG_SCH_MAX_DRXQ_SIZE;
908 ueCb = (RgSchUeCb *)node->node;
909 ueDrxCb = ueCb->drxCb;
911 /* Stop inactivity timer */
912 if ( ueDrxCb->drxInactvIndx != DRX_INVALID )
914 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->drxInactvIndx].inActvTmrQ),
915 &(ueDrxCb->inActvTmrEnt));
919 rgSCHDrxCalcNxtTmrExpry(cell,
922 ueDrxCb->inactvtyTmrLen,
923 &(ueDrxCb->drxInactDistance),
928 inActvTmrExpIndx = (index1 + ueDrxCb->inactvtyTmrLen)
929 % RG_SCH_MAX_DRXQ_SIZE;
931 ueDrxCb->drxInactDistance = ueDrxCb->inactvtyTmrLen
932 / RG_SCH_MAX_DRXQ_SIZE;
935 cmLListAdd2Tail(&(cell->drxCb->drxQ[inActvTmrExpIndx].inActvTmrQ),
936 &(ueDrxCb->inActvTmrEnt));
938 ueDrxCb->inActvTmrEnt.node = (PTR)ueCb;
940 ueDrxCb->drxInactvIndx = inActvTmrExpIndx;
942 /* Update DRX InActive both masks */
943 ueDrxCb->drxUlInactvMask &= ~RG_SCH_DRX_INACTVTMR_BITMASK;
944 ueDrxCb->drxDlInactvMask &= ~RG_SCH_DRX_INACTVTMR_BITMASK;
946 /* Update UE's Inactive masks */
947 ueCb->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
948 ueCb->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
950 if ( delInUlScan == TRUE)
952 if ( ueDrxCb->inactvtyTmrLen == RGR_DRX_PRD_1PSF)
954 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
955 ueDrxCb->drxDlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
957 /* if no other condition is keeping ue inactive,
960 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(ueDrxCb) )
962 ueCb->dl.dlInactvMask |= RG_DRX_INACTIVE;
964 /* Add to DL inactive list */
965 cmLListAdd2Tail(&dlInactvLst,&(ueCb->dlDrxInactvLnk));
966 ueCb->dlDrxInactvLnk.node = (PTR)ueCb;
968 }/*if ( ueDrxCb->inactvyTmrLen...*/
970 }/*delInUlScan==TRUE*/
973 if ( ueDrxCb->inactvtyTmrLen == RGR_DRX_PRD_1PSF )
975 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
976 ueDrxCb->drxUlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
977 /* if no other condition is keeping ue inactive,
980 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(ueDrxCb) )
982 ueCb->ul.ulInactvMask |= RG_DRX_INACTIVE;
984 if ( !RG_SCH_CMN_UL_IS_UE_ACTIVE(ueCb))
986 /* Add to UL inactive list */
987 cmLListAdd2Tail(&ulInactvLst,&(ueCb->ulDrxInactvLnk));
988 ueCb->ulDrxInactvLnk.node = (PTR)ueCb;
990 }/*if ( !RG_SCH_DRX....)*/
991 }/*if (ueDrxCb->inactv...*/
994 /* move the link list forward */
998 cmLListDelFrm(ueLst, delNode);
999 delNode->node = NULLP;
1003 /* Send the list to the scheduler to mark UE as inactive in UL*/
1004 cellSch = RG_SCH_CMN_GET_CELL(cell);
1005 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
1007 /* Send the DL inactive list to the scheduler to mark UE as inactive */
1008 cellSch = RG_SCH_CMN_GET_CELL(cell);
1009 cellSch->apisDl->rgSCHDlInactvtUes(cell,&dlInactvLst);
1012 }/*rgSCHDrxStrtInActvTmr*/
1014 /** @brief This function is called by the downlink HARQ module on receiving a
1015 * negative feedback from the UE for a PDSCH transmission.
1018 * Invoked by - rgSCHDhmHqTrnsFail
1020 * Function: rgSCHDrxStartHarqRTTTmr
1025 * @param RgSchCellCb *cell
1026 * @param RgSchDlHqProcCb *dlHq
1031 Void rgSCHDrxStartHarqRTTTmr
1034 RgSchDlHqProcCb *hqP,
1038 Void rgSCHDrxStartHarqRTTTmr(cell, hqP, tbCnt)
1040 RgSchDlHqProcCb *hqP;
1044 RgSchDRXCellCb *drxCell =NULLP;
1045 RgSchDrxDlHqProcCb *drxHq =NULLP;
1049 U8 firstDlTxOcassion;
1050 U8 drxRetxTmrStartSf;
1052 TRC2(rgSCHDrxStartHarqRTTTmr);
1055 drxCell = RG_SCH_DRX_GET_CELL(cell);
1056 drxHq = RG_SCH_DRX_GET_DL_HQ(hqP);
1059 /* ccpu00134196-[Add]-DRX retx timer changes */
1060 firstDlTxOcassion = rgSchDrxHarqRetxFirstPsf[cell->ulDlCfgIdx]
1061 [hqP->tbInfo[tbCnt].fdbkTime.subframe];
1063 harqRTTExpIndx = ((hqP->tbInfo[tbCnt].fdbkTime.sfn * 10) +
1064 hqP->tbInfo[tbCnt].fdbkTime.subframe + firstDlTxOcassion)
1065 % RG_SCH_MAX_DRXQ_SIZE;
1067 fdbkDelta = RGSCH_CALC_SF_DIFF(cell->crntTime, hqP->tbInfo[tbCnt].fdbkTime);
1070 /* For FDD HARQ RTT expiry index is 8 subframes from the time
1071 * corresponding PDSCH was scheduled. We are adding 1 subframe
1072 * so that UE is scheduled for retransmission in the next subframe*/
1073 /* ccpu00134196-[Add]-DRX retx timer changes */
1074 harqRTTExpIndx = ((hqP->tbInfo[tbCnt].timingInfo.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1075 hqP->tbInfo[tbCnt].timingInfo.slot + RG_SCH_MIN_HARQ_RTT)
1076 % RG_SCH_MAX_DRXQ_SIZE;
1078 fdbkDelta = RGSCH_CALC_SF_DIFF(cell->crntTime, hqP->tbInfo[tbCnt].timingInfo);
1080 /* ccpu00134196-[Add]-DRX retx timer changes */
1081 /* ensure that the insertion into the queue happens at an index
1082 greater than the dl index, ie, do +1 */
1083 /* Instead of depending on TTI details of current time and HARQ RTT Expire
1084 * time, Handling this check with deltas, because with TTIs it is not possible
1085 * to handle wrap-around condition*/
1087 if(fdbkDelta + RG_SCH_DRX_DL_DELTA >= firstDlTxOcassion)
1089 /* The retx timer length should be reduced.
1090 This means based on the platforms delta between the DL HARQ
1091 processing and DL scheduling, drx retx timer lengths of 1ms/2ms
1092 may not be possible */
1093 drxRetxTmrStartSf = (hqP->tbInfo[tbCnt].fdbkTime.subframe +
1094 firstDlTxOcassion) % RGSCH_NUM_SUB_FRAMES;
1096 /* We are here because the Retx Timer start is moved by atleast one
1097 position. Hence the timer will be reduced by minimum one */
1098 drxHq->retxTmrReduction = 1;
1100 /* Now check the consecutive subframes starting from the actual
1101 starting position of the retx tmr till the new position. Reduce the
1102 timer value only if the sf is a Pdcch sf */
1103 for(i = 1; i <= fdbkDelta + RG_SCH_DRX_DL_DELTA-firstDlTxOcassion+ 1; i++)
1105 if (rgSchTddUlDlSubfrmTbl[cell->ulDlCfgIdx]
1106 [(drxRetxTmrStartSf+i)%RGSCH_NUM_SUB_FRAMES]
1107 != RG_SCH_TDD_UL_SUBFRAME)
1109 drxHq->retxTmrReduction++;
1113 if(fdbkDelta + RG_SCH_DRX_DL_DELTA >= RG_SCH_MIN_HARQ_RTT)
1115 drxHq->retxTmrReduction =
1116 fdbkDelta + RG_SCH_DRX_DL_DELTA - RG_SCH_MIN_HARQ_RTT+ 1;
1119 harqRTTExpIndx = (harqRTTExpIndx + drxHq->retxTmrReduction) %
1120 RG_SCH_MAX_DRXQ_SIZE;
1124 drxHq->retxTmrReduction = 0;
1126 cmLListAdd2Tail (&(drxCell->drxQ[harqRTTExpIndx].harqRTTQ),
1127 &(drxHq->harqRTTEnt));
1129 drxHq->harqRTTEnt.node = (PTR)hqP;
1130 drxHq->rttIndx = harqRTTExpIndx;
1134 }/*rgSCHDrxStartHarqRTTTmr*/
1137 /** @brief This function is called by the Configuration module to give a
1138 * trigger to DRX module for UE configuration.
1142 * Function: rgSCHDrxUeCfg
1145 * - Copy configuration information into drxUe structure.
1146 * - Calculate the first occurance of onDuration based on values
1147 * provided in the configuration structure.
1148 * - Append the UE to the onDurationQ at that index.
1149 * - The UE must be appened to the list based on the timing calculated
1150 * above (nxtSfn, nxtSubframe).
1152 * @param RgSchCellCb *cell Cell control block.
1153 * @param RgSchUeCb *ue UE control block.
1154 * @param RgrUeCfg *ueCfg RGR UE configuration information.
1167 S16 rgSCHDrxUeCfg (cell, ue, ueCfg)
1174 RgSchDrxUeCb *ueDrxCb;
1175 CmLteTimingInfo nxtOnDur;
1182 TRC2(rgSCHDrxUeCfg);
1185 #if ( ERRCLASS & ERRCLS_INT_PAR )
1186 if ( cell == (RgSchCellCb* )NULLP)
1191 if ((ue == (RgSchUeCb* )NULLP)
1193 (ueCfg == (RgrUeCfg* )NULLP))
1195 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId, "rgSCHDrxUeCfg():"
1196 "Invalid params.cell or ue or ueCfg is NULL ");
1202 /* allocate and initialize drxCb */
1203 ret = rgSCHUtlAllocSBuf(cell->instIdx, (Data**)&ue->drxCb,
1204 (sizeof(RgSchDrxUeCb)));
1208 RLOG_ARG1(L_ERROR,DBG_CELLID,cell->cellId,
1209 "Memory allocation FAILED for DRX UECB CRBTI:%d",ue->ueId);
1213 ueDrxCb = ue->drxCb;
1215 /* initialize the masks */
1216 ueDrxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1217 ueDrxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1218 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
1219 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
1221 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1223 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1224 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1227 /* Copy the configuration values into the UE's DRX CB. */
1228 rgSCHDrxCpyUeCfg (ueDrxCb, &ueCfg->ueDrxCfg);
1232 rgSCHEmtcDrxCpyUeCfg(ue ,&ueCfg->ueDrxCfg);
1236 /* set all indexes to default values */
1237 ueDrxCb->onDurIndx = DRX_INVALID;
1238 ueDrxCb->onDurExpIndx = DRX_INVALID;
1239 ueDrxCb->drxInactvIndx = DRX_INVALID;
1240 ueDrxCb->shortCycleIndx = DRX_INVALID;
1242 /* set all distances to timer expiry */
1243 ueDrxCb->onDurExpDistance = DRX_TMR_EXPRD;
1244 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
1245 ueDrxCb->drxShortCycleDistance = DRX_TMR_EXPRD;
1246 ueDrxCb->distance = DRX_TMR_EXPRD;
1248 /* Mark the UE in long/short cycle initially as per configuration*/
1249 if(FALSE == ueDrxCb->isShortCycleCfgd)
1251 ueDrxCb->isLongCycle = TRUE;
1255 ueDrxCb->isLongCycle = FALSE;
1258 /* Calculate the next occurance from this point */
1259 rgSCHDrxGetNxtOnDur (cell, ueDrxCb, &nxtOnDur,RG_SCH_NO_DELTA);
1262 nxtOnDurTime = ((nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur.slot);
1263 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1264 cell->crntTime.slot);
1266 onDurIndx = nxtOnDurTime % RG_SCH_MAX_DRXQ_SIZE;
1268 ueDrxCb->distance = (nxtOnDurTime - curTime) / RG_SCH_MAX_DRXQ_SIZE;
1269 if (ueDrxCb->distance < 0)
1271 RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId, "DRXUE. Invalid "
1272 "value for distance, %d CRNTI:%d", ueDrxCb->distance,ue->ueId);
1274 //printf("The onduartion index is: %d\n",(int)onDurIndx);
1275 cmLListAdd2Tail(&(cell->drxCb->drxQ[onDurIndx].onDurationQ),
1276 &(ueDrxCb->onDurationEnt));
1278 ueDrxCb->onDurationEnt.node = (PTR)ue;
1279 ueDrxCb->onDurIndx = onDurIndx;
1281 /* Starting Short Cycle Timer */
1282 if(TRUE == ueDrxCb->isShortCycleCfgd)
1284 ueDrxCb->drxShortCycleDistance = (ueDrxCb->shortCycleTmrLen *
1285 ueDrxCb->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
1286 ueDrxCb->shortCycleIndx = (curTime + (ueDrxCb->shortCycleTmrLen *
1287 ueDrxCb->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
1288 cmLListAdd2Tail(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1289 &(ueDrxCb->shortCycleEnt));
1290 ueDrxCb->shortCycleEnt.node = (PTR)ue;
1294 } /* end of rgSCHDrxUeCfg */
1296 /** @brief This function gets the next occurance of onDurationTimer from the
1299 * @details rgSCHDrxGetNxtOnDur
1301 * Function: rgSCHDrxGetNxtOnDur
1303 * Processing steps: -
1304 * Calculation of first occurance of onDuration is to be done as
1306 * Assume DRX configuration came at subframe (x, y) the periodicity is
1307 * offset = (perd, offset).
1308 * The (sfn, subframe) satisfying the following condition is the first
1309 * occurance from this point.
1311 * (sfn * 10 + subframe) mod perd = offset
1316 * @param RgSchCellCb *cell
1317 * @param RgSchDrxUeCb *drxCb
1318 * @param CmLteTimingInfo *nxtOnDur
1320 * @return ROK/RFAILED
1323 PRIVATE S16 rgSCHDrxGetNxtOnDur
1326 RgSchDrxUeCb *drxCb,
1327 CmLteTimingInfo *nxtOnDur,
1331 PRIVATE S16 rgSCHDrxGetNxtOnDur (cell, drxCb, nxtOnDur, delta)
1333 RgSchDrxUeCb *drxCb;
1334 CmLteTimingInfo *nxtOnDur;
1344 TRC3(rgSCHDrxGetNxtOnDur);
1346 #if ( ERRCLASS & ERRCLS_INT_PAR )
1347 if ( cell == (RgSchCellCb* )NULLP )
1352 if( (drxCb == (RgSchDrxUeCb* )NULLP)
1354 (nxtOnDur == (CmLteTimingInfo* )NULLP)
1357 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
1358 "rgSCHDrxGetNxOnDur():Invalid params."
1359 "cell/drxCb/nxtOnDur is NULL");
1365 if (TRUE == drxCb->isLongCycle)
1367 cycleLen = drxCb->longDrxCycle;
1371 cycleLen = drxCb->shortDrxCycle;
1374 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) + cell->crntTime.slot);
1376 curTime += delta; /*TODO: see if we need to take care of wrap arounds */
1378 if ( curTime <= drxCb->drxStartOffset )
1380 /* offset is the nextOnDur */
1381 nxtOnDur->sfn = drxCb->drxStartOffset / RGSCH_NUM_SUB_FRAMES_5G;
1382 nxtOnDur->slot = (U8)(drxCb->drxStartOffset % RGSCH_NUM_SUB_FRAMES_5G);
1383 nxtDist = ((nxtOnDur->sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur->slot);
1387 curDist = curTime - drxCb->drxStartOffset;
1389 numOfCycles = curDist / cycleLen;
1391 if (0 == (curDist % cycleLen))
1393 /* Perfect match pick up the current time */
1394 /*nxtOnDur should be set to equal to currentTime + DELTA */
1395 nxtOnDur->sfn = (U16)curTime / RGSCH_NUM_SUB_FRAMES_5G;
1396 nxtOnDur->slot = (U16)curTime % RGSCH_NUM_SUB_FRAMES_5G;
1397 nxtDist = ((nxtOnDur->sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur->slot);
1402 nxtDist = drxCb->drxStartOffset + (numOfCycles + 1) *
1404 nxtOnDur->sfn = (U16)nxtDist / RGSCH_NUM_SUB_FRAMES_5G;
1405 nxtOnDur->slot = (U16)nxtDist % RGSCH_NUM_SUB_FRAMES_5G;
1410 /*If next On Duration is less than DL DELTA ahead, we will miss it and
1411 * hence need to move to the On-Duration after that.*/
1412 if((nxtDist - (curTime - delta)) <= RG_SCH_DRX_MAX_DELTA)
1414 nxtDist = nxtDist + cycleLen;
1415 nxtOnDur->sfn = (U16)nxtDist / RGSCH_NUM_SUB_FRAMES_5G;
1416 nxtOnDur->slot = (U16)nxtDist % RGSCH_NUM_SUB_FRAMES_5G;
1419 } /* end of rgSCHDrxGetNxtOnDur */
1421 /** @brief This function is a utility function to copy the UE configuration from
1422 * the RGR structure to the UE control block.
1425 * -Invoked by rgSCHDrxUeCfg
1427 * Function: rgSCHDrxCpyUeCfg
1430 * - Copies configuration values
1432 * @param RgSchDrxUeCb *ueCb
1433 * @param RgrUeDrxCfg *drxCfg
1434 * @return ROK/RFAILED
1437 PRIVATE S16 rgSCHDrxCpyUeCfg
1443 PRIVATE S16 rgSCHDrxCpyUeCfg (ueCb, drxCfg)
1445 RgrUeDrxCfg *drxCfg;
1448 TRC3(rgSCHDrxCpyUeCfg);
1450 #if ( ERRCLASS & ERRCLS_INT_PAR )
1451 if ( (ueCb == (RgSchDrxUeCb* )NULLP )
1453 (drxCfg == (RgrUeDrxCfg* )NULLP)
1461 /* Copy all values to UE control block */
1463 ueCb->cqiMask = drxCfg->cqiMask;
1464 #endif /*LTEMAC_R9*/
1465 ueCb->onDurTmrLen = drxCfg->drxOnDurTmr;
1466 ueCb->inactvtyTmrLen = drxCfg->drxInactvTmr;
1467 ueCb->drxRetransTmrLen = drxCfg->drxRetxTmr;
1468 ueCb->longDrxCycle = drxCfg->drxLongCycleOffst.longDrxCycle;
1469 ueCb->drxStartOffset = drxCfg->drxLongCycleOffst.drxStartOffst;
1470 ueCb->isShortCycleCfgd = drxCfg->drxShortDrx.pres;
1471 ueCb->shortDrxCycle = drxCfg->drxShortDrx.shortDrxCycle;
1472 ueCb->shortCycleTmrLen = drxCfg->drxShortDrx.drxShortCycleTmr;
1475 } /* end of rgSCHDrxCpyUeCfg */
1478 /** @brief This function is called by the configuration module when a UE is
1479 * reconfigured for DRX parameters.
1482 * Invoked By - rgSCHCfgRgrUeCfg
1484 * Function: rgSCHDrxUeReCfg
1485 * As per MAC specifications the new values of timers shall be applied only once
1486 * they are restarted, hence no processing is required for modified timer values.
1489 * - if offset and/or drxCycleLenght changes then recalculate the next
1491 * - remove the UE from current index
1492 * - add the UE to the new index.
1493 * - if short cycle is enabled
1494 * - set isShortCycleCfgd = TRUE
1496 * @param RgSchCellCb *cell
1497 * @param RgSchUeCb *ue
1498 * @param RgrUeRecfg *ueReCfg
1499 * @return ROK/RFAILED
1509 S16 rgSCHDrxUeReCfg (cell, ue, ueReCfg)
1512 RgrUeRecfg *ueReCfg;
1516 RgSchCmnCell *cellSch = NULLP;
1517 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
1520 Inst instIdx = cell->instIdx;
1521 RgSchDrxUeCb *ueDrxCb;
1522 CmLteTimingInfo nxtOnDur;
1526 U16 shrtCycleExpIndx;
1532 TRC2(rgSCHDrxUeReCfg);
1535 /* drx was disabled but now enabled for this ue */
1536 if ( (ue->isDrxEnabled == FALSE)
1538 (ueReCfg->ueDrxRecfg.isDrxEnabled == TRUE)
1541 /* allocated and initialize drxCb */
1542 ret = rgSCHUtlAllocSBuf(instIdx, (Data**)&ue->drxCb,
1543 (sizeof(RgSchDrxUeCb)));
1547 RLOG_ARG1(L_ERROR,DBG_CELLID,cell->cellId,
1548 "rgSCHdrxUeReCfg():""Memory allocation FAILED for DRX UE Cb CRNTI:%d",
1553 ue->isDrxEnabled = TRUE; /* sachin */
1554 /* initialize the masks */
1555 ue->drxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1556 ue->drxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1557 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
1558 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
1560 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1562 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1563 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1566 /* set all indexes to default values */
1567 ue->drxCb->onDurIndx = DRX_INVALID;
1568 ue->drxCb->onDurExpIndx = DRX_INVALID;
1569 ue->drxCb->drxInactvIndx = DRX_INVALID;
1570 ue->drxCb->shortCycleIndx = DRX_INVALID;
1572 /* set all distances to timer expiry */
1573 ue->drxCb->onDurExpDistance = DRX_TMR_EXPRD;
1574 ue->drxCb->drxInactDistance = DRX_TMR_EXPRD;
1575 ue->drxCb->drxShortCycleDistance = DRX_TMR_EXPRD;
1576 ue->drxCb->distance = DRX_TMR_EXPRD;
1579 if( ue->drxCb == NULLP )
1583 ueDrxCb = ue->drxCb;
1585 /*drx was enabled but now disabled for this UE */
1586 if ( (ue->isDrxEnabled == TRUE )
1588 (ueReCfg->ueDrxRecfg.isDrxEnabled == FALSE)
1591 /* remove UE from all DRX Queues */
1592 (Void)rgSCHDrxUeDel(cell,ue);
1595 /* ccpu00117052 - MOD - Passing double pointer
1596 for proper NULLP assignment*/
1597 rgSCHUtlFreeSBuf(instIdx,(Data **)(&((ue->drxCb))),
1598 sizeof(RgSchDrxUeCb));
1600 /* Resetting the DRX Bit set in Inactv Mask */
1601 ue->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
1602 ue->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
1604 ue->isDrxEnabled = FALSE;
1606 }/*isDrxEnabled == FALSE */
1609 /* If Application is updating DRX params */
1610 if (ueReCfg->ueRecfgTypes & RGR_UE_DRX_RECFG )
1612 rgSCHDrxCpyUeCfg (ueDrxCb, &ueReCfg->ueDrxRecfg);
1616 rgSCHEmtcDrxCpyUeCfg(ue, &ueReCfg->ueDrxRecfg);
1622 /* Removing the UE from existing index of shortcycle, if any*/
1623 if(ueDrxCb->shortCycleIndx != DRX_INVALID)
1625 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1626 &(ueDrxCb->shortCycleEnt));
1628 ueDrxCb->shortCycleEnt.node = (PTR) NULLP;
1629 ueDrxCb->shortCycleIndx = DRX_INVALID;
1632 /* Mark for intiating long/short cycle as per received config */
1633 if(FALSE == ue->drxCb->isShortCycleCfgd)
1635 ue->drxCb->isLongCycle = TRUE;
1639 ue->drxCb->isLongCycle = FALSE;
1642 /* Calculate the next occurance from this point */
1643 rgSCHDrxGetNxtOnDur (cell, ueDrxCb, &nxtOnDur,RG_SCH_NO_DELTA);
1645 /* remove the UE from the current onDuration Queue */
1646 if ( ueDrxCb->onDurIndx != DRX_INVALID )
1648 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurIndx].onDurationQ),
1649 &(ueDrxCb->onDurationEnt));
1653 nxtOnDurTime = (nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur.slot;
1654 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1655 cell->crntTime.slot);
1657 /* If Onduration timer of old configuration is already running then waiting till it expires */
1658 if((ueDrxCb->onDurExpIndx != DRX_INVALID) && (ueDrxCb->onDurExpDistance != DRX_TMR_EXPRD))
1660 curIndx = (curTime + RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
1661 RLOG_ARG3(L_DEBUG,DBG_CELLID,cell->cellId,
1662 "OLD ONDUR RUNNING-EXPIRES at %d curIdx-%d nxtOnDurTime-%d",
1663 ueDrxCb->onDurExpIndx,
1667 /* Manipulating the time when old onDuration timer can expire */
1668 if(curIndx >= ueDrxCb->onDurExpIndx)
1670 onDurExpTime = curTime + ((ueDrxCb->onDurExpDistance+1) * RG_SCH_MAX_DRXQ_SIZE)+ (ueDrxCb->onDurExpIndx - curIndx + RG_SCH_DRX_DL_DELTA);
1674 onDurExpTime = curTime + (ueDrxCb->onDurExpDistance * RG_SCH_MAX_DRXQ_SIZE)+ (ueDrxCb->onDurExpIndx - curIndx + RG_SCH_DRX_DL_DELTA);
1677 if(nxtOnDurTime <= onDurExpTime)
1679 if(ueDrxCb->isLongCycle)
1681 cycleLen = ueDrxCb->longDrxCycle;
1685 cycleLen = ueDrxCb->shortDrxCycle;
1687 /* Moving to the possible occassion of onduration after current onduration expiry:
1688 * If both are aligning then going for next cycle */
1689 nxtOnDurTime += ((onDurExpTime - nxtOnDurTime)/cycleLen + 1 ) *cycleLen ;
1692 /* Add the UE to the index which corresponds to the next onduration start*/
1693 onDurIndx = nxtOnDurTime % RG_SCH_MAX_DRXQ_SIZE;
1695 ueDrxCb->distance = (nxtOnDurTime - curTime) / RG_SCH_MAX_DRXQ_SIZE;
1696 if (ueDrxCb->distance < 0)
1698 RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId,"DRXUE. Invalid "
1699 "value for distance, %d CRNTI:%d", ueDrxCb->distance,ue->ueId);
1702 cmLListAdd2Tail(&(cell->drxCb->drxQ[onDurIndx].onDurationQ),
1703 &(ueDrxCb->onDurationEnt));
1705 ueDrxCb->onDurationEnt.node = (PTR)ue;
1706 ueDrxCb->onDurIndx = onDurIndx;
1709 cmLListInit(&dlInactvLst);
1710 /* Add to DL inactive list */
1711 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
1712 ue->dlDrxInactvLnk.node = (PTR)ue;
1713 /* Send the list to the scheduler to mark UE as inactive */
1714 cellSch = RG_SCH_CMN_GET_CELL(cell);
1715 cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
1718 /* Starting short cycle timer as per the existence of old onDuration timer */
1719 if(TRUE == ueDrxCb->isShortCycleCfgd)
1721 /* Expiring short DRX cycle Tmr once the number of short DRX cycles done */
1722 ueDrxCb->drxShortCycleDistance = (nxtOnDurTime + ueDrxCb->onDurTmrLen + (ueDrxCb->shortCycleTmrLen -1 )*
1723 ueDrxCb->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
1724 shrtCycleExpIndx = (nxtOnDurTime + ueDrxCb->onDurTmrLen + ((ueDrxCb->shortCycleTmrLen -1)*
1725 ueDrxCb->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
1726 cmLListAdd2Tail(&(cell->drxCb->drxQ[shrtCycleExpIndx].shortCycleQ),
1727 &(ueDrxCb->shortCycleEnt));
1728 ueDrxCb->shortCycleEnt.node = (PTR)ue;
1729 ueDrxCb->shortCycleIndx = shrtCycleExpIndx;
1735 } /* end of rgSCHDrxUeReCfg */
1738 /** @brief This function Loop through the list of HARQ processes for this
1739 * UE and delete from the harqRTTQ and harqRetxQ
1741 * Function: rgSCHDrxUeHqReset
1742 * Invoked by rgSCHDrxUeDel
1745 Loop through the list of HARQ processes for this UE and delete from
1746 * the harqRTTQ and harqRetxQ.
1748 * @param RgSchCellCb *cell
1749 * @return ROK/RFAILED
1752 Void rgSCHDrxUeHqReset
1760 Void rgSCHDrxUeHqReset(cell, ue, hqE, cellIdx)
1767 RgSchDlHqProcCb *hqP;
1768 RgSchDrxDlHqProcCb *drxHq =NULLP;
1771 TRC2(rgSCHDrxUeHqReset);
1773 for(i=0; i < hqE->numHqPrcs; i++)
1775 hqP = &hqE->procs[i];
1776 drxHq = RG_SCH_DRX_GET_DL_HQ(hqP);
1778 if(drxHq->rttIndx != DRX_INVALID)
1780 cmLListDelFrm (&(cell->drxCb->drxQ[drxHq->rttIndx].harqRTTQ),
1781 &(drxHq->harqRTTEnt));
1783 drxHq->rttIndx = DRX_INVALID;
1786 if(drxHq->reTxIndx != DRX_INVALID)
1788 cmLListDelFrm (&(cell->drxCb->drxQ[drxHq->reTxIndx].harqRetxQ),
1789 &(drxHq->harqRetxEnt));
1791 drxHq->reTxIndx = DRX_INVALID;
1795 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1796 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1799 /** @brief This function Deletes DRX specific context for a UE.
1801 * @details This funciton is invoked by the Configuration module on RGR UE Deletion.
1802 * This function removes the UE's context from all of the DRX Queues.
1803 * In addition it deletes context of UE's HARQ Processes present in the harqRTTQ
1807 * Function: rgSCHDrxUeDel
1808 * Invoked by rgSCHCfgRgrUeDel
1811 * - Remove the UE from the following queues
1812 * - onDurationQ - using onDurIndx
1813 * - onDurationExpQ - using onDurExpIndx
1814 * - inActvTmrQ - using drxInactvIndx
1815 * - shortCycleQ - using shortCycleIndx
1816 * - Loop through the list of HARQ processes for this UE and delete from
1817 * the harqRTTQ and harqRetxQ.
1819 * @param RgSchCellCb *cell
1820 * @param RgSchUeCb *ue
1821 * @return ROK/RFAILED
1830 S16 rgSCHDrxUeDel (cell, ue)
1835 RgSchDrxUeCb *ueDrxCb;
1836 RgSchDlHqEnt *hqE = NULLP;
1838 RgSchUeCellInfo *cellInfo = NULLP;
1840 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
1842 TRC2(rgSCHDrxUeDel);
1845 /* ccpu00129899: Moved the drx-enabled check to the caller */
1846 ueDrxCb = ue->drxCb;
1848 /* Remove UE from all queues */
1849 if ( ueDrxCb->onDurIndx != DRX_INVALID )
1851 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurIndx].onDurationQ),
1852 &(ueDrxCb->onDurationEnt));
1854 ueDrxCb->onDurIndx = DRX_INVALID;
1857 if ( ueDrxCb->onDurExpIndx != DRX_INVALID )
1859 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurExpIndx].onDurationExpQ),
1860 &(ueDrxCb->onDurationExpEnt));
1862 ueDrxCb->onDurExpIndx = DRX_INVALID;
1865 if ( ueDrxCb->drxInactvIndx != DRX_INVALID )
1867 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->drxInactvIndx].inActvTmrQ),
1868 &(ueDrxCb->inActvTmrEnt));
1870 ueDrxCb->drxInactvIndx = DRX_INVALID;
1873 if ( ueDrxCb->shortCycleIndx != DRX_INVALID )
1875 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1876 &(ueDrxCb->shortCycleEnt));
1878 ueDrxCb->shortCycleIndx = DRX_INVALID;
1881 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1883 cellInfo = ue->cellInfo[cellIdx];
1887 hqE = cellInfo->hqEnt;
1888 rgSCHDrxUeHqReset(cell, ue, hqE, cellIdx);
1894 rgSCHDrxUeUlHqReset(cell, ue, &(ueUl->hqEnt));
1897 /* Resetting the DRX Bit set in Inactv Mask */
1898 ue->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
1899 ue->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
1900 ueDrxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1901 ueDrxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1906 /** @brief This function is called at the time of RGR cell configuration.
1909 * Invoked by - rgSCHCfgRgrCellCfg
1911 * Function: rgSCHDrxCellCfg
1914 * - Initializes the following drxQ (cmMemset would do).
1917 * @param RgSchCellCb *cell
1918 * @param RgrCellCfg *cellCfg
1919 * @return ROK/RFAILED
1928 S16 rgSCHDrxCellCfg (cell, cellCfg)
1930 RgrCellCfg *cellCfg;
1935 Inst instIdx = cell->instIdx;
1937 TRC2(rgSCHDrxCellCfg);
1940 #if ( ERRCLASS & ERRCLS_INT_PAR )
1941 /*KWORK_FIX :Removed check for cell being NULL*/
1942 if( (cellCfg == (RgrCellCfg* )NULLP))
1944 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
1945 "rgSCHDrxCellCfg():Invalid Params. cell/cellCfg is NULL");
1950 /* allocate and initialize drxCb */
1951 ret = rgSCHUtlAllocSBuf(instIdx, (Data**)&cell->drxCb,
1952 (sizeof(RgSchDRXCellCb)));
1956 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,"rgSCHDrxCellCfg():"
1957 "Memory allocation FAILED for DRX cell Cb");
1961 /* delInUlScan determines which index scans the queue last.
1962 * We look at onDurationQ both from ulIndex & dlIndex pov.
1963 * Consider, onDuration starts at index 5, and current index is 2,
1964 * while dlIndex is 2 & ulIndex is 3 i.e dl is looking 2 SF ahead
1965 * and ul is looking 3 SF ahead. In this case, dl will scan the queue
1966 * last and therefore DL will delete ueCb from onDuration q.
1967 * The reverse is true for the other case.*/
1969 if ( RG_SCH_DRX_UL_DELTA > RG_SCH_DRX_DL_DELTA )
1971 cell->drxCb->delInUlScan = FALSE;
1975 cell->drxCb->delInUlScan = TRUE;
1979 } /* end of rgSchDrxCellCfg */
1983 /** @brief This function to delete DRX specific context in the cell control
1987 * Invoked by - rgSCHCfgRgrCellDel
1989 * Function: rgSCHDrxCellDel
1992 * - De-Inits RgSchDRXCellCb (Nothing to be done)
1993 * - Assumption: The API is invoked after deletion of UEs from the cell.
1995 * @param RgSchCellCb *cell
1999 Void rgSCHDrxCellDel
2004 Void rgSCHDrxCellDel (cell)
2008 Inst instIdx = cell->instIdx;
2010 TRC2(rgSCHCfgRgrCellDel);
2015 /* ccpu00117052 - MOD - Passing double pointer
2016 for proper NULLP assignment*/
2017 rgSCHUtlFreeSBuf(instIdx, (Data **)(&(cell->drxCb)),
2018 sizeof(RgSchDRXCellCb));
2021 } /* end of rgSchDrxCellDel */
2023 /** @brief This function is called when an SR is received from the UE. In this
2024 * case the UE should be marked as ACTIVE till we send a UL allocation to the
2028 * Invoked by - rgSCHCmnSrRcvd
2029 * Must be called after calling the specific scheduler.
2031 * Function: rgSCHDrxSrInd
2034 * - Mark the UE as ACTIVE
2035 * ueCb->drxUlInactvMask |= (DRX_SR_ACTIVE);
2036 * - Optionally call schedulers to add this UE to their scheduling
2038 * - Set drxUe->srRcvd = TRUE
2040 * Note : the specification state that the UE shall start be active
2041 * listening for UL grant, this implies we could potentially exploit
2042 * this to send DL transmissions as well. However we have currently
2043 * chosen not to do so.
2045 * @param RgSchCellCb *cell
2046 * @param RgSchUeCb *ue
2047 * @return ROK/RFAILED
2056 S16 rgSCHDrxSrInd (cell, ue)
2061 RgSchDrxUeCb *drxCb;
2063 TRC2(rgSCHDrxSrInd);
2066 #if ( ERRCLASS & ERRCLS_INT_PAR )
2067 if ( cell == (RgSchCellCb* )NULLP)
2072 if( (ue == (RgSchUeCb* )NULLP))
2074 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
2075 "rgSCHDrxSrInd():Invalid Params. cell/ue is NULL");
2079 /* KWork fix - shifted this down */
2082 drxCb = RG_SCH_DRX_GET_UE(ue);
2084 /* Mark the UE as active for UL only */
2085 drxCb->drxUlInactvMask &= ~RG_SCH_DRX_SR_BITMASK;
2086 drxCb->srRcvd = TRUE;
2087 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2088 RG_SCH_CMN_UL_UPDT_INACTV_MASK( cell, ue, RG_DRX_INACTIVE);
2091 } /* rgSCHDrxSrInd */
2094 /** @brief This function handles ACTIVITY due to RACH using a dedicated preamble
2095 * (PDCCH order) OR Handover. A UE shall remain marked as active from the time
2096 * we successfully send out a RAR upto the time it receives a PDCCH indicating a
2100 * Invoked by - rgSCHCmnHdlHoPo
2102 * Function: rgSCHDrxDedRa
2105 * - MARK the UE as active
2106 * - set the raRcvd = TRUE for this UE.
2109 * ueCb->drxDlInactvMask |= (DRX_RA_ACTIVE);
2110 * ueCb->drxUlInactvMask |= (DRX_RA_ACTIVE);
2111 * ueCb->raRcvd = TRUE;
2114 * @param RgSchCellCb *cellCb
2115 * @param RgSchUeCb *ueCb
2121 RgSchCellCb *cellCb,
2125 Void rgSCHDrxDedRa (cellCb, ueCb)
2126 RgSchCellCb *cellCb;
2130 RgSchDrxUeCb *drxCb;
2132 TRC2(rgSCHDrxDedRa);
2135 drxCb = RG_SCH_DRX_GET_UE(ueCb);
2137 /* Mark the UE as active for UL & DL */
2138 drxCb->drxUlInactvMask &= ~RG_SCH_DRX_RA_BITMASK;
2139 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2140 RG_SCH_CMN_UL_UPDT_INACTV_MASK(cellCb, ueCb, RG_DRX_INACTIVE);
2142 drxCb->drxDlInactvMask &= ~RG_SCH_DRX_RA_BITMASK;
2143 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2144 RG_SCH_CMN_DL_UPDT_INACTV_MASK(cellCb, ueCb, RG_DRX_INACTIVE);
2146 drxCb->raRcvd = TRUE;
2149 } /* end of rgSCHDrxDedRa */
2152 /** @brief This function calculates the next onDuration Occurence
2153 * and removes & queue it again in onDurationQ
2158 * Function: rgSCHDrxMvToNxtOnDurOcc
2163 * @param RgSchCellCb *cell
2164 * @param RgSchUeCb *ueCb
2165 * @param U16 idx - if calcFrmOffst is TRUE,
2166 * idx is delta to be added
2167 * @param Bool calcFrmOffst
2171 PRIVATE Void rgSCHDrxMvToNxtOnDurOcc
2179 PRIVATE Void rgSCHDrxMvToNxtOnDurOcc (cell, ueCb, idx, calcFrmOffst)
2188 RgSchDrxUeCb *drxUe;
2189 RgSchDRXCellCb *drxCell;
2190 CmLteTimingInfo nxtOnDur; /* to be used when calcFrmOffset is set */
2191 U16 nxtOnDurInSf; /* next On Duration in no of subframes */
2193 drxCell = cell->drxCb;
2194 drxUe = ueCb->drxCb;
2196 TRC2(rgSCHDrxMvToNxtOnDurOcc)
2198 if(calcFrmOffst == FALSE)
2200 if (drxUe->isLongCycle)
2202 nxtOnDurIndex = ((idx + drxUe->longDrxCycle)
2203 % RG_SCH_MAX_DRXQ_SIZE );
2204 drxUe->distance = drxUe->longDrxCycle/RG_SCH_MAX_DRXQ_SIZE;
2208 nxtOnDurIndex = ((idx + drxUe->shortDrxCycle)% RG_SCH_MAX_DRXQ_SIZE);
2210 drxUe->distance = drxUe->shortDrxCycle / RG_SCH_MAX_DRXQ_SIZE;
2215 rgSCHDrxGetNxtOnDur(cell,drxUe,&nxtOnDur,(U8)idx);
2217 nxtOnDurInSf = ((nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
2220 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
2221 cell->crntTime.slot);
2223 nxtOnDurIndex = nxtOnDurInSf % RG_SCH_MAX_DRXQ_SIZE;
2224 drxUe->distance = (nxtOnDurInSf-curTime) / RG_SCH_MAX_DRXQ_SIZE;
2225 if (drxUe->distance < 0)
2227 RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId,"DRXUE. Invalid "
2228 "value for distance, %d CRNTI:%d", drxUe->distance,ueCb->ueId);
2232 /* First remove from existing location */
2233 if ( drxUe->onDurIndx != DRX_INVALID )
2235 cmLListDelFrm(&(drxCell->drxQ[drxUe->onDurIndx].onDurationQ),
2236 &(drxUe->onDurationEnt));
2239 /* Add at new location */
2240 cmLListAdd2Tail(&(drxCell->drxQ[nxtOnDurIndex].onDurationQ),
2241 &(drxUe->onDurationEnt));
2243 drxUe->onDurationEnt.node = (PTR)ueCb;
2244 drxUe->onDurIndx = nxtOnDurIndex;
2247 }/*rgSCHDrxMvToNxtOnDurOcc*/
2250 /** @brief This function calculates the next SFN,subframe a given
2251 * timer is going to expire. Works for all TDD configurations.
2255 * Function: rgSCHDrxGetNxtTmrExpry
2256 * We need to count only PDCCH frames in a given TDD
2257 * configuration. This is true for onDuration, inActivity
2258 * & drx-retransmission timers.
2260 * Processing steps (assume timer starts at (12,2) and duration
2261 * is 23 DL subframes):
2262 * - based on TDD configuration, move to the next SFN and
2263 * count the number of DL subframes consumed. In our example,
2264 * moving to (12,9) will consume 6 DL subframes assuming TDD
2266 * - From this point on, determine how many exact Radio Frames
2267 * will be consumed for the remaining DL subframes. In our
2268 * example, remaining DL subframes are (23-6) are 17.
2269 * For config 2, the following holds true
2270 * 8 DLSF are in 1 RF
2271 * 1 DLSF in 1/8 DLSF
2272 * 17 DLSF in 17/8 i.e 2 RF + 1 subframe
2273 * In order to consume 17 DLSF, we need to move forward
2274 * 2 RFs + 1 subframe. Adding 2 RF's gives us (14,9)
2275 * - For the remaining subframe, we need to figure out the next
2276 * available DL subframe. For TDD_configuration, the first DL
2277 * subframe is at index 0. So, the timer will run till (15,0)
2278 * and will expire on (15,1)
2280 * @param RgSchUeCb *ue Ue control block.
2281 * @param U16 curTime current Time
2282 * @param U32 duration Timer duration
2283 * @param CmLteTimingInfo *tmrExpryIdx Timer expry (SFN,sf)
2284 * @return ROK/RFAILED
2287 PRIVATE S16 rgSCHDrxGetNxtTmrExpry
2292 CmLteTimingInfo *tmrExpryIdx
2295 PRIVATE S16 rgSCHDrxGetNxtTmrExpry (cell,curTime,duration,tmrExpryIdx)
2299 CmLteTimingInfo *tmrExpryIdx;
2302 U32 dlSfTillNxtSFN; /*!< DL subframes till next SFN */
2303 U8 tddCfgMode; /*!< tdd config mode */
2304 Bool isDwPtsCnted; /*!< is DwPts counted as PDCCH sf */
2305 CmLteTimingInfo crntTime; /*!< current SFN & sf */
2308 TRC2(rgSCHDrxGetNxtTmrExpry);
2310 #if ( ERRCLASS & ERRCLS_INT_PAR )
2311 if ( (cell == (RgSchCellCb* )NULLP)
2313 (tmrExpryIdx == (CmLteTimingInfo* )NULLP)
2321 isDwPtsCnted = cell->isDwPtsCnted ;
2323 tddCfgMode = cell->ulDlCfgIdx;
2324 crntTime.sfn = curTime / RGSCH_NUM_SUB_FRAMES_5G;
2325 crntTime.slot = curTime % RGSCH_NUM_SUB_FRAMES_5G;
2329 /* First calculate the number of DL subframes till next SFN */
2331 dlSfTillNxtSFN = rgSchDrxDLSfTillNxtSFN[isDwPtsCnted][tddCfgMode]
2332 [(crntTime.slot % RGSCH_NUM_SUB_FRAMES)];
2335 if ( dlSfTillNxtSFN >= duration )
2337 /* the timer would expire on the same RF */
2338 U32 diff = dlSfTillNxtSFN - duration;
2340 tmrExpryIdx->sfn = crntTime.sfn;
2344 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2350 /* to know the DL sf index based on diff */
2351 arrayIdx = rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2353 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2356 }/* if ( dlSfTillNxtSFN >= duration...*/
2359 U32 remSf; /*!< remaining subframes */
2360 U32 numRf; /*!< num of complete radio frames */
2361 U32 numRemSfs; /*!< num of remaining subframes */
2363 remSf = duration - dlSfTillNxtSFN;
2365 /* move to (currSFN,9) having consued dlSfTillNxtSFN DL subframes */
2366 tmrExpryIdx->sfn = crntTime.sfn;
2367 tmrExpryIdx->subframe = (U8)9;
2369 numRf = (1 * remSf)/rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2370 numRemSfs = (1 * remSf)%rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2372 tmrExpryIdx->sfn = tmrExpryIdx->sfn + numRf;
2374 /* we are now at (X,9) having consumed dlSfTillNxtSFN + numRf * num of DL
2375 * subframes in 1 RF */
2377 if ( numRemSfs == 0 )
2379 /* we are at subframe 9 i.e. the timer is going to expire using exact
2380 * radio frames. However, not all TDD_configurations have 9 as their
2381 * last DL subframe. We might have passed the last DL subfrme.
2382 * Therefore, move back */
2383 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2388 /* a reminder implies we have to move past this SFN as we are at the
2389 * last subframe on that SFN */
2391 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2394 }/*else if diff > duration */
2396 /* timer will expire 1 + tmrExpryIdx */
2398 if ( ( tmrExpryIdx->subframe + 1) == 10 )
2401 tmrExpryIdx->subframe = 0;
2405 tmrExpryIdx->subframe++;
2408 /* check to see if it sfn has crossed its max */
2409 if ( tmrExpryIdx->sfn > RG_SCH_CMN_MAX_SFN_NUM )
2411 tmrExpryIdx->sfn = tmrExpryIdx->sfn - (RG_SCH_CMN_MAX_SFN_NUM + 1);
2415 }/*rgSCHDrxGetNxtTmrExpry*/
2417 /** @brief This function calculates the next onDuration Occurence
2422 * Function: rgSCHDrxCalcNxtTmrExpry
2424 * Processing steps: a wrapper function to call
2425 * rgSCHDrxGetNxtTmrExpry
2427 * @param RgSchCellCb *cell
2428 * @param RgSchUeCb *ue
2431 * @param U16 *distance
2433 * @return ROK/RFAILED
2436 PRIVATE Void rgSCHDrxCalcNxtTmrExpry
2446 PRIVATE Void rgSCHDrxCalcNxtTmrExpry (cell,ue,delta,tmrLen,distance,idx)
2455 U16 curTimeInSf; /*current time in no of subframes*/
2456 CmLteTimingInfo tmrExpry;
2457 U16 tmrExpryInSf; /*timer expry in no of subframes*/
2459 TRC2(rgSCHDrxCalcNxtTmrExpry)
2461 curTimeInSf = cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G +
2462 cell->crntTime.slot;
2464 /* add delta to curTime */
2465 curTimeInSf += delta;
2467 rgSCHDrxGetNxtTmrExpry(ue->cell,curTimeInSf,tmrLen,&tmrExpry);
2469 /* convert timre Expry in terms of subframes */
2470 tmrExpryInSf = tmrExpry.sfn * RGSCH_NUM_SUB_FRAMES_5G +
2474 *idx = (tmrExpryInSf) % RG_SCH_MAX_DRXQ_SIZE;
2476 if ( distance != NULLP ) /* hqReTx don't use the concept of distance.
2477 They can send NULLP for distance.
2480 if ( tmrExpryInSf > curTimeInSf )
2482 *distance = (tmrExpryInSf - curTimeInSf) /
2483 RG_SCH_MAX_DRXQ_SIZE;
2487 /* in case the RF is at its max and wraps around */
2489 *distance = ((tmrExpryInSf + (RG_SCH_CMN_MAX_NUM_OF_SFN - 1))
2491 curTimeInSf) / RG_SCH_MAX_DRXQ_SIZE;
2495 RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId, "DRXUE. Invalid "
2496 "value for distance, %d CRNTI:%d", *distance,ue->ueId);
2501 }/*rgSCHDrxCalcNxtTmrExpry*/
2503 /* ccpu00134670- Validating onduration timer versus DRX cycle*/
2504 /***********************************************************
2506 * Func : rgSCHCfgVldtTddDrxCycCfg
2509 * Desc : Validates DRX Cycle Length configuration against received
2510 * onDuration timer from RRC.
2521 **********************************************************/
2523 S16 rgSCHCfgVldtTddDrxCycCfg
2531 S16 rgSCHCfgVldtTddDrxCycCfg(cell, drxCycle, onDurTmr, offSet)
2540 CmLteTimingInfo endTime;
2541 TRC2(rgSCHCfgVldtTddDrxCycCfg)
2546 rgSCHDrxGetNxtTmrExpry(cell, startTime, onDurTmr, &endTime);
2548 endTimeInSf = (endTime.sfn* RGSCH_NUM_SUB_FRAMES)+endTime.subframe;
2550 if(((RGSCH_MAX_SUBFRM_5G + endTimeInSf- startTime) % RGSCH_MAX_SUBFRM_5G) >=
2556 startTime = (startTime + drxCycle);
2557 /* Going for next iteration if the DRX cycle is not multiple of 10. If it is
2558 multiple of 10(Number of Subframes in a SFN) then subframe, at which
2559 onduration timer can start, will be always same, Otherwise the possible
2560 subframe numbers, where the onDuration timer can start, is 5. Hence 4
2561 more iterations are required. */
2562 }while((drxCycle % RGSCH_NUM_SUB_FRAMES) &&
2563 (startTime < (drxCycle * RGSCH_NUM_SUB_FRAMES/2)));
2570 /** @brief This function is called to handle onDurationTimer per TTI processing.
2573 * Invoked by - rgSCHDrxTtiInd
2575 * Function: rgSCHDrxTtiHdlOnDurUl
2579 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
2581 * - For Uplink we shall look at an index that is
2582 * n + RG_SCH_DRX_UL_DELTA as
2583 * we are concerned with the PDCCH and not the actual PUSCH.
2586 * @param RgSchCellCb *cellCb
2587 * @param U16 ulIndex
2592 PRIVATE Void rgSCHDrxTtiHdlOnDurUl
2598 PRIVATE Void rgSCHDrxTtiHdlOnDurUl(cell, ulIndex)
2604 RgSchDRXCellCb *drxCell = NULLP;
2605 RgSchUeCb *ue = NULLP;
2606 RgSchDrxUeCb *drxUe = NULLP;
2607 CmLListCp ulInactvLst; /* list of UE's becoming DL-inactive */
2608 RgSchCmnCell *cellSch = NULLP;
2609 Bool delInUlScan = FALSE;
2611 TRC2(rgSCHDrxTtiHdlOnDurUl)
2613 drxCell = (cell->drxCb);
2614 delInUlScan = drxCell->delInUlScan;
2615 /***********************************************************
2616 * Scanning OnDurationQ in UL
2617 ***********************************************************/
2619 /* For Uplink we shall look at an index that is n + RG_SCH_DRX_UL_DELTA as
2620 we are concerned with the PDCCH and not the actual PUSCH.*/
2622 node = drxCell->drxQ[ulIndex].onDurationQ.first;
2626 ue = (RgSchUeCb*)node->node;
2628 drxUe = RG_SCH_DRX_GET_UE(ue);
2631 if ( delInUlScan == FALSE)
2636 if ( drxUe->distance != DRX_TMR_EXPRD )
2641 /* reset the bit mask to indicate that onduration has started */
2642 drxUe->drxUlInactvMask &= ~RG_SCH_DRX_ONDUR_BITMASK;
2644 /* if no other condition is keeping UE as inactive,
2647 RG_SCH_CMN_UL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2649 if ( delInUlScan == TRUE )
2651 /*calculate next on duration occurence
2652 * and it to the onDuration Queue*/
2653 rgSCHDrxMvToNxtOnDurOcc(cell,ue,ulIndex,FALSE);
2654 }/*delInUlScan == FALSE */
2657 /***********************************************************
2658 * Scanning OnDurationExpQ in UL
2659 ***********************************************************/
2661 node = drxCell->drxQ[ulIndex].onDurationExpQ.first;
2663 /* Initialize UL inactive list */
2664 cmLListInit(&ulInactvLst);
2668 ue = (RgSchUeCb*)node->node;
2670 drxUe = RG_SCH_DRX_GET_UE(ue);
2672 if ( delInUlScan == FALSE )
2674 drxUe->onDurExpDistance--;
2677 if ( drxUe->onDurExpDistance != DRX_TMR_EXPRD )
2682 /*UE is inactive as onduration has expired */
2683 drxUe->drxUlInactvMask |= RG_SCH_DRX_ONDUR_BITMASK;
2685 if( !RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
2687 /* set the inactive bit to indicate UE has now become inactive */
2688 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
2690 /* Add to DL inactive list */
2691 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
2692 ue->ulDrxInactvLnk.node = (PTR)ue;
2695 if ( delInUlScan == TRUE)
2697 /*Remove from DRX queue*/
2698 cmLListDelFrm(&(drxCell->drxQ[ulIndex].onDurationExpQ),
2699 &(drxUe->onDurationExpEnt));
2701 drxUe->onDurExpIndx = DRX_INVALID;
2706 /* Send the list to the scheduler to mark UE as inactive in UL*/
2707 cellSch = RG_SCH_CMN_GET_CELL(cell);
2708 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
2713 /** @brief This function is called to handle onDurationTimer per TTI processing.
2716 * Invoked by - rgSCHDrxTtiInd
2718 * Function: rgSCHDrxTtiHdlOnDurDl
2722 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
2724 * - For Downlink we shall look at an index that is
2725 * n + RG_SCH_DRX_DL_DELTA.
2728 * @param RgSchCellCb *cellCb
2729 * @param U16 dlIndex
2734 PRIVATE Void rgSCHDrxTtiHdlOnDurDl
2740 PRIVATE Void rgSCHDrxTtiHdlOnDurDl(cell, dlIndex)
2746 RgSchDRXCellCb *drxCell = NULLP;
2747 RgSchUeCb *ue = NULLP;
2748 RgSchDrxUeCb *drxUe = NULLP;
2749 RgSchCmnCell *cellSch = NULLP;
2751 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
2752 Bool delInUlScan = FALSE;
2754 /* The DL loop, if onDurationTimer has started, will add the UeCb
2755 * in the onDurationTmrExprQ. If !delInUlScan, then calculate the next
2756 * OnDuration occurence, q it there and remove it from the current location.
2758 TRC2(rgSCHDrxTtiHdlOnDurDl)
2759 /***********************************************************
2760 * Scanning OnDurationQ in DL
2761 ***********************************************************/
2762 drxCell = (cell->drxCb);
2764 delInUlScan = drxCell->delInUlScan;
2765 //printf("CELL Timer [SFN : %d],[SF : %d]\n",cell->crntTime.sfn,cell->crntTime.slot);
2767 node = drxCell->drxQ[dlIndex].onDurationQ.first;
2772 ue = (RgSchUeCb* )node->node;
2776 drxUe = RG_SCH_DRX_GET_UE(ue);
2778 if ( delInUlScan == TRUE)
2783 if ( drxUe->distance != DRX_TMR_EXPRD )
2789 /* UE is active as onduration is to start */
2790 drxUe->drxDlInactvMask &= ~RG_SCH_DRX_ONDUR_BITMASK;
2792 /* set the UE as DRX active*/
2794 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2795 RG_SCH_CMN_DL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2797 /* Temporary fix to delete stale entry */
2798 if (drxUe->onDurExpIndx != DRX_INVALID)
2800 RLOG_ARG4(L_DEBUG,DBG_CELLID,cell->cellId,
2801 "UEID:%d PreExisted[%d:%d]in onDurExpQ new[%d]",
2803 drxUe->onDurExpIndx,
2804 drxUe->onDurExpDistance,
2806 cmLListDelFrm(&(drxCell->drxQ[drxUe->onDurExpIndx].onDurationExpQ),
2807 &(drxUe->onDurationExpEnt));
2809 drxUe->onDurExpIndx = DRX_INVALID;
2811 /*start the onduration expiry timer*/
2813 rgSCHDrxCalcNxtTmrExpry(cell,
2817 &(drxUe->onDurExpDistance),
2821 expiryIndex = ((dlIndex + drxUe->onDurTmrLen) %
2822 RG_SCH_MAX_DRXQ_SIZE);
2823 drxUe->onDurExpDistance = (drxUe->onDurTmrLen)/
2824 RG_SCH_MAX_DRXQ_SIZE;
2827 cmLListAdd2Tail(&(drxCell->drxQ[expiryIndex].onDurationExpQ),
2828 &(drxUe->onDurationExpEnt));
2829 //printf("DRXOnDuration Timer Started at [SFN : %d],[SF : %d]\n",cell->crntTime.sfn,cell->crntTime.slot);
2830 drxUe->onDurationExpEnt.node = (PTR)ue;
2831 drxUe->onDurExpIndx = expiryIndex;
2833 //printf("DRxOnDuration will Expire = [%d]\n",(cell->crntTime.sfn*10+cell->crntTime.slot+drxUe->onDurTmrLen));
2835 if ( delInUlScan == FALSE )
2837 /*calculate next on duration occurence
2838 * and it to the onDuration Queue*/
2839 rgSCHDrxMvToNxtOnDurOcc(cell,ue,dlIndex,FALSE);
2840 }/*delInUlScan == FALSE */
2844 /***********************************************************
2845 * Scanning OnDurationExpQ in DL
2846 ***********************************************************/
2848 /* Mark UE as Inactive based on OnDuration Expiry */
2849 node = drxCell->drxQ[dlIndex].onDurationExpQ.first;
2851 /* Initialize DL inactive list */
2852 cmLListInit(&dlInactvLst);
2856 ue = (RgSchUeCb*)node->node;
2858 drxUe = RG_SCH_DRX_GET_UE(ue);
2860 if ( delInUlScan == TRUE )
2862 drxUe->onDurExpDistance--;
2865 if ( drxUe->onDurExpDistance != DRX_TMR_EXPRD )
2871 /* UE is inactive as onduration has expired */
2872 drxUe->drxDlInactvMask |= (RG_SCH_DRX_ONDUR_BITMASK);
2874 if( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
2876 /* set the inactive bit to indicate UE has now become inactive */
2877 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
2879 /* Add to DL inactive list */
2880 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
2881 ue->dlDrxInactvLnk.node = (PTR)ue;
2884 if ( delInUlScan == FALSE )
2886 /*Remove from DRX queue*/
2887 cmLListDelFrm(&(drxCell->drxQ[dlIndex].onDurationExpQ),
2888 &(drxUe->onDurationExpEnt));
2890 drxUe->onDurExpIndx = DRX_INVALID;
2895 /* Send the list to the scheduler to mark UE as inactive */
2896 cellSch = RG_SCH_CMN_GET_CELL(cell);
2897 cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
2900 }/*rgSCHDrxTtiHdlOnDurDl*/
2902 /** @brief This function handles the Dl HARQ timer's processing per TTI.
2905 * Invoked by - rgSCHDrxTtiHdlDlHarq
2907 * Function: rgSCHDrxTtiHdlDlHarqRTT
2910 * - In addition per TTI DRX module must look at Downlink HARQ queues
2911 * maintained to track HARQ RTT timer and drx-RetransmissionTimer.
2912 * Every TTI at the scheduling index we shall check these queues and
2913 * process accordingly.
2915 * @param RgSchCellCb *cellCb
2916 * @param U16 dlIndex
2921 PRIVATE Void rgSCHDrxTtiHdlDlHarqRTT
2927 PRIVATE Void rgSCHDrxTtiHdlDlHarqRTT(cell, dlIndex)
2933 RgSchDrxDlHqProcCb *drxHq;
2934 RgSchDlHqProcCb *dlHq;
2935 RgSchDRXCellCb *drxCell;
2936 RgSchDrxUeCb *drxUe;
2940 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
2941 RgSchCmnCell *cellSch = RG_SCH_CMN_GET_CELL(cell);
2945 TRC2(rgSCHDrxTtiHdlDlHarqRTT);
2947 drxCell = cell->drxCb;
2948 delInUlScan = drxCell->delInUlScan;
2950 /***********************************************************
2951 * Scanning harqRTTQ in DL
2952 ***********************************************************/
2954 cmLListInit(&dlInactvLst);
2955 node = drxCell->drxQ[dlIndex].harqRTTQ.first;
2959 dlHq = (RgSchDlHqProcCb*)node->node;
2963 if(TRUE == ue->isEmtcUe)
2968 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2969 drxUe = RG_SCH_DRX_GET_UE(ue);
2970 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2971 /* add the UE to the cell's retransmission queuee before starting
2972 * reTx timer, because this will not depend on retx timer trigger*/
2973 rgSCHUtlDlProcAddToRetx(dlHq->hqE->cell, dlHq);
2975 if ( delInUlScan == FALSE)
2977 cmLListDelFrm (&(drxCell->drxQ[dlIndex].harqRTTQ),
2978 &(drxHq->harqRTTEnt));
2980 drxHq->rttIndx = DRX_INVALID;
2982 /* ccpu00134565: Starting retransmission timer only if timerLen is
2983 * having non-zero value after reduction, Adding to Retx queue is
2984 * independent of starting retransmission timer. Hence if part will
2985 * take care of starting retx timer only*/
2986 if (drxUe->drxRetransTmrLen > drxHq->retxTmrReduction)
2988 /* add the harq proc to the re-tx queue--*/
2990 /* ccpu00134196-[Add]-DRX retx timer changes */
2991 rgSCHDrxCalcNxtTmrExpry(cell,
2994 drxUe->drxRetransTmrLen-drxHq->retxTmrReduction,
2995 NULLP, /*retransQ does not maintain distance*/
3000 /* ccpu00134196-[Add]-DRX retx timer changes */
3001 reTxExpIndx = ((dlIndex +
3002 drxUe->drxRetransTmrLen-drxHq->retxTmrReduction) %
3003 RG_SCH_MAX_DRXQ_SIZE);
3005 /* TODO. Workaround to avoid duplicate entry */
3006 if(drxHq->reTxIndx == DRX_INVALID)
3008 cmLListAdd2Tail (&(drxCell->drxQ[reTxExpIndx].harqRetxQ),
3009 &(drxHq->harqRetxEnt));
3011 drxHq->harqRetxEnt.node = (PTR)dlHq;
3012 drxHq->reTxIndx = reTxExpIndx;
3016 RLOG_ARG4(L_ERROR,DBG_CELLID,cell->cellId,"CRNTI:%d "
3017 "Adding Retx Node to expire at RetxIndx: %d at dlIndex %d "
3018 "drxHq->reTxIndx %d", ue->ueId, reTxExpIndx, dlIndex,
3022 /*mark the ue as active for downlink--*/
3023 drxUe->drxDlInactvMask &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3024 drxUe->drxDlInactvMaskPerCell[cellIdx] &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3026 /* Update UE's inactive mask and if required move UE to ACTIVE state */
3027 RG_SCH_CMN_DL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
3031 /***********************************************************
3032 * Scanning harqRetxQ in DL
3033 ***********************************************************/
3035 node = drxCell->drxQ[dlIndex].harqRetxQ.first;
3038 dlHq = (RgSchDlHqProcCb*)node->node;
3040 drxUe = RG_SCH_DRX_GET_UE(ue);
3042 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
3043 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
3045 /*mark the ue as in-active for downlink*/
3046 drxUe->drxDlInactvMaskPerCell[cellIdx] |= (RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3048 dlInactvMask = RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId;
3050 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
3052 dlInactvMask &= drxUe->drxDlInactvMaskPerCell[cellIdx];
3055 drxUe->drxDlInactvMask |= dlInactvMask;
3057 /* if no other condition is keeping ue active,
3060 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
3062 ue->dl.dlInactvMask |= (RG_DRX_INACTIVE);
3064 /* Add to DL inactive list */
3065 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
3066 ue->dlDrxInactvLnk.node = (PTR)ue;
3069 /*remove the harq proc from this queue*/
3070 if ( delInUlScan == FALSE)
3072 cmLListDelFrm (&(drxCell->drxQ[dlIndex].harqRetxQ),
3073 &(drxHq->harqRetxEnt));
3074 drxHq->reTxIndx = DRX_INVALID;
3077 /*Call schedulers to inactivate ue*/
3078 cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
3083 /** @brief This function handles the Ul HARQ timer's processing per TTI.
3086 * Invoked by - rgSCHDrxTtiHdlDlHarq
3088 * Function: rgSCHDrxTtiHdlUlHarqRTT
3091 * - In addition per TTI DRX module must look at Downlink HARQ queues
3092 * maintained to track HARQ RTT timer and drx-RetransmissionTimer.
3093 * Every TTI at the scheduling index we shall check these queues and
3094 * process accordingly.
3096 * - Though these timers are related to downlink HARQ processing, they
3097 * have an impact on uplink scheduling. The reason is that the UE,
3098 * if active for downlink scheduling implies that it is reading
3099 * PDCCHs i.e. we can still send uplink allocations to the UE. Hence
3100 * every TTI Uplink too would look at the harqRTTQ and harqRetxQ.
3104 * @param RgSchCellCb *cellCb
3105 * @param U16 ulIndex
3110 PRIVATE Void rgSCHDrxTtiHdlUlHarqRTT
3116 PRIVATE Void rgSCHDrxTtiHdlUlHarqRTT(cell, ulIndex)
3122 RgSchDrxDlHqProcCb *drxHq;
3123 RgSchDlHqProcCb *dlHq;
3124 RgSchDRXCellCb *drxCell;
3125 RgSchDrxUeCb *drxUe;
3128 CmLListCp ulInactvLst; /* list of UE's becoming DL-inactive */
3129 RgSchCmnCell *cellSch = RG_SCH_CMN_GET_CELL(cell);
3134 TRC2(rgSCHDrxTtiHdlUlHarqRTT);
3136 drxCell = cell->drxCb;
3137 delInUlScan = drxCell->delInUlScan;
3139 cmLListInit(&ulInactvLst);
3141 /***********************************************************
3142 * Scanning harqRTTQ in UL
3143 ***********************************************************/
3146 Though these timers are related to downlink HARQ processing, they
3147 have an impact on uplink scheduling. The reason is that the UE,
3148 if active for downlink scheduling implies that it is reading
3149 PDCCHs i.e. we can still send uplink allocations to the UE. Hence
3150 every TTI Uplink too would look at the harqRTTQ and harqRetxQ.
3153 node = drxCell->drxQ[ulIndex].harqRTTQ.first;
3156 dlHq = (RgSchDlHqProcCb*)node->node;
3158 drxUe = RG_SCH_DRX_GET_UE(ue);
3160 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
3161 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
3163 if ( delInUlScan == TRUE )
3165 /* remove the harq proc from this queue--*/
3166 cmLListDelFrm (&(drxCell->drxQ[ulIndex].harqRTTQ),
3167 &(drxHq->harqRTTEnt));
3169 drxHq->rttIndx = DRX_INVALID;
3172 /* mark the ue as active for uplink--*/
3173 drxUe->drxUlInactvMask &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3174 drxUe->drxUlInactvMaskPerCell[cellIdx] &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3176 /* Update UE's inactive mask and if required move UE to ACTIVE state */
3177 RG_SCH_CMN_UL_UPDT_INACTV_MASK( cell, ue, RG_DRX_INACTIVE);
3180 /***********************************************************
3181 * Scanning harqRetxQ in UL
3182 ***********************************************************/
3183 node = drxCell->drxQ[ulIndex].harqRetxQ.first;
3186 dlHq = (RgSchDlHqProcCb*)node->node;
3188 drxUe = RG_SCH_DRX_GET_UE(ue);
3189 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
3190 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
3192 /*mark the ue as in-active for uplink*/
3194 drxUe->drxUlInactvMaskPerCell[cellIdx] |= (RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3196 ulInactvMask = RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId;
3198 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
3200 ulInactvMask &= drxUe->drxUlInactvMaskPerCell[cellIdx];
3203 drxUe->drxUlInactvMask |= ulInactvMask;
3205 if(!RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
3207 ue->ul.ulInactvMask |= (RG_DRX_INACTIVE);
3209 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
3210 ue->ulDrxInactvLnk.node = (PTR)ue;
3213 /* remove the harq proc from this queue*/
3214 if ( delInUlScan == TRUE)
3216 cmLListDelFrm (&(drxCell->drxQ[ulIndex].harqRetxQ),
3217 &(drxHq->harqRetxEnt));
3218 drxHq->reTxIndx = DRX_INVALID;
3223 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
3229 /**********************************************************************
3232 **********************************************************************/