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
311 Void rgSCHDrxTtiInd (cell)
318 dlIndex = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot +
319 RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
321 ulIndex = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot +
322 RG_SCH_DRX_UL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
325 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex);
326 /* checks the Ul-Retransmission timer */
330 rgSCHDrxTtiHdlUlHarq (cell, dlIndex, ulIndex);
333 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex);
335 /*Process Short cycle expiry before On duration timer so that long cycles
336 * On Duration can be processed if timer has expired*/
337 rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex);
338 rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex);
341 rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex);
342 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex);
343 /* checks the Ul-Retransmission timer */
347 rgSCHDrxTtiHdlUlHarq (cell, dlIndex, ulIndex);
350 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex);
351 rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex);
359 /** @brief This function is called to handle onDurationTimer per TTI processing.
362 * Invoked by - rgSCHDrxTtiInd
364 * Function: rgSCHDrxTtiHdlOnDur
368 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
370 * - For Downlink we shall look at an index that is
371 * n + RG_SCH_DRX_DL_DELTA.
374 * - For Uplink we shall look at an index that is
375 * n + RG_SCH_DRX_UL_DELTA as
376 * we are concerned with the PDCCH and not the actual PUSCH.
379 * @param RgSchCellCb *cellCb
380 * @param uint16_t dlIndex
381 * @param uint16_t ulIndex
382 * @return ROK/RFAILED
386 static S16 rgSCHDrxTtiHdlOnDur
393 static S16 rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex)
400 #if ( ERRCLASS & ERRCLS_INT_PAR )
401 if ( cell == (RgSchCellCb* )NULLP )
407 rgSCHDrxTtiHdlOnDurDl(cell,dlIndex);
409 rgSCHDrxTtiHdlOnDurUl(cell, ulIndex);
413 }/*rgSCHDrxTtiHdlOnDur*/
416 /** @brief This function handles the processing for drxInactityTimer per TTI
419 * Invoked by - rgSCHDrxTtiInd
421 * Function: rgSCHDrxTtiHdlInActv
425 * - For Downlink we shall look at an index that is
426 * n + RG_SCH_DRX_DL_DELTA of the drxQ.
428 * - MARK UE AS INACTIVE BASED ON DRX-INACTIVITY TIMER EXPIRY
431 * - For Uplink we shall look at an index that is
432 * n + RG_SCH_DRX_UL_DELTA as
433 * we are concerned with the PDCCH and not the actual PUSCH.
436 * @param RgSchCellCb *cellCb
437 * @param uint16_t dlIndex
438 * @param uint16_t ulIndex
439 * @return ROK/RFAILED
443 S16 rgSCHDrxTtiHdlInActv
450 S16 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex)
457 RgSchDRXCellCb *drxCell=NULLP;
459 RgSchDrxUeCb *drxUe=NULLP;
460 uint16_t shrtCycleExpIndx;
461 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
462 CmLListCp ulInactvLst; /* list of UE's becoming UL-inactive */
463 RgSchCmnCell *cellSch = NULLP;
464 Bool delInUlScan = FALSE;
466 #if ( ERRCLASS & ERRCLS_INT_PAR )
467 if ( cell == (RgSchCellCb* )NULLP)
474 drxCell = (cell->drxCb);
475 delInUlScan = drxCell->delInUlScan;
478 /***********************************************************
479 * Scanning inActvitiyQ in DL
480 ***********************************************************/
482 /* The DL loop will scan for UE's whose inactivity timer has
483 * expired. It will switch the cycle to short or long based
484 * on the cycle configured.
485 * Furhter,if !delInUlScan, then will remove the UE from the
489 node = drxCell->drxQ[dlIndex].inActvTmrQ.first;
491 /* Initialize DL inactive list */
492 cmLListInit(&dlInactvLst);
494 /* Initialize UL inactive list */
495 cmLListInit(&ulInactvLst);
499 ue = (RgSchUeCb*)node->node;
501 drxUe = RG_SCH_DRX_GET_UE(ue);
503 if ( delInUlScan == TRUE)
505 drxUe->drxInactDistance--;
508 if ( drxUe->drxInactDistance != DRX_TMR_EXPRD )
513 /* UE is inactive as inactivity timer has expired */
514 drxUe->drxDlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
517 /* update the ue mask only if no condition in drx
518 * is keeping ue active
520 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
522 /* set the UE has DRX inactive */
523 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
525 /* Add to DL inactive list */
526 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
527 ue->dlDrxInactvLnk.node = (PTR)ue;
530 /*Remove from the queue if !delInUlScan */
531 if( delInUlScan == FALSE )
533 cmLListDelFrm(&(drxCell->drxQ[dlIndex].inActvTmrQ),
534 &(drxUe->inActvTmrEnt));
536 drxUe->drxInactvIndx = DRX_INVALID;
538 }/* if (delInUlScan == FALSE) */
540 if (drxUe->isShortCycleCfgd)
542 /* add shorty cycle expirty */
543 drxUe->isLongCycle = FALSE;
545 shrtCycleExpIndx = (dlIndex + (drxUe->shortCycleTmrLen *
546 drxUe->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
548 drxUe->drxShortCycleDistance = (drxUe->shortCycleTmrLen *
549 drxUe->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
551 /*Remove the UE from existing index*/
552 if (drxUe->shortCycleIndx != DRX_INVALID)
554 cmLListDelFrm(&(drxCell->drxQ[drxUe->shortCycleIndx].shortCycleQ),
555 &(drxUe->shortCycleEnt));
558 cmLListAdd2Tail(&(drxCell->drxQ[shrtCycleExpIndx].shortCycleQ),
559 &(drxUe->shortCycleEnt));
561 drxUe->shortCycleEnt.node = (PTR)ue;
562 drxUe->shortCycleIndx = shrtCycleExpIndx;
564 /*Calculate onDuration again & move the
565 * ueCb to the next Onduration occurence
568 /*we maybe at any position in the RF timeline,
569 * need to calculate onDuration from the starting
572 rgSCHDrxMvToNxtOnDurOcc(cell,ue,RG_SCH_DRX_DL_DELTA,TRUE);
574 }/*isShortCycleCfgd */
577 /* use the long cycle */
578 drxUe->isLongCycle = TRUE;
584 /***********************************************************
585 * Scanning inActvitiyQ in UL
586 ***********************************************************/
588 /* The UL loop will scan for UE's whose inactivity timer has
589 * expired and mark the UE's UL inactive.
590 * Furhter,if delInUlScan, then will remove the UE from the
594 /* For Uplink we shall look at an index that is n + RG_SCH_DRX_UL_DELTA as
595 we are concerned with the PDCCH and not the actual PUSCH.*/
599 node = drxCell->drxQ[ulIndex].inActvTmrQ.first;
604 ue = (RgSchUeCb*)node->node;
606 drxUe = RG_SCH_DRX_GET_UE(ue);
608 if ( delInUlScan == FALSE)
610 drxUe->drxInactDistance--;
613 if ( drxUe->drxInactDistance != DRX_TMR_EXPRD )
618 /* Need to mark the UE as inactive due to expiry of
619 * DRX inactivity timer */
621 /* UE is inactive as inactivity timer has expired */
622 drxUe->drxUlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
624 /* update the ue mask only if no other condition in
625 * drx is keeping ue active */
627 if (!RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
629 /* set the inactivity bit */
630 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
632 /* Add to Ul inactive list */
633 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
634 ue->ulDrxInactvLnk.node = (PTR)ue;
637 if ( delInUlScan == TRUE)
639 /* remove from queue */
640 cmLListDelFrm(&(drxCell->drxQ[ulIndex].inActvTmrQ),
641 &(drxUe->inActvTmrEnt));
643 drxUe->drxInactvIndx = DRX_INVALID;
645 }/* if ( delInUlScan == TRUE) */
646 }/*while(node) for uplink */
649 /* Send the list to the scheduler to mark UE as inactive in UL*/
650 cellSch = RG_SCH_CMN_GET_CELL(cell);
651 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
653 /* Send the DL inactive list to the scheduler to mark UE as inactive */
654 cellSch = RG_SCH_CMN_GET_CELL(cell);
655 cellSch->apisDl->rgSCHDlInactvtUes(cell,&dlInactvLst);
658 }/*rgSCHDrxTtiHdlInActv*/
660 /** @brief This function handles the per TTI processing for DRX short cycle
664 * Invoked by - rgSCHDrxTtiInd
666 * Function: rgSCHDrxTtiHdlShortCycle
671 * in addition we have to mark the ues based on drx short cycle
675 * @param RgSchCellCb *cell
676 * @param uint16_t dlIndex
677 * @param uint16_t ulIndex
678 * @return ROK/RFAILED
682 S16 rgSCHDrxTtiHdlShortCycle
689 S16 rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex)
696 RgSchDRXCellCb *drxCell=NULLP;
698 RgSchDrxUeCb *drxUe=NULLP;
700 #if ( ERRCLASS & ERRCLS_INT_PAR )
701 if ( cell == (RgSchCellCb* )NULLP )
710 drxCell = RG_SCH_DRX_GET_CELL(cell);
712 node = drxCell->drxQ[dlIndex].shortCycleQ.first;
716 ue = (RgSchUeCb*)node->node;
718 drxUe = RG_SCH_DRX_GET_UE(ue);
720 if ( --drxUe->drxShortCycleDistance != DRX_TMR_EXPRD)
725 /* mark the UE's current cycle to be long */
726 drxUe->isLongCycle = TRUE;
728 /* remove from the shortCycleQ */
730 cmLListDelFrm(&(drxCell->drxQ[dlIndex].shortCycleQ),
731 &(drxUe->shortCycleEnt));
732 drxUe->shortCycleIndx = DRX_INVALID;
734 /* Remove from onDuration queue inserted based on short cycle
735 * and calculate onDuration based on long cycle.*/
736 rgSCHDrxMvToNxtOnDurOcc(cell,ue,RG_SCH_DRX_DL_DELTA,TRUE);
740 }/*rgSCHDrxTtiHdlShortCycle*/
743 /** @brief This function handles the HARQ timer's processing per TTI.
746 * Invoked by - rgSCHDrxTtiInd
748 * Function: rgSCHDrxTtiHdlDlHarq
751 * - In addition per TTI DRX module must look at Downlink HARQ queues
752 * maintained to track HARQ RTT timer and drx-RetransmissionTimer.
753 * Every TTI at the scheduling index we shall check these queues and
754 * process accordingly.
757 * - Though these timers are related to downlink HARQ processing, they
758 * have an impact on uplink scheduling. The reason is that the UE,
759 * if active for downlink scheduling implies that it is reading
760 * PDCCHs i.e. we can still send uplink allocations to the UE. Hence
761 * every TTI Uplink too would look at the harqRTTQ and harqRetxQ.
765 * @param RgSchCellCb *cellCb
766 * @param uint16_t dlIndex
767 * @param uint16_t ulIndex
768 * @return ROK/RFAILED
772 static S16 rgSCHDrxTtiHdlDlHarq
779 static S16 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex)
786 #if ( ERRCLASS & ERRCLS_INT_PAR)
787 if ( cell == (RgSchCellCb *)NULLP )
791 #endif /*ERRCLASS & ERRCLS_INT_PAR*/
794 rgSCHDrxTtiHdlDlHarqRTT(cell, dlIndex);
796 rgSCHDrxTtiHdlUlHarqRTT(cell, ulIndex);
801 /** @brief This function is called by the common scheduler as part of
802 * finalization of allocations in downlink.
807 * Function: rgSchDrxStrtInActvTmr
809 * This function is responsible to starting drx-InactivityTimer
814 * @param RgSchCellCb *cell
815 * @param CmLListCp *ueUlLst
816 * @param uint8_t direction
821 Void rgSCHDrxStrtInActvTmr
828 Void rgSCHDrxStrtInActvTmr(cell, ueLst, direction)
837 RgSchDrxUeCb *ueDrxCb;
841 uint16_t inActvTmrExpIndx;
843 uint16_t curTimeInSf; /* current time in number of subframes */
848 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
849 CmLListCp ulInactvLst; /* list of UE's becoming UL-inactive */
850 RgSchCmnCell *cellSch = NULLP;
851 Bool delInUlScan = FALSE;
853 if ( direction == RG_SCH_DRX_UL)
856 curTimeInSf = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
857 (cell->crntTime.slot) +RG_SCH_DRX_UL_DELTA;
861 delta = RG_SCH_DRX_UL_DELTA;
867 curTimeInSf = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
868 (cell->crntTime.slot) + RG_SCH_DRX_DL_DELTA;
872 delta = RG_SCH_DRX_DL_DELTA;
877 /* Initialize DL inactive list */
878 cmLListInit(&dlInactvLst);
880 /* Initialize UL inactive list */
881 cmLListInit(&ulInactvLst);
883 delInUlScan = cell->drxCb->delInUlScan;
886 index1 = (curTimeInSf) % RG_SCH_MAX_DRXQ_SIZE;
893 ueCb = (RgSchUeCb *)node->node;
894 ueDrxCb = ueCb->drxCb;
896 /* Stop inactivity timer */
897 if ( ueDrxCb->drxInactvIndx != DRX_INVALID )
899 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->drxInactvIndx].inActvTmrQ),
900 &(ueDrxCb->inActvTmrEnt));
904 rgSCHDrxCalcNxtTmrExpry(cell,
907 ueDrxCb->inactvtyTmrLen,
908 &(ueDrxCb->drxInactDistance),
913 inActvTmrExpIndx = (index1 + ueDrxCb->inactvtyTmrLen)
914 % RG_SCH_MAX_DRXQ_SIZE;
916 ueDrxCb->drxInactDistance = ueDrxCb->inactvtyTmrLen
917 / RG_SCH_MAX_DRXQ_SIZE;
920 cmLListAdd2Tail(&(cell->drxCb->drxQ[inActvTmrExpIndx].inActvTmrQ),
921 &(ueDrxCb->inActvTmrEnt));
923 ueDrxCb->inActvTmrEnt.node = (PTR)ueCb;
925 ueDrxCb->drxInactvIndx = inActvTmrExpIndx;
927 /* Update DRX InActive both masks */
928 ueDrxCb->drxUlInactvMask &= ~RG_SCH_DRX_INACTVTMR_BITMASK;
929 ueDrxCb->drxDlInactvMask &= ~RG_SCH_DRX_INACTVTMR_BITMASK;
931 /* Update UE's Inactive masks */
932 ueCb->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
933 ueCb->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
935 if ( delInUlScan == TRUE)
937 if ( ueDrxCb->inactvtyTmrLen == RGR_DRX_PRD_1PSF)
939 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
940 ueDrxCb->drxDlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
942 /* if no other condition is keeping ue inactive,
945 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(ueDrxCb) )
947 ueCb->dl.dlInactvMask |= RG_DRX_INACTIVE;
949 /* Add to DL inactive list */
950 cmLListAdd2Tail(&dlInactvLst,&(ueCb->dlDrxInactvLnk));
951 ueCb->dlDrxInactvLnk.node = (PTR)ueCb;
953 }/*if ( ueDrxCb->inactvyTmrLen...*/
955 }/*delInUlScan==TRUE*/
958 if ( ueDrxCb->inactvtyTmrLen == RGR_DRX_PRD_1PSF )
960 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
961 ueDrxCb->drxUlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
962 /* if no other condition is keeping ue inactive,
965 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(ueDrxCb) )
967 ueCb->ul.ulInactvMask |= RG_DRX_INACTIVE;
969 if ( !RG_SCH_CMN_UL_IS_UE_ACTIVE(ueCb))
971 /* Add to UL inactive list */
972 cmLListAdd2Tail(&ulInactvLst,&(ueCb->ulDrxInactvLnk));
973 ueCb->ulDrxInactvLnk.node = (PTR)ueCb;
975 }/*if ( !RG_SCH_DRX....)*/
976 }/*if (ueDrxCb->inactv...*/
979 /* move the link list forward */
983 cmLListDelFrm(ueLst, delNode);
984 delNode->node = NULLP;
988 /* Send the list to the scheduler to mark UE as inactive in UL*/
989 cellSch = RG_SCH_CMN_GET_CELL(cell);
990 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
992 /* Send the DL inactive list to the scheduler to mark UE as inactive */
993 cellSch = RG_SCH_CMN_GET_CELL(cell);
994 cellSch->apisDl->rgSCHDlInactvtUes(cell,&dlInactvLst);
997 }/*rgSCHDrxStrtInActvTmr*/
999 /** @brief This function is called by the downlink HARQ module on receiving a
1000 * negative feedback from the UE for a PDSCH transmission.
1003 * Invoked by - rgSCHDhmHqTrnsFail
1005 * Function: rgSCHDrxStartHarqRTTTmr
1010 * @param RgSchCellCb *cell
1011 * @param RgSchDlHqProcCb *dlHq
1012 * @param uint8_t tbCnt
1016 Void rgSCHDrxStartHarqRTTTmr
1019 RgSchDlHqProcCb *hqP,
1023 Void rgSCHDrxStartHarqRTTTmr(cell, hqP, tbCnt)
1025 RgSchDlHqProcCb *hqP;
1029 RgSchDRXCellCb *drxCell =NULLP;
1030 RgSchDrxDlHqProcCb *drxHq =NULLP;
1031 uint16_t harqRTTExpIndx;
1034 uint8_t firstDlTxOcassion;
1035 uint8_t drxRetxTmrStartSf;
1038 drxCell = RG_SCH_DRX_GET_CELL(cell);
1039 drxHq = RG_SCH_DRX_GET_DL_HQ(hqP);
1042 /* ccpu00134196-[Add]-DRX retx timer changes */
1043 firstDlTxOcassion = rgSchDrxHarqRetxFirstPsf[cell->ulDlCfgIdx]
1044 [hqP->tbInfo[tbCnt].fdbkTime.subframe];
1046 harqRTTExpIndx = ((hqP->tbInfo[tbCnt].fdbkTime.sfn * 10) +
1047 hqP->tbInfo[tbCnt].fdbkTime.subframe + firstDlTxOcassion)
1048 % RG_SCH_MAX_DRXQ_SIZE;
1050 fdbkDelta = RGSCH_CALC_SF_DIFF(cell->crntTime, hqP->tbInfo[tbCnt].fdbkTime);
1053 /* For FDD HARQ RTT expiry index is 8 subframes from the time
1054 * corresponding PDSCH was scheduled. We are adding 1 subframe
1055 * so that UE is scheduled for retransmission in the next subframe*/
1056 /* ccpu00134196-[Add]-DRX retx timer changes */
1057 harqRTTExpIndx = ((hqP->tbInfo[tbCnt].timingInfo.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1058 hqP->tbInfo[tbCnt].timingInfo.slot + RG_SCH_MIN_HARQ_RTT)
1059 % RG_SCH_MAX_DRXQ_SIZE;
1061 fdbkDelta = RGSCH_CALC_SF_DIFF(cell->crntTime, hqP->tbInfo[tbCnt].timingInfo);
1063 /* ccpu00134196-[Add]-DRX retx timer changes */
1064 /* ensure that the insertion into the queue happens at an index
1065 greater than the dl index, ie, do +1 */
1066 /* Instead of depending on TTI details of current time and HARQ RTT Expire
1067 * time, Handling this check with deltas, because with TTIs it is not possible
1068 * to handle wrap-around condition*/
1070 if(fdbkDelta + RG_SCH_DRX_DL_DELTA >= firstDlTxOcassion)
1072 /* The retx timer length should be reduced.
1073 This means based on the platforms delta between the DL HARQ
1074 processing and DL scheduling, drx retx timer lengths of 1ms/2ms
1075 may not be possible */
1076 drxRetxTmrStartSf = (hqP->tbInfo[tbCnt].fdbkTime.subframe +
1077 firstDlTxOcassion) % RGSCH_NUM_SUB_FRAMES;
1079 /* We are here because the Retx Timer start is moved by atleast one
1080 position. Hence the timer will be reduced by minimum one */
1081 drxHq->retxTmrReduction = 1;
1083 /* Now check the consecutive subframes starting from the actual
1084 starting position of the retx tmr till the new position. Reduce the
1085 timer value only if the sf is a Pdcch sf */
1086 for(i = 1; i <= fdbkDelta + RG_SCH_DRX_DL_DELTA-firstDlTxOcassion+ 1; i++)
1088 if (rgSchTddUlDlSubfrmTbl[cell->ulDlCfgIdx]
1089 [(drxRetxTmrStartSf+i)%RGSCH_NUM_SUB_FRAMES]
1090 != RG_SCH_TDD_UL_SUBFRAME)
1092 drxHq->retxTmrReduction++;
1096 if(fdbkDelta + RG_SCH_DRX_DL_DELTA >= RG_SCH_MIN_HARQ_RTT)
1098 drxHq->retxTmrReduction =
1099 fdbkDelta + RG_SCH_DRX_DL_DELTA - RG_SCH_MIN_HARQ_RTT+ 1;
1102 harqRTTExpIndx = (harqRTTExpIndx + drxHq->retxTmrReduction) %
1103 RG_SCH_MAX_DRXQ_SIZE;
1107 drxHq->retxTmrReduction = 0;
1109 cmLListAdd2Tail (&(drxCell->drxQ[harqRTTExpIndx].harqRTTQ),
1110 &(drxHq->harqRTTEnt));
1112 drxHq->harqRTTEnt.node = (PTR)hqP;
1113 drxHq->rttIndx = harqRTTExpIndx;
1117 }/*rgSCHDrxStartHarqRTTTmr*/
1120 /** @brief This function is called by the Configuration module to give a
1121 * trigger to DRX module for UE configuration.
1125 * Function: rgSCHDrxUeCfg
1128 * - Copy configuration information into drxUe structure.
1129 * - Calculate the first occurance of onDuration based on values
1130 * provided in the configuration structure.
1131 * - Append the UE to the onDurationQ at that index.
1132 * - The UE must be appened to the list based on the timing calculated
1133 * above (nxtSfn, nxtSubframe).
1135 * @param RgSchCellCb *cell Cell control block.
1136 * @param RgSchUeCb *ue UE control block.
1137 * @param RgrUeCfg *ueCfg RGR UE configuration information.
1150 S16 rgSCHDrxUeCfg (cell, ue, ueCfg)
1157 RgSchDrxUeCb *ueDrxCb;
1158 CmLteTimingInfo nxtOnDur;
1160 uint16_t nxtOnDurTime;
1165 #if ( ERRCLASS & ERRCLS_INT_PAR )
1166 if ( cell == (RgSchCellCb* )NULLP)
1171 if ((ue == (RgSchUeCb* )NULLP)
1173 (ueCfg == (RgrUeCfg* )NULLP))
1175 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId, "rgSCHDrxUeCfg():"
1176 "Invalid params.cell or ue or ueCfg is NULL ");
1182 /* allocate and initialize drxCb */
1183 ret = rgSCHUtlAllocSBuf(cell->instIdx, (Data**)&ue->drxCb,
1184 (sizeof(RgSchDrxUeCb)));
1188 RLOG_ARG1(L_ERROR,DBG_CELLID,cell->cellId,
1189 "Memory allocation FAILED for DRX UECB CRBTI:%d",ue->ueId);
1193 ueDrxCb = ue->drxCb;
1195 /* initialize the masks */
1196 ueDrxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1197 ueDrxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1198 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
1199 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
1201 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1203 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1204 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1207 /* Copy the configuration values into the UE's DRX CB. */
1208 rgSCHDrxCpyUeCfg (ueDrxCb, &ueCfg->ueDrxCfg);
1212 rgSCHEmtcDrxCpyUeCfg(ue ,&ueCfg->ueDrxCfg);
1216 /* set all indexes to default values */
1217 ueDrxCb->onDurIndx = DRX_INVALID;
1218 ueDrxCb->onDurExpIndx = DRX_INVALID;
1219 ueDrxCb->drxInactvIndx = DRX_INVALID;
1220 ueDrxCb->shortCycleIndx = DRX_INVALID;
1222 /* set all distances to timer expiry */
1223 ueDrxCb->onDurExpDistance = DRX_TMR_EXPRD;
1224 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
1225 ueDrxCb->drxShortCycleDistance = DRX_TMR_EXPRD;
1226 ueDrxCb->distance = DRX_TMR_EXPRD;
1228 /* Mark the UE in long/short cycle initially as per configuration*/
1229 if(FALSE == ueDrxCb->isShortCycleCfgd)
1231 ueDrxCb->isLongCycle = TRUE;
1235 ueDrxCb->isLongCycle = FALSE;
1238 /* Calculate the next occurance from this point */
1239 rgSCHDrxGetNxtOnDur (cell, ueDrxCb, &nxtOnDur,RG_SCH_NO_DELTA);
1242 nxtOnDurTime = ((nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur.slot);
1243 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1244 cell->crntTime.slot);
1246 onDurIndx = nxtOnDurTime % RG_SCH_MAX_DRXQ_SIZE;
1248 ueDrxCb->distance = (nxtOnDurTime - curTime) / RG_SCH_MAX_DRXQ_SIZE;
1249 if (ueDrxCb->distance < 0)
1251 RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId, "DRXUE. Invalid "
1252 "value for distance, %d CRNTI:%d", ueDrxCb->distance,ue->ueId);
1254 //printf("The onduartion index is: %d\n",(int)onDurIndx);
1255 cmLListAdd2Tail(&(cell->drxCb->drxQ[onDurIndx].onDurationQ),
1256 &(ueDrxCb->onDurationEnt));
1258 ueDrxCb->onDurationEnt.node = (PTR)ue;
1259 ueDrxCb->onDurIndx = onDurIndx;
1261 /* Starting Short Cycle Timer */
1262 if(TRUE == ueDrxCb->isShortCycleCfgd)
1264 ueDrxCb->drxShortCycleDistance = (ueDrxCb->shortCycleTmrLen *
1265 ueDrxCb->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
1266 ueDrxCb->shortCycleIndx = (curTime + (ueDrxCb->shortCycleTmrLen *
1267 ueDrxCb->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
1268 cmLListAdd2Tail(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1269 &(ueDrxCb->shortCycleEnt));
1270 ueDrxCb->shortCycleEnt.node = (PTR)ue;
1274 } /* end of rgSCHDrxUeCfg */
1276 /** @brief This function gets the next occurance of onDurationTimer from the
1279 * @details rgSCHDrxGetNxtOnDur
1281 * Function: rgSCHDrxGetNxtOnDur
1283 * Processing steps: -
1284 * Calculation of first occurance of onDuration is to be done as
1286 * Assume DRX configuration came at subframe (x, y) the periodicity is
1287 * offset = (perd, offset).
1288 * The (sfn, subframe) satisfying the following condition is the first
1289 * occurance from this point.
1291 * (sfn * 10 + subframe) mod perd = offset
1296 * @param RgSchCellCb *cell
1297 * @param RgSchDrxUeCb *drxCb
1298 * @param CmLteTimingInfo *nxtOnDur
1299 * @param uint8_t delta
1300 * @return ROK/RFAILED
1303 static S16 rgSCHDrxGetNxtOnDur
1306 RgSchDrxUeCb *drxCb,
1307 CmLteTimingInfo *nxtOnDur,
1311 static S16 rgSCHDrxGetNxtOnDur (cell, drxCb, nxtOnDur, delta)
1313 RgSchDrxUeCb *drxCb;
1314 CmLteTimingInfo *nxtOnDur;
1321 uint32_t numOfCycles;
1325 #if ( ERRCLASS & ERRCLS_INT_PAR )
1326 if ( cell == (RgSchCellCb* )NULLP )
1331 if( (drxCb == (RgSchDrxUeCb* )NULLP)
1333 (nxtOnDur == (CmLteTimingInfo* )NULLP)
1336 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
1337 "rgSCHDrxGetNxOnDur():Invalid params."
1338 "cell/drxCb/nxtOnDur is NULL");
1344 if (TRUE == drxCb->isLongCycle)
1346 cycleLen = drxCb->longDrxCycle;
1350 cycleLen = drxCb->shortDrxCycle;
1353 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) + cell->crntTime.slot);
1355 curTime += delta; /*TODO: see if we need to take care of wrap arounds */
1357 if ( curTime <= drxCb->drxStartOffset )
1359 /* offset is the nextOnDur */
1360 nxtOnDur->sfn = drxCb->drxStartOffset / RGSCH_NUM_SUB_FRAMES_5G;
1361 nxtOnDur->slot = (uint8_t)(drxCb->drxStartOffset % RGSCH_NUM_SUB_FRAMES_5G);
1362 nxtDist = ((nxtOnDur->sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur->slot);
1366 curDist = curTime - drxCb->drxStartOffset;
1368 numOfCycles = curDist / cycleLen;
1370 if (0 == (curDist % cycleLen))
1372 /* Perfect match pick up the current time */
1373 /*nxtOnDur should be set to equal to currentTime + DELTA */
1374 nxtOnDur->sfn = (uint16_t)curTime / RGSCH_NUM_SUB_FRAMES_5G;
1375 nxtOnDur->slot = (uint16_t)curTime % RGSCH_NUM_SUB_FRAMES_5G;
1376 nxtDist = ((nxtOnDur->sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur->slot);
1381 nxtDist = drxCb->drxStartOffset + (numOfCycles + 1) *
1383 nxtOnDur->sfn = (uint16_t)nxtDist / RGSCH_NUM_SUB_FRAMES_5G;
1384 nxtOnDur->slot = (uint16_t)nxtDist % RGSCH_NUM_SUB_FRAMES_5G;
1389 /*If next On Duration is less than DL DELTA ahead, we will miss it and
1390 * hence need to move to the On-Duration after that.*/
1391 if((nxtDist - (curTime - delta)) <= RG_SCH_DRX_MAX_DELTA)
1393 nxtDist = nxtDist + cycleLen;
1394 nxtOnDur->sfn = (uint16_t)nxtDist / RGSCH_NUM_SUB_FRAMES_5G;
1395 nxtOnDur->slot = (uint16_t)nxtDist % RGSCH_NUM_SUB_FRAMES_5G;
1398 } /* end of rgSCHDrxGetNxtOnDur */
1400 /** @brief This function is a utility function to copy the UE configuration from
1401 * the RGR structure to the UE control block.
1404 * -Invoked by rgSCHDrxUeCfg
1406 * Function: rgSCHDrxCpyUeCfg
1409 * - Copies configuration values
1411 * @param RgSchDrxUeCb *ueCb
1412 * @param RgrUeDrxCfg *drxCfg
1413 * @return ROK/RFAILED
1416 static S16 rgSCHDrxCpyUeCfg
1422 static S16 rgSCHDrxCpyUeCfg (ueCb, drxCfg)
1424 RgrUeDrxCfg *drxCfg;
1428 #if ( ERRCLASS & ERRCLS_INT_PAR )
1429 if ( (ueCb == (RgSchDrxUeCb* )NULLP )
1431 (drxCfg == (RgrUeDrxCfg* )NULLP)
1439 /* Copy all values to UE control block */
1441 ueCb->cqiMask = drxCfg->cqiMask;
1442 #endif /*LTEMAC_R9*/
1443 ueCb->onDurTmrLen = drxCfg->drxOnDurTmr;
1444 ueCb->inactvtyTmrLen = drxCfg->drxInactvTmr;
1445 ueCb->drxRetransTmrLen = drxCfg->drxRetxTmr;
1446 ueCb->longDrxCycle = drxCfg->drxLongCycleOffst.longDrxCycle;
1447 ueCb->drxStartOffset = drxCfg->drxLongCycleOffst.drxStartOffst;
1448 ueCb->isShortCycleCfgd = drxCfg->drxShortDrx.pres;
1449 ueCb->shortDrxCycle = drxCfg->drxShortDrx.shortDrxCycle;
1450 ueCb->shortCycleTmrLen = drxCfg->drxShortDrx.drxShortCycleTmr;
1453 } /* end of rgSCHDrxCpyUeCfg */
1456 /** @brief This function is called by the configuration module when a UE is
1457 * reconfigured for DRX parameters.
1460 * Invoked By - rgSCHCfgRgrUeCfg
1462 * Function: rgSCHDrxUeReCfg
1463 * As per MAC specifications the new values of timers shall be applied only once
1464 * they are restarted, hence no processing is required for modified timer values.
1467 * - if offset and/or drxCycleLenght changes then recalculate the next
1469 * - remove the UE from current index
1470 * - add the UE to the new index.
1471 * - if short cycle is enabled
1472 * - set isShortCycleCfgd = TRUE
1474 * @param RgSchCellCb *cell
1475 * @param RgSchUeCb *ue
1476 * @param RgrUeRecfg *ueReCfg
1477 * @return ROK/RFAILED
1487 S16 rgSCHDrxUeReCfg (cell, ue, ueReCfg)
1490 RgrUeRecfg *ueReCfg;
1494 RgSchCmnCell *cellSch = NULLP;
1495 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
1498 Inst instIdx = cell->instIdx;
1499 RgSchDrxUeCb *ueDrxCb;
1500 CmLteTimingInfo nxtOnDur;
1501 uint16_t nxtOnDurTime;
1504 uint16_t shrtCycleExpIndx;
1505 uint16_t onDurExpTime;
1511 /* drx was disabled but now enabled for this ue */
1512 if ( (ue->isDrxEnabled == FALSE)
1514 (ueReCfg->ueDrxRecfg.isDrxEnabled == TRUE)
1517 /* allocated and initialize drxCb */
1518 ret = rgSCHUtlAllocSBuf(instIdx, (Data**)&ue->drxCb,
1519 (sizeof(RgSchDrxUeCb)));
1523 RLOG_ARG1(L_ERROR,DBG_CELLID,cell->cellId,
1524 "rgSCHdrxUeReCfg():""Memory allocation FAILED for DRX UE Cb CRNTI:%d",
1529 ue->isDrxEnabled = TRUE; /* sachin */
1530 /* initialize the masks */
1531 ue->drxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1532 ue->drxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1533 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
1534 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
1536 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1538 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1539 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1542 /* set all indexes to default values */
1543 ue->drxCb->onDurIndx = DRX_INVALID;
1544 ue->drxCb->onDurExpIndx = DRX_INVALID;
1545 ue->drxCb->drxInactvIndx = DRX_INVALID;
1546 ue->drxCb->shortCycleIndx = DRX_INVALID;
1548 /* set all distances to timer expiry */
1549 ue->drxCb->onDurExpDistance = DRX_TMR_EXPRD;
1550 ue->drxCb->drxInactDistance = DRX_TMR_EXPRD;
1551 ue->drxCb->drxShortCycleDistance = DRX_TMR_EXPRD;
1552 ue->drxCb->distance = DRX_TMR_EXPRD;
1555 if( ue->drxCb == NULLP )
1559 ueDrxCb = ue->drxCb;
1561 /*drx was enabled but now disabled for this UE */
1562 if ( (ue->isDrxEnabled == TRUE )
1564 (ueReCfg->ueDrxRecfg.isDrxEnabled == FALSE)
1567 /* remove UE from all DRX Queues */
1568 (Void)rgSCHDrxUeDel(cell,ue);
1571 /* ccpu00117052 - MOD - Passing double pointer
1572 for proper NULLP assignment*/
1573 rgSCHUtlFreeSBuf(instIdx,(Data **)(&((ue->drxCb))),
1574 sizeof(RgSchDrxUeCb));
1576 /* Resetting the DRX Bit set in Inactv Mask */
1577 ue->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
1578 ue->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
1580 ue->isDrxEnabled = FALSE;
1582 }/*isDrxEnabled == FALSE */
1585 /* If Application is updating DRX params */
1586 if (ueReCfg->ueRecfgTypes & RGR_UE_DRX_RECFG )
1588 rgSCHDrxCpyUeCfg (ueDrxCb, &ueReCfg->ueDrxRecfg);
1592 rgSCHEmtcDrxCpyUeCfg(ue, &ueReCfg->ueDrxRecfg);
1598 /* Removing the UE from existing index of shortcycle, if any*/
1599 if(ueDrxCb->shortCycleIndx != DRX_INVALID)
1601 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1602 &(ueDrxCb->shortCycleEnt));
1604 ueDrxCb->shortCycleEnt.node = (PTR) NULLP;
1605 ueDrxCb->shortCycleIndx = DRX_INVALID;
1608 /* Mark for intiating long/short cycle as per received config */
1609 if(FALSE == ue->drxCb->isShortCycleCfgd)
1611 ue->drxCb->isLongCycle = TRUE;
1615 ue->drxCb->isLongCycle = FALSE;
1618 /* Calculate the next occurance from this point */
1619 rgSCHDrxGetNxtOnDur (cell, ueDrxCb, &nxtOnDur,RG_SCH_NO_DELTA);
1621 /* remove the UE from the current onDuration Queue */
1622 if ( ueDrxCb->onDurIndx != DRX_INVALID )
1624 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurIndx].onDurationQ),
1625 &(ueDrxCb->onDurationEnt));
1629 nxtOnDurTime = (nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur.slot;
1630 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1631 cell->crntTime.slot);
1633 /* If Onduration timer of old configuration is already running then waiting till it expires */
1634 if((ueDrxCb->onDurExpIndx != DRX_INVALID) && (ueDrxCb->onDurExpDistance != DRX_TMR_EXPRD))
1636 curIndx = (curTime + RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
1637 RLOG_ARG3(L_DEBUG,DBG_CELLID,cell->cellId,
1638 "OLD ONDUR RUNNING-EXPIRES at %d curIdx-%d nxtOnDurTime-%d",
1639 ueDrxCb->onDurExpIndx,
1643 /* Manipulating the time when old onDuration timer can expire */
1644 if(curIndx >= ueDrxCb->onDurExpIndx)
1646 onDurExpTime = curTime + ((ueDrxCb->onDurExpDistance+1) * RG_SCH_MAX_DRXQ_SIZE)+ (ueDrxCb->onDurExpIndx - curIndx + RG_SCH_DRX_DL_DELTA);
1650 onDurExpTime = curTime + (ueDrxCb->onDurExpDistance * RG_SCH_MAX_DRXQ_SIZE)+ (ueDrxCb->onDurExpIndx - curIndx + RG_SCH_DRX_DL_DELTA);
1653 if(nxtOnDurTime <= onDurExpTime)
1655 if(ueDrxCb->isLongCycle)
1657 cycleLen = ueDrxCb->longDrxCycle;
1661 cycleLen = ueDrxCb->shortDrxCycle;
1663 /* Moving to the possible occassion of onduration after current onduration expiry:
1664 * If both are aligning then going for next cycle */
1665 nxtOnDurTime += ((onDurExpTime - nxtOnDurTime)/cycleLen + 1 ) *cycleLen ;
1668 /* Add the UE to the index which corresponds to the next onduration start*/
1669 onDurIndx = nxtOnDurTime % RG_SCH_MAX_DRXQ_SIZE;
1671 ueDrxCb->distance = (nxtOnDurTime - curTime) / RG_SCH_MAX_DRXQ_SIZE;
1672 if (ueDrxCb->distance < 0)
1674 RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId,"DRXUE. Invalid "
1675 "value for distance, %d CRNTI:%d", ueDrxCb->distance,ue->ueId);
1678 cmLListAdd2Tail(&(cell->drxCb->drxQ[onDurIndx].onDurationQ),
1679 &(ueDrxCb->onDurationEnt));
1681 ueDrxCb->onDurationEnt.node = (PTR)ue;
1682 ueDrxCb->onDurIndx = onDurIndx;
1685 cmLListInit(&dlInactvLst);
1686 /* Add to DL inactive list */
1687 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
1688 ue->dlDrxInactvLnk.node = (PTR)ue;
1689 /* Send the list to the scheduler to mark UE as inactive */
1690 cellSch = RG_SCH_CMN_GET_CELL(cell);
1691 cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
1694 /* Starting short cycle timer as per the existence of old onDuration timer */
1695 if(TRUE == ueDrxCb->isShortCycleCfgd)
1697 /* Expiring short DRX cycle Tmr once the number of short DRX cycles done */
1698 ueDrxCb->drxShortCycleDistance = (nxtOnDurTime + ueDrxCb->onDurTmrLen + (ueDrxCb->shortCycleTmrLen -1 )*
1699 ueDrxCb->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
1700 shrtCycleExpIndx = (nxtOnDurTime + ueDrxCb->onDurTmrLen + ((ueDrxCb->shortCycleTmrLen -1)*
1701 ueDrxCb->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
1702 cmLListAdd2Tail(&(cell->drxCb->drxQ[shrtCycleExpIndx].shortCycleQ),
1703 &(ueDrxCb->shortCycleEnt));
1704 ueDrxCb->shortCycleEnt.node = (PTR)ue;
1705 ueDrxCb->shortCycleIndx = shrtCycleExpIndx;
1711 } /* end of rgSCHDrxUeReCfg */
1714 /** @brief This function Loop through the list of HARQ processes for this
1715 * UE and delete from the harqRTTQ and harqRetxQ
1717 * Function: rgSCHDrxUeHqReset
1718 * Invoked by rgSCHDrxUeDel
1721 Loop through the list of HARQ processes for this UE and delete from
1722 * the harqRTTQ and harqRetxQ.
1724 * @param RgSchCellCb *cell
1725 * @return ROK/RFAILED
1728 Void rgSCHDrxUeHqReset
1736 Void rgSCHDrxUeHqReset(cell, ue, hqE, cellIdx)
1743 RgSchDlHqProcCb *hqP;
1744 RgSchDrxDlHqProcCb *drxHq =NULLP;
1747 for(i=0; i < hqE->numHqPrcs; i++)
1749 hqP = &hqE->procs[i];
1750 drxHq = RG_SCH_DRX_GET_DL_HQ(hqP);
1752 if(drxHq->rttIndx != DRX_INVALID)
1754 cmLListDelFrm (&(cell->drxCb->drxQ[drxHq->rttIndx].harqRTTQ),
1755 &(drxHq->harqRTTEnt));
1757 drxHq->rttIndx = DRX_INVALID;
1760 if(drxHq->reTxIndx != DRX_INVALID)
1762 cmLListDelFrm (&(cell->drxCb->drxQ[drxHq->reTxIndx].harqRetxQ),
1763 &(drxHq->harqRetxEnt));
1765 drxHq->reTxIndx = DRX_INVALID;
1769 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1770 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1773 /** @brief This function Deletes DRX specific context for a UE.
1775 * @details This funciton is invoked by the Configuration module on RGR UE Deletion.
1776 * This function removes the UE's context from all of the DRX Queues.
1777 * In addition it deletes context of UE's HARQ Processes present in the harqRTTQ
1781 * Function: rgSCHDrxUeDel
1782 * Invoked by rgSCHCfgRgrUeDel
1785 * - Remove the UE from the following queues
1786 * - onDurationQ - using onDurIndx
1787 * - onDurationExpQ - using onDurExpIndx
1788 * - inActvTmrQ - using drxInactvIndx
1789 * - shortCycleQ - using shortCycleIndx
1790 * - Loop through the list of HARQ processes for this UE and delete from
1791 * the harqRTTQ and harqRetxQ.
1793 * @param RgSchCellCb *cell
1794 * @param RgSchUeCb *ue
1795 * @return ROK/RFAILED
1804 S16 rgSCHDrxUeDel (cell, ue)
1809 RgSchDrxUeCb *ueDrxCb;
1810 RgSchDlHqEnt *hqE = NULLP;
1812 RgSchUeCellInfo *cellInfo = NULLP;
1814 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
1818 /* ccpu00129899: Moved the drx-enabled check to the caller */
1819 ueDrxCb = ue->drxCb;
1821 /* Remove UE from all queues */
1822 if ( ueDrxCb->onDurIndx != DRX_INVALID )
1824 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurIndx].onDurationQ),
1825 &(ueDrxCb->onDurationEnt));
1827 ueDrxCb->onDurIndx = DRX_INVALID;
1830 if ( ueDrxCb->onDurExpIndx != DRX_INVALID )
1832 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurExpIndx].onDurationExpQ),
1833 &(ueDrxCb->onDurationExpEnt));
1835 ueDrxCb->onDurExpIndx = DRX_INVALID;
1838 if ( ueDrxCb->drxInactvIndx != DRX_INVALID )
1840 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->drxInactvIndx].inActvTmrQ),
1841 &(ueDrxCb->inActvTmrEnt));
1843 ueDrxCb->drxInactvIndx = DRX_INVALID;
1846 if ( ueDrxCb->shortCycleIndx != DRX_INVALID )
1848 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1849 &(ueDrxCb->shortCycleEnt));
1851 ueDrxCb->shortCycleIndx = DRX_INVALID;
1854 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1856 cellInfo = ue->cellInfo[cellIdx];
1860 hqE = cellInfo->hqEnt;
1861 rgSCHDrxUeHqReset(cell, ue, hqE, cellIdx);
1867 rgSCHDrxUeUlHqReset(cell, ue, &(ueUl->hqEnt));
1870 /* Resetting the DRX Bit set in Inactv Mask */
1871 ue->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
1872 ue->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
1873 ueDrxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1874 ueDrxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1879 /** @brief This function is called at the time of RGR cell configuration.
1882 * Invoked by - rgSCHCfgRgrCellCfg
1884 * Function: rgSCHDrxCellCfg
1887 * - Initializes the following drxQ (memset would do).
1890 * @param RgSchCellCb *cell
1891 * @param RgrCellCfg *cellCfg
1892 * @return ROK/RFAILED
1901 S16 rgSCHDrxCellCfg (cell, cellCfg)
1903 RgrCellCfg *cellCfg;
1908 Inst instIdx = cell->instIdx;
1910 #if ( ERRCLASS & ERRCLS_INT_PAR )
1911 /*KWORK_FIX :Removed check for cell being NULL*/
1912 if( (cellCfg == (RgrCellCfg* )NULLP))
1914 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
1915 "rgSCHDrxCellCfg():Invalid Params. cell/cellCfg is NULL");
1920 /* allocate and initialize drxCb */
1921 ret = rgSCHUtlAllocSBuf(instIdx, (Data**)&cell->drxCb,
1922 (sizeof(RgSchDRXCellCb)));
1926 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,"rgSCHDrxCellCfg():"
1927 "Memory allocation FAILED for DRX cell Cb");
1931 /* delInUlScan determines which index scans the queue last.
1932 * We look at onDurationQ both from ulIndex & dlIndex pov.
1933 * Consider, onDuration starts at index 5, and current index is 2,
1934 * while dlIndex is 2 & ulIndex is 3 i.e dl is looking 2 SF ahead
1935 * and ul is looking 3 SF ahead. In this case, dl will scan the queue
1936 * last and therefore DL will delete ueCb from onDuration q.
1937 * The reverse is true for the other case.*/
1939 if ( RG_SCH_DRX_UL_DELTA > RG_SCH_DRX_DL_DELTA )
1941 cell->drxCb->delInUlScan = FALSE;
1945 cell->drxCb->delInUlScan = TRUE;
1949 } /* end of rgSchDrxCellCfg */
1953 /** @brief This function to delete DRX specific context in the cell control
1957 * Invoked by - rgSCHCfgRgrCellDel
1959 * Function: rgSCHDrxCellDel
1962 * - De-Inits RgSchDRXCellCb (Nothing to be done)
1963 * - Assumption: The API is invoked after deletion of UEs from the cell.
1965 * @param RgSchCellCb *cell
1969 Void rgSCHDrxCellDel
1974 Void rgSCHDrxCellDel (cell)
1978 Inst instIdx = cell->instIdx;
1982 /* ccpu00117052 - MOD - Passing double pointer
1983 for proper NULLP assignment*/
1984 rgSCHUtlFreeSBuf(instIdx, (Data **)(&(cell->drxCb)),
1985 sizeof(RgSchDRXCellCb));
1988 } /* end of rgSchDrxCellDel */
1990 /** @brief This function is called when an SR is received from the UE. In this
1991 * case the UE should be marked as ACTIVE till we send a UL allocation to the
1995 * Invoked by - rgSCHCmnSrRcvd
1996 * Must be called after calling the specific scheduler.
1998 * Function: rgSCHDrxSrInd
2001 * - Mark the UE as ACTIVE
2002 * ueCb->drxUlInactvMask |= (DRX_SR_ACTIVE);
2003 * - Optionally call schedulers to add this UE to their scheduling
2005 * - Set drxUe->srRcvd = TRUE
2007 * Note : the specification state that the UE shall start be active
2008 * listening for UL grant, this implies we could potentially exploit
2009 * this to send DL transmissions as well. However we have currently
2010 * chosen not to do so.
2012 * @param RgSchCellCb *cell
2013 * @param RgSchUeCb *ue
2014 * @return ROK/RFAILED
2023 S16 rgSCHDrxSrInd (cell, ue)
2028 RgSchDrxUeCb *drxCb;
2030 #if ( ERRCLASS & ERRCLS_INT_PAR )
2031 if ( cell == (RgSchCellCb* )NULLP)
2036 if( (ue == (RgSchUeCb* )NULLP))
2038 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
2039 "rgSCHDrxSrInd():Invalid Params. cell/ue is NULL");
2043 /* KWork fix - shifted this down */
2046 drxCb = RG_SCH_DRX_GET_UE(ue);
2048 /* Mark the UE as active for UL only */
2049 drxCb->drxUlInactvMask &= ~RG_SCH_DRX_SR_BITMASK;
2050 drxCb->srRcvd = TRUE;
2051 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2052 RG_SCH_CMN_UL_UPDT_INACTV_MASK( cell, ue, RG_DRX_INACTIVE);
2055 } /* rgSCHDrxSrInd */
2058 /** @brief This function handles ACTIVITY due to RACH using a dedicated preamble
2059 * (PDCCH order) OR Handover. A UE shall remain marked as active from the time
2060 * we successfully send out a RAR upto the time it receives a PDCCH indicating a
2064 * Invoked by - rgSCHCmnHdlHoPo
2066 * Function: rgSCHDrxDedRa
2069 * - MARK the UE as active
2070 * - set the raRcvd = TRUE for this UE.
2073 * ueCb->drxDlInactvMask |= (DRX_RA_ACTIVE);
2074 * ueCb->drxUlInactvMask |= (DRX_RA_ACTIVE);
2075 * ueCb->raRcvd = TRUE;
2078 * @param RgSchCellCb *cellCb
2079 * @param RgSchUeCb *ueCb
2085 RgSchCellCb *cellCb,
2089 Void rgSCHDrxDedRa (cellCb, ueCb)
2090 RgSchCellCb *cellCb;
2094 RgSchDrxUeCb *drxCb;
2096 drxCb = RG_SCH_DRX_GET_UE(ueCb);
2098 /* Mark the UE as active for UL & DL */
2099 drxCb->drxUlInactvMask &= ~RG_SCH_DRX_RA_BITMASK;
2100 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2101 RG_SCH_CMN_UL_UPDT_INACTV_MASK(cellCb, ueCb, RG_DRX_INACTIVE);
2103 drxCb->drxDlInactvMask &= ~RG_SCH_DRX_RA_BITMASK;
2104 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2105 RG_SCH_CMN_DL_UPDT_INACTV_MASK(cellCb, ueCb, RG_DRX_INACTIVE);
2107 drxCb->raRcvd = TRUE;
2110 } /* end of rgSCHDrxDedRa */
2113 /** @brief This function calculates the next onDuration Occurence
2114 * and removes & queue it again in onDurationQ
2119 * Function: rgSCHDrxMvToNxtOnDurOcc
2124 * @param RgSchCellCb *cell
2125 * @param RgSchUeCb *ueCb
2126 * @param uint16_t idx - if calcFrmOffst is TRUE,
2127 * idx is delta to be added
2128 * @param Bool calcFrmOffst
2132 static Void rgSCHDrxMvToNxtOnDurOcc
2140 static Void rgSCHDrxMvToNxtOnDurOcc (cell, ueCb, idx, calcFrmOffst)
2147 uint16_t nxtOnDurIndex;
2149 RgSchDrxUeCb *drxUe;
2150 RgSchDRXCellCb *drxCell;
2151 CmLteTimingInfo nxtOnDur; /* to be used when calcFrmOffset is set */
2152 uint16_t nxtOnDurInSf; /* next On Duration in no of subframes */
2154 drxCell = cell->drxCb;
2155 drxUe = ueCb->drxCb;
2158 if(calcFrmOffst == FALSE)
2160 if (drxUe->isLongCycle)
2162 nxtOnDurIndex = ((idx + drxUe->longDrxCycle)
2163 % RG_SCH_MAX_DRXQ_SIZE );
2164 drxUe->distance = drxUe->longDrxCycle/RG_SCH_MAX_DRXQ_SIZE;
2168 nxtOnDurIndex = ((idx + drxUe->shortDrxCycle)% RG_SCH_MAX_DRXQ_SIZE);
2170 drxUe->distance = drxUe->shortDrxCycle / RG_SCH_MAX_DRXQ_SIZE;
2175 rgSCHDrxGetNxtOnDur(cell,drxUe,&nxtOnDur,(uint8_t)idx);
2177 nxtOnDurInSf = ((nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
2180 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
2181 cell->crntTime.slot);
2183 nxtOnDurIndex = nxtOnDurInSf % RG_SCH_MAX_DRXQ_SIZE;
2184 drxUe->distance = (nxtOnDurInSf-curTime) / RG_SCH_MAX_DRXQ_SIZE;
2185 if (drxUe->distance < 0)
2187 RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId,"DRXUE. Invalid "
2188 "value for distance, %d CRNTI:%d", drxUe->distance,ueCb->ueId);
2192 /* First remove from existing location */
2193 if ( drxUe->onDurIndx != DRX_INVALID )
2195 cmLListDelFrm(&(drxCell->drxQ[drxUe->onDurIndx].onDurationQ),
2196 &(drxUe->onDurationEnt));
2199 /* Add at new location */
2200 cmLListAdd2Tail(&(drxCell->drxQ[nxtOnDurIndex].onDurationQ),
2201 &(drxUe->onDurationEnt));
2203 drxUe->onDurationEnt.node = (PTR)ueCb;
2204 drxUe->onDurIndx = nxtOnDurIndex;
2207 }/*rgSCHDrxMvToNxtOnDurOcc*/
2210 /** @brief This function calculates the next SFN,subframe a given
2211 * timer is going to expire. Works for all TDD configurations.
2215 * Function: rgSCHDrxGetNxtTmrExpry
2216 * We need to count only PDCCH frames in a given TDD
2217 * configuration. This is true for onDuration, inActivity
2218 * & drx-retransmission timers.
2220 * Processing steps (assume timer starts at (12,2) and duration
2221 * is 23 DL subframes):
2222 * - based on TDD configuration, move to the next SFN and
2223 * count the number of DL subframes consumed. In our example,
2224 * moving to (12,9) will consume 6 DL subframes assuming TDD
2226 * - From this point on, determine how many exact Radio Frames
2227 * will be consumed for the remaining DL subframes. In our
2228 * example, remaining DL subframes are (23-6) are 17.
2229 * For config 2, the following holds true
2230 * 8 DLSF are in 1 RF
2231 * 1 DLSF in 1/8 DLSF
2232 * 17 DLSF in 17/8 i.e 2 RF + 1 subframe
2233 * In order to consume 17 DLSF, we need to move forward
2234 * 2 RFs + 1 subframe. Adding 2 RF's gives us (14,9)
2235 * - For the remaining subframe, we need to figure out the next
2236 * available DL subframe. For TDD_configuration, the first DL
2237 * subframe is at index 0. So, the timer will run till (15,0)
2238 * and will expire on (15,1)
2240 * @param RgSchUeCb *ue Ue control block.
2241 * @param uint16_t curTime current Time
2242 * @param uint32_t duration Timer duration
2243 * @param CmLteTimingInfo *tmrExpryIdx Timer expry (SFN,sf)
2244 * @return ROK/RFAILED
2247 static S16 rgSCHDrxGetNxtTmrExpry
2252 CmLteTimingInfo *tmrExpryIdx
2255 static S16 rgSCHDrxGetNxtTmrExpry (cell,curTime,duration,tmrExpryIdx)
2259 CmLteTimingInfo *tmrExpryIdx;
2262 uint32_t dlSfTillNxtSFN; /*!< DL subframes till next SFN */
2263 uint8_t tddCfgMode; /*!< tdd config mode */
2264 Bool isDwPtsCnted; /*!< is DwPts counted as PDCCH sf */
2265 CmLteTimingInfo crntTime; /*!< current SFN & sf */
2268 #if ( ERRCLASS & ERRCLS_INT_PAR )
2269 if ( (cell == (RgSchCellCb* )NULLP)
2271 (tmrExpryIdx == (CmLteTimingInfo* )NULLP)
2279 isDwPtsCnted = cell->isDwPtsCnted ;
2281 tddCfgMode = cell->ulDlCfgIdx;
2282 crntTime.sfn = curTime / RGSCH_NUM_SUB_FRAMES_5G;
2283 crntTime.slot = curTime % RGSCH_NUM_SUB_FRAMES_5G;
2287 /* First calculate the number of DL subframes till next SFN */
2289 dlSfTillNxtSFN = rgSchDrxDLSfTillNxtSFN[isDwPtsCnted][tddCfgMode]
2290 [(crntTime.slot % RGSCH_NUM_SUB_FRAMES)];
2293 if ( dlSfTillNxtSFN >= duration )
2295 /* the timer would expire on the same RF */
2296 uint32_t diff = dlSfTillNxtSFN - duration;
2298 tmrExpryIdx->sfn = crntTime.sfn;
2302 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2308 /* to know the DL sf index based on diff */
2309 arrayIdx = rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2311 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2314 }/* if ( dlSfTillNxtSFN >= duration...*/
2317 uint32_t remSf; /*!< remaining subframes */
2318 uint32_t numRf; /*!< num of complete radio frames */
2319 uint32_t numRemSfs; /*!< num of remaining subframes */
2321 remSf = duration - dlSfTillNxtSFN;
2323 /* move to (currSFN,9) having consued dlSfTillNxtSFN DL subframes */
2324 tmrExpryIdx->sfn = crntTime.sfn;
2325 tmrExpryIdx->subframe = (uint8_t)9;
2327 numRf = (1 * remSf)/rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2328 numRemSfs = (1 * remSf)%rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2330 tmrExpryIdx->sfn = tmrExpryIdx->sfn + numRf;
2332 /* we are now at (X,9) having consumed dlSfTillNxtSFN + numRf * num of DL
2333 * subframes in 1 RF */
2335 if ( numRemSfs == 0 )
2337 /* we are at subframe 9 i.e. the timer is going to expire using exact
2338 * radio frames. However, not all TDD_configurations have 9 as their
2339 * last DL subframe. We might have passed the last DL subfrme.
2340 * Therefore, move back */
2341 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2346 /* a reminder implies we have to move past this SFN as we are at the
2347 * last subframe on that SFN */
2349 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2352 }/*else if diff > duration */
2354 /* timer will expire 1 + tmrExpryIdx */
2356 if ( ( tmrExpryIdx->subframe + 1) == 10 )
2359 tmrExpryIdx->subframe = 0;
2363 tmrExpryIdx->subframe++;
2366 /* check to see if it sfn has crossed its max */
2367 if ( tmrExpryIdx->sfn > RG_SCH_CMN_MAX_SFN_NUM )
2369 tmrExpryIdx->sfn = tmrExpryIdx->sfn - (RG_SCH_CMN_MAX_SFN_NUM + 1);
2373 }/*rgSCHDrxGetNxtTmrExpry*/
2375 /** @brief This function calculates the next onDuration Occurence
2380 * Function: rgSCHDrxCalcNxtTmrExpry
2382 * Processing steps: a wrapper function to call
2383 * rgSCHDrxGetNxtTmrExpry
2385 * @param RgSchCellCb *cell
2386 * @param RgSchUeCb *ue
2387 * @param uint16_t delta
2388 * @param uint32_t tmrLen
2389 * @param uint16_t *distance
2391 * @return ROK/RFAILED
2394 static Void rgSCHDrxCalcNxtTmrExpry
2404 static Void rgSCHDrxCalcNxtTmrExpry (cell,ue,delta,tmrLen,distance,idx)
2413 uint16_t curTimeInSf; /*current time in no of subframes*/
2414 CmLteTimingInfo tmrExpry;
2415 uint16_t tmrExpryInSf; /*timer expry in no of subframes*/
2417 curTimeInSf = cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G +
2418 cell->crntTime.slot;
2420 /* add delta to curTime */
2421 curTimeInSf += delta;
2423 rgSCHDrxGetNxtTmrExpry(ue->cell,curTimeInSf,tmrLen,&tmrExpry);
2425 /* convert timre Expry in terms of subframes */
2426 tmrExpryInSf = tmrExpry.sfn * RGSCH_NUM_SUB_FRAMES_5G +
2430 *idx = (tmrExpryInSf) % RG_SCH_MAX_DRXQ_SIZE;
2432 if ( distance != NULLP ) /* hqReTx don't use the concept of distance.
2433 They can send NULLP for distance.
2436 if ( tmrExpryInSf > curTimeInSf )
2438 *distance = (tmrExpryInSf - curTimeInSf) /
2439 RG_SCH_MAX_DRXQ_SIZE;
2443 /* in case the RF is at its max and wraps around */
2445 *distance = ((tmrExpryInSf + (RG_SCH_CMN_MAX_NUM_OF_SFN - 1))
2447 curTimeInSf) / RG_SCH_MAX_DRXQ_SIZE;
2451 RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId, "DRXUE. Invalid "
2452 "value for distance, %d CRNTI:%d", *distance,ue->ueId);
2457 }/*rgSCHDrxCalcNxtTmrExpry*/
2459 /* ccpu00134670- Validating onduration timer versus DRX cycle*/
2460 /***********************************************************
2462 * Func : rgSCHCfgVldtTddDrxCycCfg
2465 * Desc : Validates DRX Cycle Length configuration against received
2466 * onDuration timer from RRC.
2477 **********************************************************/
2479 S16 rgSCHCfgVldtTddDrxCycCfg
2487 S16 rgSCHCfgVldtTddDrxCycCfg(cell, drxCycle, onDurTmr, offSet)
2495 uint16_t endTimeInSf;
2496 CmLteTimingInfo endTime;
2501 rgSCHDrxGetNxtTmrExpry(cell, startTime, onDurTmr, &endTime);
2503 endTimeInSf = (endTime.sfn* RGSCH_NUM_SUB_FRAMES)+endTime.subframe;
2505 if(((RGSCH_MAX_SUBFRM_5G + endTimeInSf- startTime) % RGSCH_MAX_SUBFRM_5G) >=
2511 startTime = (startTime + drxCycle);
2512 /* Going for next iteration if the DRX cycle is not multiple of 10. If it is
2513 multiple of 10(Number of Subframes in a SFN) then subframe, at which
2514 onduration timer can start, will be always same, Otherwise the possible
2515 subframe numbers, where the onDuration timer can start, is 5. Hence 4
2516 more iterations are required. */
2517 }while((drxCycle % RGSCH_NUM_SUB_FRAMES) &&
2518 (startTime < (drxCycle * RGSCH_NUM_SUB_FRAMES/2)));
2525 /** @brief This function is called to handle onDurationTimer per TTI processing.
2528 * Invoked by - rgSCHDrxTtiInd
2530 * Function: rgSCHDrxTtiHdlOnDurUl
2534 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
2536 * - For Uplink we shall look at an index that is
2537 * n + RG_SCH_DRX_UL_DELTA as
2538 * we are concerned with the PDCCH and not the actual PUSCH.
2541 * @param RgSchCellCb *cellCb
2542 * @param uint16_t ulIndex
2547 static Void rgSCHDrxTtiHdlOnDurUl
2553 static Void rgSCHDrxTtiHdlOnDurUl(cell, ulIndex)
2559 RgSchDRXCellCb *drxCell = NULLP;
2560 RgSchUeCb *ue = NULLP;
2561 RgSchDrxUeCb *drxUe = NULLP;
2562 CmLListCp ulInactvLst; /* list of UE's becoming DL-inactive */
2563 RgSchCmnCell *cellSch = NULLP;
2564 Bool delInUlScan = FALSE;
2566 drxCell = (cell->drxCb);
2567 delInUlScan = drxCell->delInUlScan;
2568 /***********************************************************
2569 * Scanning OnDurationQ in UL
2570 ***********************************************************/
2572 /* For Uplink we shall look at an index that is n + RG_SCH_DRX_UL_DELTA as
2573 we are concerned with the PDCCH and not the actual PUSCH.*/
2575 node = drxCell->drxQ[ulIndex].onDurationQ.first;
2579 ue = (RgSchUeCb*)node->node;
2581 drxUe = RG_SCH_DRX_GET_UE(ue);
2584 if ( delInUlScan == FALSE)
2589 if ( drxUe->distance != DRX_TMR_EXPRD )
2594 /* reset the bit mask to indicate that onduration has started */
2595 drxUe->drxUlInactvMask &= ~RG_SCH_DRX_ONDUR_BITMASK;
2597 /* if no other condition is keeping UE as inactive,
2600 RG_SCH_CMN_UL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2602 if ( delInUlScan == TRUE )
2604 /*calculate next on duration occurence
2605 * and it to the onDuration Queue*/
2606 rgSCHDrxMvToNxtOnDurOcc(cell,ue,ulIndex,FALSE);
2607 }/*delInUlScan == FALSE */
2610 /***********************************************************
2611 * Scanning OnDurationExpQ in UL
2612 ***********************************************************/
2614 node = drxCell->drxQ[ulIndex].onDurationExpQ.first;
2616 /* Initialize UL inactive list */
2617 cmLListInit(&ulInactvLst);
2621 ue = (RgSchUeCb*)node->node;
2623 drxUe = RG_SCH_DRX_GET_UE(ue);
2625 if ( delInUlScan == FALSE )
2627 drxUe->onDurExpDistance--;
2630 if ( drxUe->onDurExpDistance != DRX_TMR_EXPRD )
2635 /*UE is inactive as onduration has expired */
2636 drxUe->drxUlInactvMask |= RG_SCH_DRX_ONDUR_BITMASK;
2638 if( !RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
2640 /* set the inactive bit to indicate UE has now become inactive */
2641 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
2643 /* Add to DL inactive list */
2644 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
2645 ue->ulDrxInactvLnk.node = (PTR)ue;
2648 if ( delInUlScan == TRUE)
2650 /*Remove from DRX queue*/
2651 cmLListDelFrm(&(drxCell->drxQ[ulIndex].onDurationExpQ),
2652 &(drxUe->onDurationExpEnt));
2654 drxUe->onDurExpIndx = DRX_INVALID;
2659 /* Send the list to the scheduler to mark UE as inactive in UL*/
2660 cellSch = RG_SCH_CMN_GET_CELL(cell);
2661 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
2666 /** @brief This function is called to handle onDurationTimer per TTI processing.
2669 * Invoked by - rgSCHDrxTtiInd
2671 * Function: rgSCHDrxTtiHdlOnDurDl
2675 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
2677 * - For Downlink we shall look at an index that is
2678 * n + RG_SCH_DRX_DL_DELTA.
2681 * @param RgSchCellCb *cellCb
2682 * @param uint16_t dlIndex
2687 static Void rgSCHDrxTtiHdlOnDurDl
2693 static Void rgSCHDrxTtiHdlOnDurDl(cell, dlIndex)
2699 RgSchDRXCellCb *drxCell = NULLP;
2700 RgSchUeCb *ue = NULLP;
2701 RgSchDrxUeCb *drxUe = NULLP;
2702 RgSchCmnCell *cellSch = NULLP;
2703 uint16_t expiryIndex;
2704 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
2705 Bool delInUlScan = FALSE;
2707 /* The DL loop, if onDurationTimer has started, will add the UeCb
2708 * in the onDurationTmrExprQ. If !delInUlScan, then calculate the next
2709 * OnDuration occurence, q it there and remove it from the current location.
2711 /***********************************************************
2712 * Scanning OnDurationQ in DL
2713 ***********************************************************/
2714 drxCell = (cell->drxCb);
2716 delInUlScan = drxCell->delInUlScan;
2717 //printf("CELL Timer [SFN : %d],[SF : %d]\n",cell->crntTime.sfn,cell->crntTime.slot);
2719 node = drxCell->drxQ[dlIndex].onDurationQ.first;
2724 ue = (RgSchUeCb* )node->node;
2728 drxUe = RG_SCH_DRX_GET_UE(ue);
2730 if ( delInUlScan == TRUE)
2735 if ( drxUe->distance != DRX_TMR_EXPRD )
2741 /* UE is active as onduration is to start */
2742 drxUe->drxDlInactvMask &= ~RG_SCH_DRX_ONDUR_BITMASK;
2744 /* set the UE as DRX active*/
2746 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2747 RG_SCH_CMN_DL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2749 /* Temporary fix to delete stale entry */
2750 if (drxUe->onDurExpIndx != DRX_INVALID)
2752 RLOG_ARG4(L_DEBUG,DBG_CELLID,cell->cellId,
2753 "UEID:%d PreExisted[%d:%d]in onDurExpQ new[%d]",
2755 drxUe->onDurExpIndx,
2756 drxUe->onDurExpDistance,
2758 cmLListDelFrm(&(drxCell->drxQ[drxUe->onDurExpIndx].onDurationExpQ),
2759 &(drxUe->onDurationExpEnt));
2761 drxUe->onDurExpIndx = DRX_INVALID;
2763 /*start the onduration expiry timer*/
2765 rgSCHDrxCalcNxtTmrExpry(cell,
2769 &(drxUe->onDurExpDistance),
2773 expiryIndex = ((dlIndex + drxUe->onDurTmrLen) %
2774 RG_SCH_MAX_DRXQ_SIZE);
2775 drxUe->onDurExpDistance = (drxUe->onDurTmrLen)/
2776 RG_SCH_MAX_DRXQ_SIZE;
2779 cmLListAdd2Tail(&(drxCell->drxQ[expiryIndex].onDurationExpQ),
2780 &(drxUe->onDurationExpEnt));
2781 //printf("DRXOnDuration Timer Started at [SFN : %d],[SF : %d]\n",cell->crntTime.sfn,cell->crntTime.slot);
2782 drxUe->onDurationExpEnt.node = (PTR)ue;
2783 drxUe->onDurExpIndx = expiryIndex;
2785 //printf("DRxOnDuration will Expire = [%d]\n",(cell->crntTime.sfn*10+cell->crntTime.slot+drxUe->onDurTmrLen));
2787 if ( delInUlScan == FALSE )
2789 /*calculate next on duration occurence
2790 * and it to the onDuration Queue*/
2791 rgSCHDrxMvToNxtOnDurOcc(cell,ue,dlIndex,FALSE);
2792 }/*delInUlScan == FALSE */
2796 /***********************************************************
2797 * Scanning OnDurationExpQ in DL
2798 ***********************************************************/
2800 /* Mark UE as Inactive based on OnDuration Expiry */
2801 node = drxCell->drxQ[dlIndex].onDurationExpQ.first;
2803 /* Initialize DL inactive list */
2804 cmLListInit(&dlInactvLst);
2808 ue = (RgSchUeCb*)node->node;
2810 drxUe = RG_SCH_DRX_GET_UE(ue);
2812 if ( delInUlScan == TRUE )
2814 drxUe->onDurExpDistance--;
2817 if ( drxUe->onDurExpDistance != DRX_TMR_EXPRD )
2823 /* UE is inactive as onduration has expired */
2824 drxUe->drxDlInactvMask |= (RG_SCH_DRX_ONDUR_BITMASK);
2826 if( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
2828 /* set the inactive bit to indicate UE has now become inactive */
2829 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
2831 /* Add to DL inactive list */
2832 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
2833 ue->dlDrxInactvLnk.node = (PTR)ue;
2836 if ( delInUlScan == FALSE )
2838 /*Remove from DRX queue*/
2839 cmLListDelFrm(&(drxCell->drxQ[dlIndex].onDurationExpQ),
2840 &(drxUe->onDurationExpEnt));
2842 drxUe->onDurExpIndx = DRX_INVALID;
2847 /* Send the list to the scheduler to mark UE as inactive */
2848 cellSch = RG_SCH_CMN_GET_CELL(cell);
2849 cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
2852 }/*rgSCHDrxTtiHdlOnDurDl*/
2854 /** @brief This function handles the Dl HARQ timer's processing per TTI.
2857 * Invoked by - rgSCHDrxTtiHdlDlHarq
2859 * Function: rgSCHDrxTtiHdlDlHarqRTT
2862 * - In addition per TTI DRX module must look at Downlink HARQ queues
2863 * maintained to track HARQ RTT timer and drx-RetransmissionTimer.
2864 * Every TTI at the scheduling index we shall check these queues and
2865 * process accordingly.
2867 * @param RgSchCellCb *cellCb
2868 * @param uint16_t dlIndex
2873 static Void rgSCHDrxTtiHdlDlHarqRTT
2879 static Void rgSCHDrxTtiHdlDlHarqRTT(cell, dlIndex)
2885 RgSchDrxDlHqProcCb *drxHq;
2886 RgSchDlHqProcCb *dlHq;
2887 RgSchDRXCellCb *drxCell;
2888 RgSchDrxUeCb *drxUe;
2889 uint16_t reTxExpIndx;
2892 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
2893 RgSchCmnCell *cellSch = RG_SCH_CMN_GET_CELL(cell);
2895 uint32_t dlInactvMask;
2897 drxCell = cell->drxCb;
2898 delInUlScan = drxCell->delInUlScan;
2900 /***********************************************************
2901 * Scanning harqRTTQ in DL
2902 ***********************************************************/
2904 cmLListInit(&dlInactvLst);
2905 node = drxCell->drxQ[dlIndex].harqRTTQ.first;
2909 dlHq = (RgSchDlHqProcCb*)node->node;
2913 if(TRUE == ue->isEmtcUe)
2918 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2919 drxUe = RG_SCH_DRX_GET_UE(ue);
2920 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2921 /* add the UE to the cell's retransmission queuee before starting
2922 * reTx timer, because this will not depend on retx timer trigger*/
2923 rgSCHUtlDlProcAddToRetx(dlHq->hqE->cell, dlHq);
2925 if ( delInUlScan == FALSE)
2927 cmLListDelFrm (&(drxCell->drxQ[dlIndex].harqRTTQ),
2928 &(drxHq->harqRTTEnt));
2930 drxHq->rttIndx = DRX_INVALID;
2932 /* ccpu00134565: Starting retransmission timer only if timerLen is
2933 * having non-zero value after reduction, Adding to Retx queue is
2934 * independent of starting retransmission timer. Hence if part will
2935 * take care of starting retx timer only*/
2936 if (drxUe->drxRetransTmrLen > drxHq->retxTmrReduction)
2938 /* add the harq proc to the re-tx queue--*/
2940 /* ccpu00134196-[Add]-DRX retx timer changes */
2941 rgSCHDrxCalcNxtTmrExpry(cell,
2944 drxUe->drxRetransTmrLen-drxHq->retxTmrReduction,
2945 NULLP, /*retransQ does not maintain distance*/
2950 /* ccpu00134196-[Add]-DRX retx timer changes */
2951 reTxExpIndx = ((dlIndex +
2952 drxUe->drxRetransTmrLen-drxHq->retxTmrReduction) %
2953 RG_SCH_MAX_DRXQ_SIZE);
2955 /* TODO. Workaround to avoid duplicate entry */
2956 if(drxHq->reTxIndx == DRX_INVALID)
2958 cmLListAdd2Tail (&(drxCell->drxQ[reTxExpIndx].harqRetxQ),
2959 &(drxHq->harqRetxEnt));
2961 drxHq->harqRetxEnt.node = (PTR)dlHq;
2962 drxHq->reTxIndx = reTxExpIndx;
2966 RLOG_ARG4(L_ERROR,DBG_CELLID,cell->cellId,"CRNTI:%d "
2967 "Adding Retx Node to expire at RetxIndx: %d at dlIndex %d "
2968 "drxHq->reTxIndx %d", ue->ueId, reTxExpIndx, dlIndex,
2972 /*mark the ue as active for downlink--*/
2973 drxUe->drxDlInactvMask &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2974 drxUe->drxDlInactvMaskPerCell[cellIdx] &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2976 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2977 RG_SCH_CMN_DL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2981 /***********************************************************
2982 * Scanning harqRetxQ in DL
2983 ***********************************************************/
2985 node = drxCell->drxQ[dlIndex].harqRetxQ.first;
2988 dlHq = (RgSchDlHqProcCb*)node->node;
2990 drxUe = RG_SCH_DRX_GET_UE(ue);
2992 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2993 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2995 /*mark the ue as in-active for downlink*/
2996 drxUe->drxDlInactvMaskPerCell[cellIdx] |= (RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2998 dlInactvMask = RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId;
3000 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
3002 dlInactvMask &= drxUe->drxDlInactvMaskPerCell[cellIdx];
3005 drxUe->drxDlInactvMask |= dlInactvMask;
3007 /* if no other condition is keeping ue active,
3010 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
3012 ue->dl.dlInactvMask |= (RG_DRX_INACTIVE);
3014 /* Add to DL inactive list */
3015 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
3016 ue->dlDrxInactvLnk.node = (PTR)ue;
3019 /*remove the harq proc from this queue*/
3020 if ( delInUlScan == FALSE)
3022 cmLListDelFrm (&(drxCell->drxQ[dlIndex].harqRetxQ),
3023 &(drxHq->harqRetxEnt));
3024 drxHq->reTxIndx = DRX_INVALID;
3027 /*Call schedulers to inactivate ue*/
3028 cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
3033 /** @brief This function handles the Ul HARQ timer's processing per TTI.
3036 * Invoked by - rgSCHDrxTtiHdlDlHarq
3038 * Function: rgSCHDrxTtiHdlUlHarqRTT
3041 * - In addition per TTI DRX module must look at Downlink HARQ queues
3042 * maintained to track HARQ RTT timer and drx-RetransmissionTimer.
3043 * Every TTI at the scheduling index we shall check these queues and
3044 * process accordingly.
3046 * - Though these timers are related to downlink HARQ processing, they
3047 * have an impact on uplink scheduling. The reason is that the UE,
3048 * if active for downlink scheduling implies that it is reading
3049 * PDCCHs i.e. we can still send uplink allocations to the UE. Hence
3050 * every TTI Uplink too would look at the harqRTTQ and harqRetxQ.
3054 * @param RgSchCellCb *cellCb
3055 * @param uint16_t ulIndex
3060 static Void rgSCHDrxTtiHdlUlHarqRTT
3066 static Void rgSCHDrxTtiHdlUlHarqRTT(cell, ulIndex)
3072 RgSchDrxDlHqProcCb *drxHq;
3073 RgSchDlHqProcCb *dlHq;
3074 RgSchDRXCellCb *drxCell;
3075 RgSchDrxUeCb *drxUe;
3078 CmLListCp ulInactvLst; /* list of UE's becoming DL-inactive */
3079 RgSchCmnCell *cellSch = RG_SCH_CMN_GET_CELL(cell);
3081 uint32_t ulInactvMask;
3084 drxCell = cell->drxCb;
3085 delInUlScan = drxCell->delInUlScan;
3087 cmLListInit(&ulInactvLst);
3089 /***********************************************************
3090 * Scanning harqRTTQ in UL
3091 ***********************************************************/
3094 Though these timers are related to downlink HARQ processing, they
3095 have an impact on uplink scheduling. The reason is that the UE,
3096 if active for downlink scheduling implies that it is reading
3097 PDCCHs i.e. we can still send uplink allocations to the UE. Hence
3098 every TTI Uplink too would look at the harqRTTQ and harqRetxQ.
3101 node = drxCell->drxQ[ulIndex].harqRTTQ.first;
3104 dlHq = (RgSchDlHqProcCb*)node->node;
3106 drxUe = RG_SCH_DRX_GET_UE(ue);
3108 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
3109 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
3111 if ( delInUlScan == TRUE )
3113 /* remove the harq proc from this queue--*/
3114 cmLListDelFrm (&(drxCell->drxQ[ulIndex].harqRTTQ),
3115 &(drxHq->harqRTTEnt));
3117 drxHq->rttIndx = DRX_INVALID;
3120 /* mark the ue as active for uplink--*/
3121 drxUe->drxUlInactvMask &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3122 drxUe->drxUlInactvMaskPerCell[cellIdx] &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3124 /* Update UE's inactive mask and if required move UE to ACTIVE state */
3125 RG_SCH_CMN_UL_UPDT_INACTV_MASK( cell, ue, RG_DRX_INACTIVE);
3128 /***********************************************************
3129 * Scanning harqRetxQ in UL
3130 ***********************************************************/
3131 node = drxCell->drxQ[ulIndex].harqRetxQ.first;
3134 dlHq = (RgSchDlHqProcCb*)node->node;
3136 drxUe = RG_SCH_DRX_GET_UE(ue);
3137 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
3138 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
3140 /*mark the ue as in-active for uplink*/
3142 drxUe->drxUlInactvMaskPerCell[cellIdx] |= (RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3144 ulInactvMask = RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId;
3146 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
3148 ulInactvMask &= drxUe->drxUlInactvMaskPerCell[cellIdx];
3151 drxUe->drxUlInactvMask |= ulInactvMask;
3153 if(!RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
3155 ue->ul.ulInactvMask |= (RG_DRX_INACTIVE);
3157 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
3158 ue->ulDrxInactvLnk.node = (PTR)ue;
3161 /* remove the harq proc from this queue*/
3162 if ( delInUlScan == TRUE)
3164 cmLListDelFrm (&(drxCell->drxQ[ulIndex].harqRetxQ),
3165 &(drxHq->harqRetxEnt));
3166 drxHq->reTxIndx = DRX_INVALID;
3171 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
3177 /**********************************************************************
3180 **********************************************************************/