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 .
36 /* header include files -- defines (.h) */
37 #include "common_def.h"
43 #include "rg_sch_inf.h"
44 #ifdef LTEMAC_PH3_HDFDD
45 #include "rg_sch_hdfdd.h"
46 #endif /*LTEMAC_PH3_HDFDD*/
48 #include "rg_sch_err.h"
49 #include "rg_sch_cmn.h"
50 #include "rl_interface.h"
51 #include "rl_common.h"
53 /* header/extern include files (.x) */
54 #include "tfu.x" /* TFU types */
55 #include "lrg.x" /* layer management typedefs for MAC */
56 #include "rgr.x" /* layer management typedefs for MAC */
57 #include "rgm.x" /* layer management typedefs for MAC */
58 #include "rg_sch_inf.x" /* typedefs for Scheduler */
59 #ifdef LTEMAC_PH3_HDFDD
60 #include "rg_sch_hdfdd.x"
61 #endif /*LTEMAC_PH3_HDFDD*/
63 #include "rg_sch.x" /* typedefs for Scheduler */
64 #include "rg_sch_cmn.x"
67 * @file rg_sch_drx.c This file gives the describes the design for DRX feature.
69 * DRX is Discontinuous Reception i.e. the UE in order to save some battery
70 * would not monitor (decode) PDCCHs at all times. Instead the UE is configured
71 * with a periodically occuring duration wherein it shall monitor PDCCHs. The UE
72 * can be called ACTIVE at this time, this time is a minimum of a configurable
73 * value - onDuration and a maximum of Infinity.
75 * ACTIVE time MIN (onDuration) MAX (infinity)
77 * A sample configuration is periodicity of 10 subframes (ms) and an offset
78 * value of 3. This can be represented as the diagram given below. The portion
79 * marked as ACTIVE is the onDuration and the UE monitors PDCCHs.
83 * <-ACTIVE-><---IN-ACTIVE------><-ACTIVE-><---IN-ACTIVE--
85 * |__|__|__|--------|__|__|__|__|__|__|__|--------|__|__|__|__|__|
86 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
91 /******************************************************************************
92 * Structure definitions for TDD *
93 ******************************************************************************/
95 /** @brief : No of DL subframes in a particular TDD configuration
97 * @details : Special subframes in TDD can carry PDCCH if configured
98 * for DwPTS. For normal CP with subframe configruation (0-8)
99 * & extended CP with subframe configuration (0-6), Special
100 * Subframes can carry PDCCH and are represented in row 0.
101 * Extended CP with subframe configuraton (7-8), which do
102 * not carry PDCCH are represented in row 1.
103 * rgSchDrxDlSfTddCfg[1][2] represent number of DL subframes
104 * in TDD config 2 where DwPTS can carry PDCCH and
105 * rgSchDrxDlSfTddCfg[0][2] represent number of DL subframes
106 * in TDD config 2 where no DwPTS exits.
109 static uint8_t rgSchDrxDlSfTddCfg[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG] =
115 /** @brief : No of DL subframes till next SFN from a particular subframe
117 * @details :For a given Special subframe config
118 * (refer rgSchDrxDlSfTddCfg for an explanation) and given
119 * TDD config, how many DL subframes till Next SFN from this
124 static uint8_t rgSchDrxDLSfTillNxtSFN[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG]
125 [RGSCH_NUM_SUB_FRAMES]=
128 {2,1,1,1,1,1,0,0,0,0},
129 {4,3,3,3,3,2,1,1,1,1},
130 {6,5,5,5,4,3,2,2,2,1},
131 {6,5,5,5,5,5,4,3,2,1},
132 {7,6,6,6,6,5,4,3,2,1},
133 {8,7,7,7,6,5,4,3,2,1},
134 {3,2,2,2,2,2,1,1,1,1}
138 {4,3,2,2,2,2,1,0,0,0},
139 {6,5,4,4,4,3,2,1,1,1},
140 {8,7,6,6,5,4,3,2,1,1},
141 {7,6,5,5,5,5,4,3,2,1},
142 {8,7,6,6,6,5,4,3,2,1},
143 {9,8,7,7,6,5,4,3,2,1},
144 {5,4,3,3,3,3,2,1,1,1}
146 }; /*rgSchDrxDLSfTillNxtSFN*/
149 /** @brief : Lookup table for DL subframe given the number of subframes
151 * @details :For a given Special subframe config
152 * (refer rgSchDrxDlSfTddCfg for an explanation) and given
153 * TDD config, the DL subframe index given the number of subframes
157 static uint8_t rgSchDrxDLSftoDLSfIdx[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG]
158 [RGSCH_NUM_SUB_FRAMES]=
178 };/* rgSchdrxDLSftoDLSfIdx*/
179 /* ccpu00134196-[Add]-DRX retx timer changes */
180 /* The k+4 th subframe in TDD at which HARQ RTT expires may be an Uplink SF.
181 In such case, the drx retx timer may start at the next pdcch sf instead
183 uint8_t rgSchDrxHarqRetxFirstPsf[RGSCH_MAX_TDD_CFG][RGSCH_NUM_SUB_FRAMES] = {
184 {0, 0, 4, 0, 6, 0, 0, 4, 0, 6},
185 {0, 0, 4, 6, 0, 0, 0, 4, 6, 0},
186 {0, 0, 4, 0, 0, 0, 0, 4, 0, 0},
187 {0, 0, 4, 4, 4, 0, 0, 0, 0, 0},
188 {0, 0, 4, 4, 0, 0, 0, 0, 0, 0},
189 {0, 0, 4, 0, 0, 0, 0, 0, 0, 0},
190 {0, 0, 4, 6, 5, 0, 0, 4, 7, 0},
194 /******************************************************************************
195 * Start of Function declarations *
196 ******************************************************************************/
197 static Void rgSCHDrxTtiHdlOnDurUl ARGS((
201 static Void rgSCHDrxTtiHdlOnDurDl ARGS((
205 static Void rgSCHDrxTtiHdlDlHarqRTT ARGS((
209 static Void rgSCHDrxTtiHdlUlHarqRTT ARGS((
213 static S16 rgSCHDrxTtiHdlOnDur ARGS((RgSchCellCb *cellCb, uint16_t dlIndex,
215 static S16 rgSCHDrxTtiHdlInActv ARGS((RgSchCellCb *cellCb, uint16_t dlIndex,
217 static S16 rgSCHDrxTtiHdlShortCycle ARGS((RgSchCellCb *cell, uint16_t dlIndex,
219 static S16 rgSCHDrxTtiHdlDlHarq ARGS((RgSchCellCb *cellCb, uint16_t dlIndex,
221 static S16 rgSCHDrxCpyUeCfg ARGS((RgSchDrxUeCb *drxCb,
222 RgrUeDrxCfg* ueDrxCfg));
224 static S16 rgSCHDrxGetNxtOnDur ARGS((RgSchCellCb* cell,RgSchDrxUeCb* drxCb,
225 CmLteTimingInfo* nxtOnDur,
228 static Void rgSCHDrxMvToNxtOnDurOcc ARGS((RgSchCellCb* cell,
233 static Void rgSCHDrxCalcNxtTmrExpry ARGS((RgSchCellCb *cell,
240 static S16 rgSCHDrxGetNxtTmrExpry ARGS((RgSchCellCb *cell,uint16_t curTime,
242 CmLteTimingInfo* tmrExpryIdx));
245 S16 rgSCHEmtcDrxCpyUeCfg
250 S16 rgSCHDrxTtiHdlUlHarq
256 Void rgSCHDrxUeUlHqReset
265 /** @brief This function handles the per TTI handling of the DRX module.
266 * Invoked by rgSCHTti @sa rgSCHTti.
268 * @details This function goes through the drxQ and marks the UE as ACTIVE or
269 * INACTIVE based on the timers and thier status.
271 * Function: rgSCHDrxTtiInd
274 * - Processing is divided into respective timer handling.
275 * - Calculate the DL and UL indices as follows
277 * dlIndex = (cell->crntTime.sfn * 10 + cell->crntTime.slot +
278 * RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
280 * ulIndex = (cell->crntTime.sfn * 10 + cell->crntTime.slot +
281 * RG_SCH_DRX_UL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
283 * - Call rgSCHDrxTtiHdlOnDur to handle onDurationTimer handling
284 * - Call rgSCHDrxTtiHdlInActv to handle drx-InactivityTimer handling
285 * - Call rgSCHDrxTtiHdlShortCycle to handle Short cycle timer.
286 * - Call rgSCHDrxTtiHdlDlHarq to handle HARQ RTT and drx-retransmission
288 * - Call rgSchDrxTtiHdlUlHarq to handle Uplink HARQ processing -
289 * related to ACTIVITY when a UE is expecting a grant for an uplink
291 * - Post this processing the ueCb->dlInactvMask's DRX Bit shall be set
292 * or reset to denote ACTIVITY or INACTIVITY respectively.
293 * - Post this processing the ueCb->ulInactvMask's DRX Bit shall be set
294 * or reset to denote ACTIVITY or INACTIVITY respectively.
295 * - Add the UE to the list of Active/inactive UEs.
297 * @param RgSchCellCb *cell
298 * @param [out] CmLListCp *dlInactvLst List to which the DL in-active UEs are
302 Void rgSCHDrxTtiInd(RgSchCellCb *cell)
307 dlIndex = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot +
308 RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
310 ulIndex = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot +
311 RG_SCH_DRX_UL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
314 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex);
315 /* checks the Ul-Retransmission timer */
319 rgSCHDrxTtiHdlUlHarq (cell, dlIndex, ulIndex);
322 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex);
324 /*Process Short cycle expiry before On duration timer so that long cycles
325 * On Duration can be processed if timer has expired*/
326 rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex);
327 rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex);
330 rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex);
331 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex);
332 /* checks the Ul-Retransmission timer */
336 rgSCHDrxTtiHdlUlHarq (cell, dlIndex, ulIndex);
339 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex);
340 rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex);
348 /** @brief This function is called to handle onDurationTimer per TTI processing.
351 * Invoked by - rgSCHDrxTtiInd
353 * Function: rgSCHDrxTtiHdlOnDur
357 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
359 * - For Downlink we shall look at an index that is
360 * n + RG_SCH_DRX_DL_DELTA.
363 * - For Uplink we shall look at an index that is
364 * n + RG_SCH_DRX_UL_DELTA as
365 * we are concerned with the PDCCH and not the actual PUSCH.
368 * @param RgSchCellCb *cellCb
369 * @param uint16_t dlIndex
370 * @param uint16_t ulIndex
371 * @return ROK/RFAILED
374 static S16 rgSCHDrxTtiHdlOnDur(RgSchCellCb *cell,uint16_t dlIndex,uint16_t ulIndex)
377 #if ( ERRCLASS & ERRCLS_INT_PAR )
378 if ( cell == (RgSchCellCb* )NULLP )
384 rgSCHDrxTtiHdlOnDurDl(cell,dlIndex);
386 rgSCHDrxTtiHdlOnDurUl(cell, ulIndex);
390 }/*rgSCHDrxTtiHdlOnDur*/
393 /** @brief This function handles the processing for drxInactityTimer per TTI
396 * Invoked by - rgSCHDrxTtiInd
398 * Function: rgSCHDrxTtiHdlInActv
402 * - For Downlink we shall look at an index that is
403 * n + RG_SCH_DRX_DL_DELTA of the drxQ.
405 * - MARK UE AS INACTIVE BASED ON DRX-INACTIVITY TIMER EXPIRY
408 * - For Uplink we shall look at an index that is
409 * n + RG_SCH_DRX_UL_DELTA as
410 * we are concerned with the PDCCH and not the actual PUSCH.
413 * @param RgSchCellCb *cellCb
414 * @param uint16_t dlIndex
415 * @param uint16_t ulIndex
416 * @return ROK/RFAILED
419 S16 rgSCHDrxTtiHdlInActv(RgSchCellCb *cell,uint16_t dlIndex,uint16_t ulIndex)
422 RgSchDRXCellCb *drxCell=NULLP;
424 RgSchDrxUeCb *drxUe=NULLP;
425 uint16_t shrtCycleExpIndx;
426 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
427 CmLListCp ulInactvLst; /* list of UE's becoming UL-inactive */
428 RgSchCmnCell *cellSch = NULLP;
429 Bool delInUlScan = FALSE;
431 #if ( ERRCLASS & ERRCLS_INT_PAR )
432 if ( cell == (RgSchCellCb* )NULLP)
439 drxCell = (cell->drxCb);
440 delInUlScan = drxCell->delInUlScan;
443 /***********************************************************
444 * Scanning inActvitiyQ in DL
445 ***********************************************************/
447 /* The DL loop will scan for UE's whose inactivity timer has
448 * expired. It will switch the cycle to short or long based
449 * on the cycle configured.
450 * Furhter,if !delInUlScan, then will remove the UE from the
454 node = drxCell->drxQ[dlIndex].inActvTmrQ.first;
456 /* Initialize DL inactive list */
457 cmLListInit(&dlInactvLst);
459 /* Initialize UL inactive list */
460 cmLListInit(&ulInactvLst);
464 ue = (RgSchUeCb*)node->node;
466 drxUe = RG_SCH_DRX_GET_UE(ue);
468 if ( delInUlScan == TRUE)
470 drxUe->drxInactDistance--;
473 if ( drxUe->drxInactDistance != DRX_TMR_EXPRD )
478 /* UE is inactive as inactivity timer has expired */
479 drxUe->drxDlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
482 /* update the ue mask only if no condition in drx
483 * is keeping ue active
485 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
487 /* set the UE has DRX inactive */
488 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
490 /* Add to DL inactive list */
491 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
492 ue->dlDrxInactvLnk.node = (PTR)ue;
495 /*Remove from the queue if !delInUlScan */
496 if( delInUlScan == FALSE )
498 cmLListDelFrm(&(drxCell->drxQ[dlIndex].inActvTmrQ),
499 &(drxUe->inActvTmrEnt));
501 drxUe->drxInactvIndx = DRX_INVALID;
503 }/* if (delInUlScan == FALSE) */
505 if (drxUe->isShortCycleCfgd)
507 /* add shorty cycle expirty */
508 drxUe->isLongCycle = FALSE;
510 shrtCycleExpIndx = (dlIndex + (drxUe->shortCycleTmrLen *
511 drxUe->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
513 drxUe->drxShortCycleDistance = (drxUe->shortCycleTmrLen *
514 drxUe->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
516 /*Remove the UE from existing index*/
517 if (drxUe->shortCycleIndx != DRX_INVALID)
519 cmLListDelFrm(&(drxCell->drxQ[drxUe->shortCycleIndx].shortCycleQ),
520 &(drxUe->shortCycleEnt));
523 cmLListAdd2Tail(&(drxCell->drxQ[shrtCycleExpIndx].shortCycleQ),
524 &(drxUe->shortCycleEnt));
526 drxUe->shortCycleEnt.node = (PTR)ue;
527 drxUe->shortCycleIndx = shrtCycleExpIndx;
529 /*Calculate onDuration again & move the
530 * ueCb to the next Onduration occurence
533 /*we maybe at any position in the RF timeline,
534 * need to calculate onDuration from the starting
537 rgSCHDrxMvToNxtOnDurOcc(cell,ue,RG_SCH_DRX_DL_DELTA,TRUE);
539 }/*isShortCycleCfgd */
542 /* use the long cycle */
543 drxUe->isLongCycle = TRUE;
549 /***********************************************************
550 * Scanning inActvitiyQ in UL
551 ***********************************************************/
553 /* The UL loop will scan for UE's whose inactivity timer has
554 * expired and mark the UE's UL inactive.
555 * Furhter,if delInUlScan, then will remove the UE from the
559 /* For Uplink we shall look at an index that is n + RG_SCH_DRX_UL_DELTA as
560 we are concerned with the PDCCH and not the actual PUSCH.*/
564 node = drxCell->drxQ[ulIndex].inActvTmrQ.first;
569 ue = (RgSchUeCb*)node->node;
571 drxUe = RG_SCH_DRX_GET_UE(ue);
573 if ( delInUlScan == FALSE)
575 drxUe->drxInactDistance--;
578 if ( drxUe->drxInactDistance != DRX_TMR_EXPRD )
583 /* Need to mark the UE as inactive due to expiry of
584 * DRX inactivity timer */
586 /* UE is inactive as inactivity timer has expired */
587 drxUe->drxUlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
589 /* update the ue mask only if no other condition in
590 * drx is keeping ue active */
592 if (!RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
594 /* set the inactivity bit */
595 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
597 /* Add to Ul inactive list */
598 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
599 ue->ulDrxInactvLnk.node = (PTR)ue;
602 if ( delInUlScan == TRUE)
604 /* remove from queue */
605 cmLListDelFrm(&(drxCell->drxQ[ulIndex].inActvTmrQ),
606 &(drxUe->inActvTmrEnt));
608 drxUe->drxInactvIndx = DRX_INVALID;
610 }/* if ( delInUlScan == TRUE) */
611 }/*while(node) for uplink */
614 /* Send the list to the scheduler to mark UE as inactive in UL*/
615 cellSch = RG_SCH_CMN_GET_CELL(cell);
616 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
618 /* Send the DL inactive list to the scheduler to mark UE as inactive */
619 cellSch = RG_SCH_CMN_GET_CELL(cell);
620 cellSch->apisDl->rgSCHDlInactvtUes(cell,&dlInactvLst);
623 }/*rgSCHDrxTtiHdlInActv*/
625 /** @brief This function handles the per TTI processing for DRX short cycle
629 * Invoked by - rgSCHDrxTtiInd
631 * Function: rgSCHDrxTtiHdlShortCycle
636 * in addition we have to mark the ues based on drx short cycle
640 * @param RgSchCellCb *cell
641 * @param uint16_t dlIndex
642 * @param uint16_t ulIndex
643 * @return ROK/RFAILED
646 S16 rgSCHDrxTtiHdlShortCycle(RgSchCellCb *cell,uint16_t dlIndex,uint16_t ulIndex)
649 RgSchDRXCellCb *drxCell=NULLP;
651 RgSchDrxUeCb *drxUe=NULLP;
653 #if ( ERRCLASS & ERRCLS_INT_PAR )
654 if ( cell == (RgSchCellCb* )NULLP )
663 drxCell = RG_SCH_DRX_GET_CELL(cell);
665 node = drxCell->drxQ[dlIndex].shortCycleQ.first;
669 ue = (RgSchUeCb*)node->node;
671 drxUe = RG_SCH_DRX_GET_UE(ue);
673 if ( --drxUe->drxShortCycleDistance != DRX_TMR_EXPRD)
678 /* mark the UE's current cycle to be long */
679 drxUe->isLongCycle = TRUE;
681 /* remove from the shortCycleQ */
683 cmLListDelFrm(&(drxCell->drxQ[dlIndex].shortCycleQ),
684 &(drxUe->shortCycleEnt));
685 drxUe->shortCycleIndx = DRX_INVALID;
687 /* Remove from onDuration queue inserted based on short cycle
688 * and calculate onDuration based on long cycle.*/
689 rgSCHDrxMvToNxtOnDurOcc(cell,ue,RG_SCH_DRX_DL_DELTA,TRUE);
693 }/*rgSCHDrxTtiHdlShortCycle*/
696 /** @brief This function handles the HARQ timer's processing per TTI.
699 * Invoked by - rgSCHDrxTtiInd
701 * Function: rgSCHDrxTtiHdlDlHarq
704 * - In addition per TTI DRX module must look at Downlink HARQ queues
705 * maintained to track HARQ RTT timer and drx-RetransmissionTimer.
706 * Every TTI at the scheduling index we shall check these queues and
707 * process accordingly.
710 * - Though these timers are related to downlink HARQ processing, they
711 * have an impact on uplink scheduling. The reason is that the UE,
712 * if active for downlink scheduling implies that it is reading
713 * PDCCHs i.e. we can still send uplink allocations to the UE. Hence
714 * every TTI Uplink too would look at the harqRTTQ and harqRetxQ.
718 * @param RgSchCellCb *cellCb
719 * @param uint16_t dlIndex
720 * @param uint16_t ulIndex
721 * @return ROK/RFAILED
724 static S16 rgSCHDrxTtiHdlDlHarq(RgSchCellCb *cell,uint16_t dlIndex,uint16_t ulIndex)
727 #if ( ERRCLASS & ERRCLS_INT_PAR)
728 if ( cell == (RgSchCellCb *)NULLP )
732 #endif /*ERRCLASS & ERRCLS_INT_PAR*/
735 rgSCHDrxTtiHdlDlHarqRTT(cell, dlIndex);
737 rgSCHDrxTtiHdlUlHarqRTT(cell, ulIndex);
742 /** @brief This function is called by the common scheduler as part of
743 * finalization of allocations in downlink.
748 * Function: rgSchDrxStrtInActvTmr
750 * This function is responsible to starting drx-InactivityTimer
755 * @param RgSchCellCb *cell
756 * @param CmLListCp *ueUlLst
757 * @param uint8_t direction
761 Void rgSCHDrxStrtInActvTmr(RgSchCellCb *cell,CmLListCp *ueLst,uint8_t direction)
766 RgSchDrxUeCb *ueDrxCb;
770 uint16_t inActvTmrExpIndx;
772 uint16_t curTimeInSf; /* current time in number of subframes */
777 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
778 CmLListCp ulInactvLst; /* list of UE's becoming UL-inactive */
779 RgSchCmnCell *cellSch = NULLP;
780 Bool delInUlScan = FALSE;
782 if ( direction == RG_SCH_DRX_UL)
785 curTimeInSf = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
786 (cell->crntTime.slot) +RG_SCH_DRX_UL_DELTA;
790 delta = RG_SCH_DRX_UL_DELTA;
796 curTimeInSf = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
797 (cell->crntTime.slot) + RG_SCH_DRX_DL_DELTA;
801 delta = RG_SCH_DRX_DL_DELTA;
806 /* Initialize DL inactive list */
807 cmLListInit(&dlInactvLst);
809 /* Initialize UL inactive list */
810 cmLListInit(&ulInactvLst);
812 delInUlScan = cell->drxCb->delInUlScan;
815 index1 = (curTimeInSf) % RG_SCH_MAX_DRXQ_SIZE;
822 ueCb = (RgSchUeCb *)node->node;
823 ueDrxCb = ueCb->drxCb;
825 /* Stop inactivity timer */
826 if ( ueDrxCb->drxInactvIndx != DRX_INVALID )
828 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->drxInactvIndx].inActvTmrQ),
829 &(ueDrxCb->inActvTmrEnt));
833 rgSCHDrxCalcNxtTmrExpry(cell,
836 ueDrxCb->inactvtyTmrLen,
837 &(ueDrxCb->drxInactDistance),
842 inActvTmrExpIndx = (index1 + ueDrxCb->inactvtyTmrLen)
843 % RG_SCH_MAX_DRXQ_SIZE;
845 ueDrxCb->drxInactDistance = ueDrxCb->inactvtyTmrLen
846 / RG_SCH_MAX_DRXQ_SIZE;
849 cmLListAdd2Tail(&(cell->drxCb->drxQ[inActvTmrExpIndx].inActvTmrQ),
850 &(ueDrxCb->inActvTmrEnt));
852 ueDrxCb->inActvTmrEnt.node = (PTR)ueCb;
854 ueDrxCb->drxInactvIndx = inActvTmrExpIndx;
856 /* Update DRX InActive both masks */
857 ueDrxCb->drxUlInactvMask &= ~RG_SCH_DRX_INACTVTMR_BITMASK;
858 ueDrxCb->drxDlInactvMask &= ~RG_SCH_DRX_INACTVTMR_BITMASK;
860 /* Update UE's Inactive masks */
861 ueCb->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
862 ueCb->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
864 if ( delInUlScan == TRUE)
866 if ( ueDrxCb->inactvtyTmrLen == RGR_DRX_PRD_1PSF)
868 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
869 ueDrxCb->drxDlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
871 /* if no other condition is keeping ue inactive,
874 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(ueDrxCb) )
876 ueCb->dl.dlInactvMask |= RG_DRX_INACTIVE;
878 /* Add to DL inactive list */
879 cmLListAdd2Tail(&dlInactvLst,&(ueCb->dlDrxInactvLnk));
880 ueCb->dlDrxInactvLnk.node = (PTR)ueCb;
882 }/*if ( ueDrxCb->inactvyTmrLen...*/
884 }/*delInUlScan==TRUE*/
887 if ( ueDrxCb->inactvtyTmrLen == RGR_DRX_PRD_1PSF )
889 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
890 ueDrxCb->drxUlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
891 /* if no other condition is keeping ue inactive,
894 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(ueDrxCb) )
896 ueCb->ul.ulInactvMask |= RG_DRX_INACTIVE;
898 if ( !RG_SCH_CMN_UL_IS_UE_ACTIVE(ueCb))
900 /* Add to UL inactive list */
901 cmLListAdd2Tail(&ulInactvLst,&(ueCb->ulDrxInactvLnk));
902 ueCb->ulDrxInactvLnk.node = (PTR)ueCb;
904 }/*if ( !RG_SCH_DRX....)*/
905 }/*if (ueDrxCb->inactv...*/
908 /* move the link list forward */
912 cmLListDelFrm(ueLst, delNode);
913 delNode->node = NULLP;
917 /* Send the list to the scheduler to mark UE as inactive in UL*/
918 cellSch = RG_SCH_CMN_GET_CELL(cell);
919 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
921 /* Send the DL inactive list to the scheduler to mark UE as inactive */
922 cellSch = RG_SCH_CMN_GET_CELL(cell);
923 cellSch->apisDl->rgSCHDlInactvtUes(cell,&dlInactvLst);
926 }/*rgSCHDrxStrtInActvTmr*/
928 /** @brief This function is called by the downlink HARQ module on receiving a
929 * negative feedback from the UE for a PDSCH transmission.
932 * Invoked by - rgSCHDhmHqTrnsFail
934 * Function: rgSCHDrxStartHarqRTTTmr
939 * @param RgSchCellCb *cell
940 * @param RgSchDlHqProcCb *dlHq
941 * @param uint8_t tbCnt
944 Void rgSCHDrxStartHarqRTTTmr(RgSchCellCb *cell,RgSchDlHqProcCb *hqP,uint8_t tbCnt)
946 RgSchDRXCellCb *drxCell =NULLP;
947 RgSchDrxDlHqProcCb *drxHq =NULLP;
948 uint16_t harqRTTExpIndx;
951 uint8_t firstDlTxOcassion;
952 uint8_t drxRetxTmrStartSf;
955 drxCell = RG_SCH_DRX_GET_CELL(cell);
956 drxHq = RG_SCH_DRX_GET_DL_HQ(hqP);
959 /* ccpu00134196-[Add]-DRX retx timer changes */
960 firstDlTxOcassion = rgSchDrxHarqRetxFirstPsf[cell->ulDlCfgIdx]
961 [hqP->tbInfo[tbCnt].fdbkTime.subframe];
963 harqRTTExpIndx = ((hqP->tbInfo[tbCnt].fdbkTime.sfn * 10) +
964 hqP->tbInfo[tbCnt].fdbkTime.subframe + firstDlTxOcassion)
965 % RG_SCH_MAX_DRXQ_SIZE;
967 fdbkDelta = RGSCH_CALC_SF_DIFF(cell->crntTime, hqP->tbInfo[tbCnt].fdbkTime);
970 /* For FDD HARQ RTT expiry index is 8 subframes from the time
971 * corresponding PDSCH was scheduled. We are adding 1 subframe
972 * so that UE is scheduled for retransmission in the next subframe*/
973 /* ccpu00134196-[Add]-DRX retx timer changes */
974 harqRTTExpIndx = ((hqP->tbInfo[tbCnt].timingInfo.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
975 hqP->tbInfo[tbCnt].timingInfo.slot + RG_SCH_MIN_HARQ_RTT)
976 % RG_SCH_MAX_DRXQ_SIZE;
978 fdbkDelta = RGSCH_CALC_SF_DIFF(cell->crntTime, hqP->tbInfo[tbCnt].timingInfo);
980 /* ccpu00134196-[Add]-DRX retx timer changes */
981 /* ensure that the insertion into the queue happens at an index
982 greater than the dl index, ie, do +1 */
983 /* Instead of depending on TTI details of current time and HARQ RTT Expire
984 * time, Handling this check with deltas, because with TTIs it is not possible
985 * to handle wrap-around condition*/
987 if(fdbkDelta + RG_SCH_DRX_DL_DELTA >= firstDlTxOcassion)
989 /* The retx timer length should be reduced.
990 This means based on the platforms delta between the DL HARQ
991 processing and DL scheduling, drx retx timer lengths of 1ms/2ms
992 may not be possible */
993 drxRetxTmrStartSf = (hqP->tbInfo[tbCnt].fdbkTime.subframe +
994 firstDlTxOcassion) % RGSCH_NUM_SUB_FRAMES;
996 /* We are here because the Retx Timer start is moved by atleast one
997 position. Hence the timer will be reduced by minimum one */
998 drxHq->retxTmrReduction = 1;
1000 /* Now check the consecutive subframes starting from the actual
1001 starting position of the retx tmr till the new position. Reduce the
1002 timer value only if the sf is a Pdcch sf */
1003 for(i = 1; i <= fdbkDelta + RG_SCH_DRX_DL_DELTA-firstDlTxOcassion+ 1; i++)
1005 if (rgSchTddUlDlSubfrmTbl[cell->ulDlCfgIdx]
1006 [(drxRetxTmrStartSf+i)%RGSCH_NUM_SUB_FRAMES]
1007 != RG_SCH_TDD_UL_SUBFRAME)
1009 drxHq->retxTmrReduction++;
1013 if(fdbkDelta + RG_SCH_DRX_DL_DELTA >= RG_SCH_MIN_HARQ_RTT)
1015 drxHq->retxTmrReduction =
1016 fdbkDelta + RG_SCH_DRX_DL_DELTA - RG_SCH_MIN_HARQ_RTT+ 1;
1019 harqRTTExpIndx = (harqRTTExpIndx + drxHq->retxTmrReduction) %
1020 RG_SCH_MAX_DRXQ_SIZE;
1024 drxHq->retxTmrReduction = 0;
1026 cmLListAdd2Tail (&(drxCell->drxQ[harqRTTExpIndx].harqRTTQ),
1027 &(drxHq->harqRTTEnt));
1029 drxHq->harqRTTEnt.node = (PTR)hqP;
1030 drxHq->rttIndx = harqRTTExpIndx;
1034 }/*rgSCHDrxStartHarqRTTTmr*/
1037 /** @brief This function is called by the Configuration module to give a
1038 * trigger to DRX module for UE configuration.
1042 * Function: rgSCHDrxUeCfg
1045 * - Copy configuration information into drxUe structure.
1046 * - Calculate the first occurance of onDuration based on values
1047 * provided in the configuration structure.
1048 * - Append the UE to the onDurationQ at that index.
1049 * - The UE must be appened to the list based on the timing calculated
1050 * above (nxtSfn, nxtSubframe).
1052 * @param RgSchCellCb *cell Cell control block.
1053 * @param RgSchUeCb *ue UE control block.
1054 * @param RgrUeCfg *ueCfg RGR UE configuration information.
1059 S16 rgSCHDrxUeCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeCfg *ueCfg)
1062 RgSchDrxUeCb *ueDrxCb;
1063 CmLteTimingInfo nxtOnDur;
1065 uint16_t nxtOnDurTime;
1070 #if ( ERRCLASS & ERRCLS_INT_PAR )
1071 if ( cell == (RgSchCellCb* )NULLP)
1076 if ((ue == (RgSchUeCb* )NULLP)
1078 (ueCfg == (RgrUeCfg* )NULLP))
1080 DU_LOG("\nERROR --> SCH : rgSCHDrxUeCfg():"
1081 "Invalid params.cell or ue or ueCfg is NULL ");
1087 /* allocate and initialize drxCb */
1088 ret = rgSCHUtlAllocSBuf(cell->instIdx, (Data**)&ue->drxCb,
1089 (sizeof(RgSchDrxUeCb)));
1093 DU_LOG("\nERROR --> SCH : Memory allocation FAILED for DRX UECB CRBTI:%d",ue->ueId);
1097 ueDrxCb = ue->drxCb;
1099 /* initialize the masks */
1100 ueDrxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1101 ueDrxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1102 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
1103 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
1105 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1107 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1108 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1111 /* Copy the configuration values into the UE's DRX CB. */
1112 rgSCHDrxCpyUeCfg (ueDrxCb, &ueCfg->ueDrxCfg);
1116 rgSCHEmtcDrxCpyUeCfg(ue ,&ueCfg->ueDrxCfg);
1120 /* set all indexes to default values */
1121 ueDrxCb->onDurIndx = DRX_INVALID;
1122 ueDrxCb->onDurExpIndx = DRX_INVALID;
1123 ueDrxCb->drxInactvIndx = DRX_INVALID;
1124 ueDrxCb->shortCycleIndx = DRX_INVALID;
1126 /* set all distances to timer expiry */
1127 ueDrxCb->onDurExpDistance = DRX_TMR_EXPRD;
1128 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
1129 ueDrxCb->drxShortCycleDistance = DRX_TMR_EXPRD;
1130 ueDrxCb->distance = DRX_TMR_EXPRD;
1132 /* Mark the UE in long/short cycle initially as per configuration*/
1133 if(FALSE == ueDrxCb->isShortCycleCfgd)
1135 ueDrxCb->isLongCycle = TRUE;
1139 ueDrxCb->isLongCycle = FALSE;
1142 /* Calculate the next occurance from this point */
1143 rgSCHDrxGetNxtOnDur (cell, ueDrxCb, &nxtOnDur,RG_SCH_NO_DELTA);
1146 nxtOnDurTime = ((nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur.slot);
1147 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1148 cell->crntTime.slot);
1150 onDurIndx = nxtOnDurTime % RG_SCH_MAX_DRXQ_SIZE;
1152 ueDrxCb->distance = (nxtOnDurTime - curTime) / RG_SCH_MAX_DRXQ_SIZE;
1153 if (ueDrxCb->distance < 0)
1155 DU_LOG("\nERROR --> SCH : DRXUE. Invalid "
1156 "value for distance, %d CRNTI:%d", ueDrxCb->distance,ue->ueId);
1158 //DU_LOG("\nDEBUG --> SCH : The onduartion index is: %d\n",(int)onDurIndx);
1159 cmLListAdd2Tail(&(cell->drxCb->drxQ[onDurIndx].onDurationQ),
1160 &(ueDrxCb->onDurationEnt));
1162 ueDrxCb->onDurationEnt.node = (PTR)ue;
1163 ueDrxCb->onDurIndx = onDurIndx;
1165 /* Starting Short Cycle Timer */
1166 if(TRUE == ueDrxCb->isShortCycleCfgd)
1168 ueDrxCb->drxShortCycleDistance = (ueDrxCb->shortCycleTmrLen *
1169 ueDrxCb->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
1170 ueDrxCb->shortCycleIndx = (curTime + (ueDrxCb->shortCycleTmrLen *
1171 ueDrxCb->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
1172 cmLListAdd2Tail(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1173 &(ueDrxCb->shortCycleEnt));
1174 ueDrxCb->shortCycleEnt.node = (PTR)ue;
1178 } /* end of rgSCHDrxUeCfg */
1180 /** @brief This function gets the next occurance of onDurationTimer from the
1183 * @details rgSCHDrxGetNxtOnDur
1185 * Function: rgSCHDrxGetNxtOnDur
1187 * Processing steps: -
1188 * Calculation of first occurance of onDuration is to be done as
1190 * Assume DRX configuration came at subframe (x, y) the periodicity is
1191 * offset = (perd, offset).
1192 * The (sfn, subframe) satisfying the following condition is the first
1193 * occurance from this point.
1195 * (sfn * 10 + subframe) mod perd = offset
1200 * @param RgSchCellCb *cell
1201 * @param RgSchDrxUeCb *drxCb
1202 * @param CmLteTimingInfo *nxtOnDur
1203 * @param uint8_t delta
1204 * @return ROK/RFAILED
1206 static S16 rgSCHDrxGetNxtOnDur(RgSchCellCb *cell,RgSchDrxUeCb *drxCb,CmLteTimingInfo *nxtOnDur,uint8_t delta)
1211 uint32_t numOfCycles;
1215 #if ( ERRCLASS & ERRCLS_INT_PAR )
1216 if ( cell == (RgSchCellCb* )NULLP )
1221 if( (drxCb == (RgSchDrxUeCb* )NULLP)
1223 (nxtOnDur == (CmLteTimingInfo* )NULLP)
1226 DU_LOG("\nERROR --> SCH : rgSCHDrxGetNxOnDur():Invalid params."
1227 "cell/drxCb/nxtOnDur is NULL");
1233 if (TRUE == drxCb->isLongCycle)
1235 cycleLen = drxCb->longDrxCycle;
1239 cycleLen = drxCb->shortDrxCycle;
1242 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) + cell->crntTime.slot);
1244 curTime += delta; /*TODO: see if we need to take care of wrap arounds */
1246 if ( curTime <= drxCb->drxStartOffset )
1248 /* offset is the nextOnDur */
1249 nxtOnDur->sfn = drxCb->drxStartOffset / RGSCH_NUM_SUB_FRAMES_5G;
1250 nxtOnDur->slot = (uint8_t)(drxCb->drxStartOffset % RGSCH_NUM_SUB_FRAMES_5G);
1251 nxtDist = ((nxtOnDur->sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur->slot);
1255 curDist = curTime - drxCb->drxStartOffset;
1257 numOfCycles = curDist / cycleLen;
1259 if (0 == (curDist % cycleLen))
1261 /* Perfect match pick up the current time */
1262 /*nxtOnDur should be set to equal to currentTime + DELTA */
1263 nxtOnDur->sfn = (uint16_t)curTime / RGSCH_NUM_SUB_FRAMES_5G;
1264 nxtOnDur->slot = (uint16_t)curTime % RGSCH_NUM_SUB_FRAMES_5G;
1265 nxtDist = ((nxtOnDur->sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur->slot);
1270 nxtDist = drxCb->drxStartOffset + (numOfCycles + 1) *
1272 nxtOnDur->sfn = (uint16_t)nxtDist / RGSCH_NUM_SUB_FRAMES_5G;
1273 nxtOnDur->slot = (uint16_t)nxtDist % RGSCH_NUM_SUB_FRAMES_5G;
1278 /*If next On Duration is less than DL DELTA ahead, we will miss it and
1279 * hence need to move to the On-Duration after that.*/
1280 if((nxtDist - (curTime - delta)) <= RG_SCH_DRX_MAX_DELTA)
1282 nxtDist = nxtDist + cycleLen;
1283 nxtOnDur->sfn = (uint16_t)nxtDist / RGSCH_NUM_SUB_FRAMES_5G;
1284 nxtOnDur->slot = (uint16_t)nxtDist % RGSCH_NUM_SUB_FRAMES_5G;
1287 } /* end of rgSCHDrxGetNxtOnDur */
1289 /** @brief This function is a utility function to copy the UE configuration from
1290 * the RGR structure to the UE control block.
1293 * -Invoked by rgSCHDrxUeCfg
1295 * Function: rgSCHDrxCpyUeCfg
1298 * - Copies configuration values
1300 * @param RgSchDrxUeCb *ueCb
1301 * @param RgrUeDrxCfg *drxCfg
1302 * @return ROK/RFAILED
1304 static S16 rgSCHDrxCpyUeCfg(RgSchDrxUeCb *ueCb,RgrUeDrxCfg *drxCfg)
1307 #if ( ERRCLASS & ERRCLS_INT_PAR )
1308 if ( (ueCb == (RgSchDrxUeCb* )NULLP )
1310 (drxCfg == (RgrUeDrxCfg* )NULLP)
1318 /* Copy all values to UE control block */
1320 ueCb->cqiMask = drxCfg->cqiMask;
1321 #endif /*LTEMAC_R9*/
1322 ueCb->onDurTmrLen = drxCfg->drxOnDurTmr;
1323 ueCb->inactvtyTmrLen = drxCfg->drxInactvTmr;
1324 ueCb->drxRetransTmrLen = drxCfg->drxRetxTmr;
1325 ueCb->longDrxCycle = drxCfg->drxLongCycleOffst.longDrxCycle;
1326 ueCb->drxStartOffset = drxCfg->drxLongCycleOffst.drxStartOffst;
1327 ueCb->isShortCycleCfgd = drxCfg->drxShortDrx.pres;
1328 ueCb->shortDrxCycle = drxCfg->drxShortDrx.shortDrxCycle;
1329 ueCb->shortCycleTmrLen = drxCfg->drxShortDrx.drxShortCycleTmr;
1332 } /* end of rgSCHDrxCpyUeCfg */
1335 /** @brief This function is called by the configuration module when a UE is
1336 * reconfigured for DRX parameters.
1339 * Invoked By - rgSCHCfgRgrUeCfg
1341 * Function: rgSCHDrxUeReCfg
1342 * As per MAC specifications the new values of timers shall be applied only once
1343 * they are restarted, hence no processing is required for modified timer values.
1346 * - if offset and/or drxCycleLenght changes then recalculate the next
1348 * - remove the UE from current index
1349 * - add the UE to the new index.
1350 * - if short cycle is enabled
1351 * - set isShortCycleCfgd = TRUE
1353 * @param RgSchCellCb *cell
1354 * @param RgSchUeCb *ue
1355 * @param RgrUeRecfg *ueReCfg
1356 * @return ROK/RFAILED
1358 S16 rgSCHDrxUeReCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeRecfg *ueReCfg)
1361 RgSchCmnCell *cellSch = NULLP;
1362 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
1364 Inst instIdx = cell->instIdx;
1365 RgSchDrxUeCb *ueDrxCb;
1366 CmLteTimingInfo nxtOnDur;
1367 uint16_t nxtOnDurTime;
1370 uint16_t shrtCycleExpIndx;
1371 uint16_t onDurExpTime;
1377 /* drx was disabled but now enabled for this ue */
1378 if ( (ue->isDrxEnabled == FALSE)
1380 (ueReCfg->ueDrxRecfg.isDrxEnabled == TRUE)
1383 /* allocated and initialize drxCb */
1384 ret = rgSCHUtlAllocSBuf(instIdx, (Data**)&ue->drxCb,
1385 (sizeof(RgSchDrxUeCb)));
1389 DU_LOG("\nERROR --> SCH : rgSCHdrxUeReCfg():""Memory allocation FAILED for DRX UE Cb CRNTI:%d",
1394 ue->isDrxEnabled = TRUE; /* sachin */
1395 /* initialize the masks */
1396 ue->drxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1397 ue->drxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1398 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
1399 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
1401 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1403 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1404 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1407 /* set all indexes to default values */
1408 ue->drxCb->onDurIndx = DRX_INVALID;
1409 ue->drxCb->onDurExpIndx = DRX_INVALID;
1410 ue->drxCb->drxInactvIndx = DRX_INVALID;
1411 ue->drxCb->shortCycleIndx = DRX_INVALID;
1413 /* set all distances to timer expiry */
1414 ue->drxCb->onDurExpDistance = DRX_TMR_EXPRD;
1415 ue->drxCb->drxInactDistance = DRX_TMR_EXPRD;
1416 ue->drxCb->drxShortCycleDistance = DRX_TMR_EXPRD;
1417 ue->drxCb->distance = DRX_TMR_EXPRD;
1420 if( ue->drxCb == NULLP )
1424 ueDrxCb = ue->drxCb;
1426 /*drx was enabled but now disabled for this UE */
1427 if ( (ue->isDrxEnabled == TRUE )
1429 (ueReCfg->ueDrxRecfg.isDrxEnabled == FALSE)
1432 /* remove UE from all DRX Queues */
1433 (Void)rgSCHDrxUeDel(cell,ue);
1436 /* ccpu00117052 - MOD - Passing double pointer
1437 for proper NULLP assignment*/
1438 rgSCHUtlFreeSBuf(instIdx,(Data **)(&((ue->drxCb))),
1439 sizeof(RgSchDrxUeCb));
1441 /* Resetting the DRX Bit set in Inactv Mask */
1442 ue->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
1443 ue->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
1445 ue->isDrxEnabled = FALSE;
1447 }/*isDrxEnabled == FALSE */
1450 /* If Application is updating DRX params */
1451 if (ueReCfg->ueRecfgTypes & RGR_UE_DRX_RECFG )
1453 rgSCHDrxCpyUeCfg (ueDrxCb, &ueReCfg->ueDrxRecfg);
1457 rgSCHEmtcDrxCpyUeCfg(ue, &ueReCfg->ueDrxRecfg);
1463 /* Removing the UE from existing index of shortcycle, if any*/
1464 if(ueDrxCb->shortCycleIndx != DRX_INVALID)
1466 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1467 &(ueDrxCb->shortCycleEnt));
1469 ueDrxCb->shortCycleEnt.node = (PTR) NULLP;
1470 ueDrxCb->shortCycleIndx = DRX_INVALID;
1473 /* Mark for intiating long/short cycle as per received config */
1474 if(FALSE == ue->drxCb->isShortCycleCfgd)
1476 ue->drxCb->isLongCycle = TRUE;
1480 ue->drxCb->isLongCycle = FALSE;
1483 /* Calculate the next occurance from this point */
1484 rgSCHDrxGetNxtOnDur (cell, ueDrxCb, &nxtOnDur,RG_SCH_NO_DELTA);
1486 /* remove the UE from the current onDuration Queue */
1487 if ( ueDrxCb->onDurIndx != DRX_INVALID )
1489 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurIndx].onDurationQ),
1490 &(ueDrxCb->onDurationEnt));
1494 nxtOnDurTime = (nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur.slot;
1495 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1496 cell->crntTime.slot);
1498 /* If Onduration timer of old configuration is already running then waiting till it expires */
1499 if((ueDrxCb->onDurExpIndx != DRX_INVALID) && (ueDrxCb->onDurExpDistance != DRX_TMR_EXPRD))
1501 curIndx = (curTime + RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
1502 DU_LOG("\nDEBUG --> SCH : OLD ONDUR RUNNING-EXPIRES at %d curIdx-%d nxtOnDurTime-%d",
1503 ueDrxCb->onDurExpIndx,
1507 /* Manipulating the time when old onDuration timer can expire */
1508 if(curIndx >= ueDrxCb->onDurExpIndx)
1510 onDurExpTime = curTime + ((ueDrxCb->onDurExpDistance+1) * RG_SCH_MAX_DRXQ_SIZE)+\
1511 (ueDrxCb->onDurExpIndx - curIndx + RG_SCH_DRX_DL_DELTA);
1515 onDurExpTime = curTime + (ueDrxCb->onDurExpDistance * RG_SCH_MAX_DRXQ_SIZE)+\
1516 (ueDrxCb->onDurExpIndx - curIndx + RG_SCH_DRX_DL_DELTA);
1519 if(nxtOnDurTime <= onDurExpTime)
1521 if(ueDrxCb->isLongCycle)
1523 cycleLen = ueDrxCb->longDrxCycle;
1527 cycleLen = ueDrxCb->shortDrxCycle;
1529 /* Moving to the possible occassion of onduration after current onduration expiry:
1530 * If both are aligning then going for next cycle */
1531 nxtOnDurTime += ((onDurExpTime - nxtOnDurTime)/cycleLen + 1 ) *cycleLen ;
1534 /* Add the UE to the index which corresponds to the next onduration start*/
1535 onDurIndx = nxtOnDurTime % RG_SCH_MAX_DRXQ_SIZE;
1537 ueDrxCb->distance = (nxtOnDurTime - curTime) / RG_SCH_MAX_DRXQ_SIZE;
1538 if (ueDrxCb->distance < 0)
1540 DU_LOG("\nERROR --> SCH : DRXUE. Invalid "
1541 "value for distance, %d CRNTI:%d", ueDrxCb->distance,ue->ueId);
1544 cmLListAdd2Tail(&(cell->drxCb->drxQ[onDurIndx].onDurationQ),
1545 &(ueDrxCb->onDurationEnt));
1547 ueDrxCb->onDurationEnt.node = (PTR)ue;
1548 ueDrxCb->onDurIndx = onDurIndx;
1551 cmLListInit(&dlInactvLst);
1552 /* Add to DL inactive list */
1553 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
1554 ue->dlDrxInactvLnk.node = (PTR)ue;
1555 /* Send the list to the scheduler to mark UE as inactive */
1556 cellSch = RG_SCH_CMN_GET_CELL(cell);
1557 cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
1560 /* Starting short cycle timer as per the existence of old onDuration timer */
1561 if(TRUE == ueDrxCb->isShortCycleCfgd)
1563 /* Expiring short DRX cycle Tmr once the number of short DRX cycles done */
1564 ueDrxCb->drxShortCycleDistance = (nxtOnDurTime + ueDrxCb->onDurTmrLen + (ueDrxCb->shortCycleTmrLen -1 )*
1565 ueDrxCb->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
1566 shrtCycleExpIndx = (nxtOnDurTime + ueDrxCb->onDurTmrLen + ((ueDrxCb->shortCycleTmrLen -1)*
1567 ueDrxCb->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
1568 cmLListAdd2Tail(&(cell->drxCb->drxQ[shrtCycleExpIndx].shortCycleQ),
1569 &(ueDrxCb->shortCycleEnt));
1570 ueDrxCb->shortCycleEnt.node = (PTR)ue;
1571 ueDrxCb->shortCycleIndx = shrtCycleExpIndx;
1577 } /* end of rgSCHDrxUeReCfg */
1580 /** @brief This function Loop through the list of HARQ processes for this
1581 * UE and delete from the harqRTTQ and harqRetxQ
1583 * Function: rgSCHDrxUeHqReset
1584 * Invoked by rgSCHDrxUeDel
1587 Loop through the list of HARQ processes for this UE and delete from
1588 * the harqRTTQ and harqRetxQ.
1590 * @param RgSchCellCb *cell
1591 * @return ROK/RFAILED
1593 Void rgSCHDrxUeHqReset(RgSchCellCb *cell,RgSchUeCb *ue,RgSchDlHqEnt *hqE,uint8_t cellIdx)
1595 RgSchDlHqProcCb *hqP;
1596 RgSchDrxDlHqProcCb *drxHq =NULLP;
1599 for(i=0; i < hqE->numHqPrcs; i++)
1601 hqP = &hqE->procs[i];
1602 drxHq = RG_SCH_DRX_GET_DL_HQ(hqP);
1604 if(drxHq->rttIndx != DRX_INVALID)
1606 cmLListDelFrm (&(cell->drxCb->drxQ[drxHq->rttIndx].harqRTTQ),
1607 &(drxHq->harqRTTEnt));
1609 drxHq->rttIndx = DRX_INVALID;
1612 if(drxHq->reTxIndx != DRX_INVALID)
1614 cmLListDelFrm (&(cell->drxCb->drxQ[drxHq->reTxIndx].harqRetxQ),
1615 &(drxHq->harqRetxEnt));
1617 drxHq->reTxIndx = DRX_INVALID;
1621 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1622 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1625 /** @brief This function Deletes DRX specific context for a UE.
1627 * @details This funciton is invoked by the Configuration module on RGR UE Deletion.
1628 * This function removes the UE's context from all of the DRX Queues.
1629 * In addition it deletes context of UE's HARQ Processes present in the harqRTTQ
1633 * Function: rgSCHDrxUeDel
1634 * Invoked by rgSCHCfgRgrUeDel
1637 * - Remove the UE from the following queues
1638 * - onDurationQ - using onDurIndx
1639 * - onDurationExpQ - using onDurExpIndx
1640 * - inActvTmrQ - using drxInactvIndx
1641 * - shortCycleQ - using shortCycleIndx
1642 * - Loop through the list of HARQ processes for this UE and delete from
1643 * the harqRTTQ and harqRetxQ.
1645 * @param RgSchCellCb *cell
1646 * @param RgSchUeCb *ue
1647 * @return ROK/RFAILED
1649 S16 rgSCHDrxUeDel(RgSchCellCb *cell,RgSchUeCb *ue)
1651 RgSchDrxUeCb *ueDrxCb;
1652 RgSchDlHqEnt *hqE = NULLP;
1654 RgSchUeCellInfo *cellInfo = NULLP;
1656 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
1660 /* ccpu00129899: Moved the drx-enabled check to the caller */
1661 ueDrxCb = ue->drxCb;
1663 /* Remove UE from all queues */
1664 if ( ueDrxCb->onDurIndx != DRX_INVALID )
1666 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurIndx].onDurationQ),
1667 &(ueDrxCb->onDurationEnt));
1669 ueDrxCb->onDurIndx = DRX_INVALID;
1672 if ( ueDrxCb->onDurExpIndx != DRX_INVALID )
1674 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurExpIndx].onDurationExpQ),
1675 &(ueDrxCb->onDurationExpEnt));
1677 ueDrxCb->onDurExpIndx = DRX_INVALID;
1680 if ( ueDrxCb->drxInactvIndx != DRX_INVALID )
1682 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->drxInactvIndx].inActvTmrQ),
1683 &(ueDrxCb->inActvTmrEnt));
1685 ueDrxCb->drxInactvIndx = DRX_INVALID;
1688 if ( ueDrxCb->shortCycleIndx != DRX_INVALID )
1690 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1691 &(ueDrxCb->shortCycleEnt));
1693 ueDrxCb->shortCycleIndx = DRX_INVALID;
1696 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1698 cellInfo = ue->cellInfo[cellIdx];
1702 hqE = cellInfo->hqEnt;
1703 rgSCHDrxUeHqReset(cell, ue, hqE, cellIdx);
1709 rgSCHDrxUeUlHqReset(cell, ue, &(ueUl->hqEnt));
1712 /* Resetting the DRX Bit set in Inactv Mask */
1713 ue->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
1714 ue->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
1715 ueDrxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1716 ueDrxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1721 /** @brief This function is called at the time of RGR cell configuration.
1724 * Invoked by - rgSCHCfgRgrCellCfg
1726 * Function: rgSCHDrxCellCfg
1729 * - Initializes the following drxQ (memset would do).
1732 * @param RgSchCellCb *cell
1733 * @param RgrCellCfg *cellCfg
1734 * @return ROK/RFAILED
1736 S16 rgSCHDrxCellCfg(RgSchCellCb *cell,RgrCellCfg *cellCfg)
1740 Inst instIdx = cell->instIdx;
1742 #if ( ERRCLASS & ERRCLS_INT_PAR )
1743 /*KWORK_FIX :Removed check for cell being NULL*/
1744 if( (cellCfg == (RgrCellCfg* )NULLP))
1746 DU_LOG("\nERROR --> SCH : rgSCHDrxCellCfg():Invalid Params. cell/cellCfg is NULL");
1751 /* allocate and initialize drxCb */
1752 ret = rgSCHUtlAllocSBuf(instIdx, (Data**)&cell->drxCb,
1753 (sizeof(RgSchDRXCellCb)));
1757 DU_LOG("\nERROR --> SCH : rgSCHDrxCellCfg():"
1758 "Memory allocation FAILED for DRX cell Cb");
1762 /* delInUlScan determines which index scans the queue last.
1763 * We look at onDurationQ both from ulIndex & dlIndex pov.
1764 * Consider, onDuration starts at index 5, and current index is 2,
1765 * while dlIndex is 2 & ulIndex is 3 i.e dl is looking 2 SF ahead
1766 * and ul is looking 3 SF ahead. In this case, dl will scan the queue
1767 * last and therefore DL will delete ueCb from onDuration q.
1768 * The reverse is true for the other case.*/
1770 if ( RG_SCH_DRX_UL_DELTA > RG_SCH_DRX_DL_DELTA )
1772 cell->drxCb->delInUlScan = FALSE;
1776 cell->drxCb->delInUlScan = TRUE;
1780 } /* end of rgSchDrxCellCfg */
1784 /** @brief This function to delete DRX specific context in the cell control
1788 * Invoked by - rgSCHCfgRgrCellDel
1790 * Function: rgSCHDrxCellDel
1793 * - De-Inits RgSchDRXCellCb (Nothing to be done)
1794 * - Assumption: The API is invoked after deletion of UEs from the cell.
1796 * @param RgSchCellCb *cell
1799 Void rgSCHDrxCellDel(RgSchCellCb *cell)
1801 Inst instIdx = cell->instIdx;
1805 /* ccpu00117052 - MOD - Passing double pointer
1806 for proper NULLP assignment*/
1807 rgSCHUtlFreeSBuf(instIdx, (Data **)(&(cell->drxCb)),
1808 sizeof(RgSchDRXCellCb));
1811 } /* end of rgSchDrxCellDel */
1813 /** @brief This function is called when an SR is received from the UE. In this
1814 * case the UE should be marked as ACTIVE till we send a UL allocation to the
1818 * Invoked by - rgSCHCmnSrRcvd
1819 * Must be called after calling the specific scheduler.
1821 * Function: rgSCHDrxSrInd
1824 * - Mark the UE as ACTIVE
1825 * ueCb->drxUlInactvMask |= (DRX_SR_ACTIVE);
1826 * - Optionally call schedulers to add this UE to their scheduling
1828 * - Set drxUe->srRcvd = TRUE
1830 * Note : the specification state that the UE shall start be active
1831 * listening for UL grant, this implies we could potentially exploit
1832 * this to send DL transmissions as well. However we have currently
1833 * chosen not to do so.
1835 * @param RgSchCellCb *cell
1836 * @param RgSchUeCb *ue
1837 * @return ROK/RFAILED
1839 S16 rgSCHDrxSrInd(RgSchCellCb *cell,RgSchUeCb *ue)
1841 RgSchDrxUeCb *drxCb;
1843 #if ( ERRCLASS & ERRCLS_INT_PAR )
1844 if ( cell == (RgSchCellCb* )NULLP)
1849 if( (ue == (RgSchUeCb* )NULLP))
1851 DU_LOG("\nERROR --> SCH : rgSCHDrxSrInd():Invalid Params. cell/ue is NULL");
1855 /* KWork fix - shifted this down */
1858 drxCb = RG_SCH_DRX_GET_UE(ue);
1860 /* Mark the UE as active for UL only */
1861 drxCb->drxUlInactvMask &= ~RG_SCH_DRX_SR_BITMASK;
1862 drxCb->srRcvd = TRUE;
1863 /* Update UE's inactive mask and if required move UE to ACTIVE state */
1864 RG_SCH_CMN_UL_UPDT_INACTV_MASK( cell, ue, RG_DRX_INACTIVE);
1867 } /* rgSCHDrxSrInd */
1870 /** @brief This function handles ACTIVITY due to RACH using a dedicated preamble
1871 * (PDCCH order) OR Handover. A UE shall remain marked as active from the time
1872 * we successfully send out a RAR upto the time it receives a PDCCH indicating a
1876 * Invoked by - rgSCHCmnHdlHoPo
1878 * Function: rgSCHDrxDedRa
1881 * - MARK the UE as active
1882 * - set the raRcvd = TRUE for this UE.
1885 * ueCb->drxDlInactvMask |= (DRX_RA_ACTIVE);
1886 * ueCb->drxUlInactvMask |= (DRX_RA_ACTIVE);
1887 * ueCb->raRcvd = TRUE;
1890 * @param RgSchCellCb *cellCb
1891 * @param RgSchUeCb *ueCb
1894 Void rgSCHDrxDedRa(RgSchCellCb *cellCb, RgSchUeCb *ueCb)
1896 RgSchDrxUeCb *drxCb;
1898 drxCb = RG_SCH_DRX_GET_UE(ueCb);
1900 /* Mark the UE as active for UL & DL */
1901 drxCb->drxUlInactvMask &= ~RG_SCH_DRX_RA_BITMASK;
1902 /* Update UE's inactive mask and if required move UE to ACTIVE state */
1903 RG_SCH_CMN_UL_UPDT_INACTV_MASK(cellCb, ueCb, RG_DRX_INACTIVE);
1905 drxCb->drxDlInactvMask &= ~RG_SCH_DRX_RA_BITMASK;
1906 /* Update UE's inactive mask and if required move UE to ACTIVE state */
1907 RG_SCH_CMN_DL_UPDT_INACTV_MASK(cellCb, ueCb, RG_DRX_INACTIVE);
1909 drxCb->raRcvd = TRUE;
1912 } /* end of rgSCHDrxDedRa */
1915 /** @brief This function calculates the next onDuration Occurence
1916 * and removes & queue it again in onDurationQ
1921 * Function: rgSCHDrxMvToNxtOnDurOcc
1926 * @param RgSchCellCb *cell
1927 * @param RgSchUeCb *ueCb
1928 * @param uint16_t idx - if calcFrmOffst is TRUE,
1929 * idx is delta to be added
1930 * @param Bool calcFrmOffst
1933 static Void rgSCHDrxMvToNxtOnDurOcc(RgSchCellCb *cell,RgSchUeCb *ueCb,uint16_t idx,Bool calcFrmOffst)
1935 uint16_t nxtOnDurIndex;
1937 RgSchDrxUeCb *drxUe;
1938 RgSchDRXCellCb *drxCell;
1939 CmLteTimingInfo nxtOnDur; /* to be used when calcFrmOffset is set */
1940 uint16_t nxtOnDurInSf; /* next On Duration in no of subframes */
1942 drxCell = cell->drxCb;
1943 drxUe = ueCb->drxCb;
1946 if(calcFrmOffst == FALSE)
1948 if (drxUe->isLongCycle)
1950 nxtOnDurIndex = ((idx + drxUe->longDrxCycle)
1951 % RG_SCH_MAX_DRXQ_SIZE );
1952 drxUe->distance = drxUe->longDrxCycle/RG_SCH_MAX_DRXQ_SIZE;
1956 nxtOnDurIndex = ((idx + drxUe->shortDrxCycle)% RG_SCH_MAX_DRXQ_SIZE);
1958 drxUe->distance = drxUe->shortDrxCycle / RG_SCH_MAX_DRXQ_SIZE;
1963 rgSCHDrxGetNxtOnDur(cell,drxUe,&nxtOnDur,(uint8_t)idx);
1965 nxtOnDurInSf = ((nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1968 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1969 cell->crntTime.slot);
1971 nxtOnDurIndex = nxtOnDurInSf % RG_SCH_MAX_DRXQ_SIZE;
1972 drxUe->distance = (nxtOnDurInSf-curTime) / RG_SCH_MAX_DRXQ_SIZE;
1973 if (drxUe->distance < 0)
1975 DU_LOG("\nERROR --> SCH : DRXUE. Invalid "
1976 "value for distance, %d CRNTI:%d", drxUe->distance,ueCb->ueId);
1980 /* First remove from existing location */
1981 if ( drxUe->onDurIndx != DRX_INVALID )
1983 cmLListDelFrm(&(drxCell->drxQ[drxUe->onDurIndx].onDurationQ),
1984 &(drxUe->onDurationEnt));
1987 /* Add at new location */
1988 cmLListAdd2Tail(&(drxCell->drxQ[nxtOnDurIndex].onDurationQ),
1989 &(drxUe->onDurationEnt));
1991 drxUe->onDurationEnt.node = (PTR)ueCb;
1992 drxUe->onDurIndx = nxtOnDurIndex;
1995 }/*rgSCHDrxMvToNxtOnDurOcc*/
1998 /** @brief This function calculates the next SFN,subframe a given
1999 * timer is going to expire. Works for all TDD configurations.
2003 * Function: rgSCHDrxGetNxtTmrExpry
2004 * We need to count only PDCCH frames in a given TDD
2005 * configuration. This is true for onDuration, inActivity
2006 * & drx-retransmission timers.
2008 * Processing steps (assume timer starts at (12,2) and duration
2009 * is 23 DL subframes):
2010 * - based on TDD configuration, move to the next SFN and
2011 * count the number of DL subframes consumed. In our example,
2012 * moving to (12,9) will consume 6 DL subframes assuming TDD
2014 * - From this point on, determine how many exact Radio Frames
2015 * will be consumed for the remaining DL subframes. In our
2016 * example, remaining DL subframes are (23-6) are 17.
2017 * For config 2, the following holds true
2018 * 8 DLSF are in 1 RF
2019 * 1 DLSF in 1/8 DLSF
2020 * 17 DLSF in 17/8 i.e 2 RF + 1 subframe
2021 * In order to consume 17 DLSF, we need to move forward
2022 * 2 RFs + 1 subframe. Adding 2 RF's gives us (14,9)
2023 * - For the remaining subframe, we need to figure out the next
2024 * available DL subframe. For TDD_configuration, the first DL
2025 * subframe is at index 0. So, the timer will run till (15,0)
2026 * and will expire on (15,1)
2028 * @param RgSchUeCb *ue Ue control block.
2029 * @param uint16_t curTime current Time
2030 * @param uint32_t duration Timer duration
2031 * @param CmLteTimingInfo *tmrExpryIdx Timer expry (SFN,sf)
2032 * @return ROK/RFAILED
2034 static S16 rgSCHDrxGetNxtTmrExpry(RgSchCellCb *cell, uint16_t curTime, uint32_t duration,CmLteTimingInfo *tmrExpryIdx)
2036 uint32_t dlSfTillNxtSFN; /*!< DL subframes till next SFN */
2037 uint8_t tddCfgMode; /*!< tdd config mode */
2038 Bool isDwPtsCnted; /*!< is DwPts counted as PDCCH sf */
2039 CmLteTimingInfo crntTime; /*!< current SFN & sf */
2042 #if ( ERRCLASS & ERRCLS_INT_PAR )
2043 if ( (cell == (RgSchCellCb* )NULLP)
2045 (tmrExpryIdx == (CmLteTimingInfo* )NULLP)
2053 isDwPtsCnted = cell->isDwPtsCnted ;
2055 tddCfgMode = cell->ulDlCfgIdx;
2056 crntTime.sfn = curTime / RGSCH_NUM_SUB_FRAMES_5G;
2057 crntTime.slot = curTime % RGSCH_NUM_SUB_FRAMES_5G;
2061 /* First calculate the number of DL subframes till next SFN */
2063 dlSfTillNxtSFN = rgSchDrxDLSfTillNxtSFN[isDwPtsCnted][tddCfgMode]
2064 [(crntTime.slot % RGSCH_NUM_SUB_FRAMES)];
2067 if ( dlSfTillNxtSFN >= duration )
2069 /* the timer would expire on the same RF */
2070 uint32_t diff = dlSfTillNxtSFN - duration;
2072 tmrExpryIdx->sfn = crntTime.sfn;
2076 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2082 /* to know the DL sf index based on diff */
2083 arrayIdx = rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2085 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2088 }/* if ( dlSfTillNxtSFN >= duration...*/
2091 uint32_t remSf; /*!< remaining subframes */
2092 uint32_t numRf; /*!< num of complete radio frames */
2093 uint32_t numRemSfs; /*!< num of remaining subframes */
2095 remSf = duration - dlSfTillNxtSFN;
2097 /* move to (currSFN,9) having consued dlSfTillNxtSFN DL subframes */
2098 tmrExpryIdx->sfn = crntTime.sfn;
2099 tmrExpryIdx->subframe = (uint8_t)9;
2101 numRf = (1 * remSf)/rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2102 numRemSfs = (1 * remSf)%rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2104 tmrExpryIdx->sfn = tmrExpryIdx->sfn + numRf;
2106 /* we are now at (X,9) having consumed dlSfTillNxtSFN + numRf * num of DL
2107 * subframes in 1 RF */
2109 if ( numRemSfs == 0 )
2111 /* we are at subframe 9 i.e. the timer is going to expire using exact
2112 * radio frames. However, not all TDD_configurations have 9 as their
2113 * last DL subframe. We might have passed the last DL subfrme.
2114 * Therefore, move back */
2115 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2120 /* a reminder implies we have to move past this SFN as we are at the
2121 * last subframe on that SFN */
2123 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2126 }/*else if diff > duration */
2128 /* timer will expire 1 + tmrExpryIdx */
2130 if ( ( tmrExpryIdx->subframe + 1) == 10 )
2133 tmrExpryIdx->subframe = 0;
2137 tmrExpryIdx->subframe++;
2140 /* check to see if it sfn has crossed its max */
2141 if ( tmrExpryIdx->sfn > RG_SCH_CMN_MAX_SFN_NUM )
2143 tmrExpryIdx->sfn = tmrExpryIdx->sfn - (RG_SCH_CMN_MAX_SFN_NUM + 1);
2147 }/*rgSCHDrxGetNxtTmrExpry*/
2149 /** @brief This function calculates the next onDuration Occurence
2154 * Function: rgSCHDrxCalcNxtTmrExpry
2156 * Processing steps: a wrapper function to call
2157 * rgSCHDrxGetNxtTmrExpry
2159 * @param RgSchCellCb *cell
2160 * @param RgSchUeCb *ue
2161 * @param uint16_t delta
2162 * @param uint32_t tmrLen
2163 * @param uint16_t *distance
2165 * @return ROK/RFAILED
2167 static Void rgSCHDrxCalcNxtTmrExpry(RgSchCellCb *cell, RgSchUeCb *ue, uint16_t delta, uint32_t tmrLen, S16 *distance, uint16_t *idx)
2169 uint16_t curTimeInSf; /*current time in no of subframes*/
2170 CmLteTimingInfo tmrExpry;
2171 uint16_t tmrExpryInSf; /*timer expry in no of subframes*/
2173 curTimeInSf = cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G +
2174 cell->crntTime.slot;
2176 /* add delta to curTime */
2177 curTimeInSf += delta;
2179 rgSCHDrxGetNxtTmrExpry(ue->cell,curTimeInSf,tmrLen,&tmrExpry);
2181 /* convert timre Expry in terms of subframes */
2182 tmrExpryInSf = tmrExpry.sfn * RGSCH_NUM_SUB_FRAMES_5G +
2186 *idx = (tmrExpryInSf) % RG_SCH_MAX_DRXQ_SIZE;
2188 if ( distance != NULLP ) /* hqReTx don't use the concept of distance.
2189 They can send NULLP for distance.
2192 if ( tmrExpryInSf > curTimeInSf )
2194 *distance = (tmrExpryInSf - curTimeInSf) /
2195 RG_SCH_MAX_DRXQ_SIZE;
2199 /* in case the RF is at its max and wraps around */
2201 *distance = ((tmrExpryInSf + (RG_SCH_CMN_MAX_NUM_OF_SFN - 1))
2203 curTimeInSf) / RG_SCH_MAX_DRXQ_SIZE;
2207 DU_LOG("\nERROR --> SCH : DRXUE. Invalid "
2208 "value for distance, %d CRNTI:%d", *distance,ue->ueId);
2213 }/*rgSCHDrxCalcNxtTmrExpry*/
2215 /* ccpu00134670- Validating onduration timer versus DRX cycle*/
2216 /***********************************************************
2218 * Func : rgSCHCfgVldtTddDrxCycCfg
2221 * Desc : Validates DRX Cycle Length configuration against received
2222 * onDuration timer from RRC.
2233 **********************************************************/
2234 S16 rgSCHCfgVldtTddDrxCycCfg(RgSchCellCb *cell,uint16_t drxCycle,uint8_t onDurTmr, uint16_t offSet)
2237 uint16_t endTimeInSf;
2238 CmLteTimingInfo endTime;
2243 rgSCHDrxGetNxtTmrExpry(cell, startTime, onDurTmr, &endTime);
2245 endTimeInSf = (endTime.sfn* RGSCH_NUM_SUB_FRAMES)+endTime.subframe;
2247 if(((RGSCH_MAX_SUBFRM_5G + endTimeInSf- startTime) % RGSCH_MAX_SUBFRM_5G) >=
2253 startTime = (startTime + drxCycle);
2254 /* Going for next iteration if the DRX cycle is not multiple of 10. If it is
2255 multiple of 10(Number of Subframes in a SFN) then subframe, at which
2256 onduration timer can start, will be always same, Otherwise the possible
2257 subframe numbers, where the onDuration timer can start, is 5. Hence 4
2258 more iterations are required. */
2259 }while((drxCycle % RGSCH_NUM_SUB_FRAMES) &&
2260 (startTime < (drxCycle * RGSCH_NUM_SUB_FRAMES/2)));
2267 /** @brief This function is called to handle onDurationTimer per TTI processing.
2270 * Invoked by - rgSCHDrxTtiInd
2272 * Function: rgSCHDrxTtiHdlOnDurUl
2276 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
2278 * - For Uplink we shall look at an index that is
2279 * n + RG_SCH_DRX_UL_DELTA as
2280 * we are concerned with the PDCCH and not the actual PUSCH.
2283 * @param RgSchCellCb *cellCb
2284 * @param uint16_t ulIndex
2288 static Void rgSCHDrxTtiHdlOnDurUl(RgSchCellCb *cell,uint16_t ulIndex)
2291 RgSchDRXCellCb *drxCell = NULLP;
2292 RgSchUeCb *ue = NULLP;
2293 RgSchDrxUeCb *drxUe = NULLP;
2294 CmLListCp ulInactvLst; /* list of UE's becoming DL-inactive */
2295 RgSchCmnCell *cellSch = NULLP;
2296 Bool delInUlScan = FALSE;
2298 drxCell = (cell->drxCb);
2299 delInUlScan = drxCell->delInUlScan;
2300 /***********************************************************
2301 * Scanning OnDurationQ in UL
2302 ***********************************************************/
2304 /* For Uplink we shall look at an index that is n + RG_SCH_DRX_UL_DELTA as
2305 we are concerned with the PDCCH and not the actual PUSCH.*/
2307 node = drxCell->drxQ[ulIndex].onDurationQ.first;
2311 ue = (RgSchUeCb*)node->node;
2313 drxUe = RG_SCH_DRX_GET_UE(ue);
2316 if ( delInUlScan == FALSE)
2321 if ( drxUe->distance != DRX_TMR_EXPRD )
2326 /* reset the bit mask to indicate that onduration has started */
2327 drxUe->drxUlInactvMask &= ~RG_SCH_DRX_ONDUR_BITMASK;
2329 /* if no other condition is keeping UE as inactive,
2332 RG_SCH_CMN_UL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2334 if ( delInUlScan == TRUE )
2336 /*calculate next on duration occurence
2337 * and it to the onDuration Queue*/
2338 rgSCHDrxMvToNxtOnDurOcc(cell,ue,ulIndex,FALSE);
2339 }/*delInUlScan == FALSE */
2342 /***********************************************************
2343 * Scanning OnDurationExpQ in UL
2344 ***********************************************************/
2346 node = drxCell->drxQ[ulIndex].onDurationExpQ.first;
2348 /* Initialize UL inactive list */
2349 cmLListInit(&ulInactvLst);
2353 ue = (RgSchUeCb*)node->node;
2355 drxUe = RG_SCH_DRX_GET_UE(ue);
2357 if ( delInUlScan == FALSE )
2359 drxUe->onDurExpDistance--;
2362 if ( drxUe->onDurExpDistance != DRX_TMR_EXPRD )
2367 /*UE is inactive as onduration has expired */
2368 drxUe->drxUlInactvMask |= RG_SCH_DRX_ONDUR_BITMASK;
2370 if( !RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
2372 /* set the inactive bit to indicate UE has now become inactive */
2373 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
2375 /* Add to DL inactive list */
2376 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
2377 ue->ulDrxInactvLnk.node = (PTR)ue;
2380 if ( delInUlScan == TRUE)
2382 /*Remove from DRX queue*/
2383 cmLListDelFrm(&(drxCell->drxQ[ulIndex].onDurationExpQ),
2384 &(drxUe->onDurationExpEnt));
2386 drxUe->onDurExpIndx = DRX_INVALID;
2391 /* Send the list to the scheduler to mark UE as inactive in UL*/
2392 cellSch = RG_SCH_CMN_GET_CELL(cell);
2393 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
2398 /** @brief This function is called to handle onDurationTimer per TTI processing.
2401 * Invoked by - rgSCHDrxTtiInd
2403 * Function: rgSCHDrxTtiHdlOnDurDl
2407 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
2409 * - For Downlink we shall look at an index that is
2410 * n + RG_SCH_DRX_DL_DELTA.
2413 * @param RgSchCellCb *cellCb
2414 * @param uint16_t dlIndex
2418 static Void rgSCHDrxTtiHdlOnDurDl(RgSchCellCb *cell,uint16_t dlIndex)
2421 RgSchDRXCellCb *drxCell = NULLP;
2422 RgSchUeCb *ue = NULLP;
2423 RgSchDrxUeCb *drxUe = NULLP;
2424 RgSchCmnCell *cellSch = NULLP;
2425 uint16_t expiryIndex;
2426 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
2427 Bool delInUlScan = FALSE;
2429 /* The DL loop, if onDurationTimer has started, will add the UeCb
2430 * in the onDurationTmrExprQ. If !delInUlScan, then calculate the next
2431 * OnDuration occurence, q it there and remove it from the current location.
2433 /***********************************************************
2434 * Scanning OnDurationQ in DL
2435 ***********************************************************/
2436 drxCell = (cell->drxCb);
2438 delInUlScan = drxCell->delInUlScan;
2439 //DU_LOG("\nINFO --> SCH : CELL Timer [SFN : %d],[SF : %d]\n",cell->crntTime.sfn,cell->crntTime.slot);
2441 node = drxCell->drxQ[dlIndex].onDurationQ.first;
2446 ue = (RgSchUeCb* )node->node;
2450 drxUe = RG_SCH_DRX_GET_UE(ue);
2452 if ( delInUlScan == TRUE)
2457 if ( drxUe->distance != DRX_TMR_EXPRD )
2463 /* UE is active as onduration is to start */
2464 drxUe->drxDlInactvMask &= ~RG_SCH_DRX_ONDUR_BITMASK;
2466 /* set the UE as DRX active*/
2468 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2469 RG_SCH_CMN_DL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2471 /* Temporary fix to delete stale entry */
2472 if (drxUe->onDurExpIndx != DRX_INVALID)
2474 DU_LOG("\nDEBUG --> SCH : UEID:%d PreExisted[%d:%d]in onDurExpQ new[%d]",
2476 drxUe->onDurExpIndx,
2477 drxUe->onDurExpDistance,
2479 cmLListDelFrm(&(drxCell->drxQ[drxUe->onDurExpIndx].onDurationExpQ),
2480 &(drxUe->onDurationExpEnt));
2482 drxUe->onDurExpIndx = DRX_INVALID;
2484 /*start the onduration expiry timer*/
2486 rgSCHDrxCalcNxtTmrExpry(cell,
2490 &(drxUe->onDurExpDistance),
2494 expiryIndex = ((dlIndex + drxUe->onDurTmrLen) %
2495 RG_SCH_MAX_DRXQ_SIZE);
2496 drxUe->onDurExpDistance = (drxUe->onDurTmrLen)/
2497 RG_SCH_MAX_DRXQ_SIZE;
2500 cmLListAdd2Tail(&(drxCell->drxQ[expiryIndex].onDurationExpQ),
2501 &(drxUe->onDurationExpEnt));
2502 //DU_LOG("\nINFO --> SCH : DRXOnDuration Timer Started at [SFN : %d],[SF : %d]\n",cell->crntTime.sfn,cell->crntTime.slot);
2503 drxUe->onDurationExpEnt.node = (PTR)ue;
2504 drxUe->onDurExpIndx = expiryIndex;
2506 //DU_LOG("\nINFO --> SCH : DRxOnDuration will Expire = [%d]\n",\
2507 (cell->crntTime.sfn*10+cell->crntTime.slot+drxUe->onDurTmrLen));
2509 if ( delInUlScan == FALSE )
2511 /*calculate next on duration occurence
2512 * and it to the onDuration Queue*/
2513 rgSCHDrxMvToNxtOnDurOcc(cell,ue,dlIndex,FALSE);
2514 }/*delInUlScan == FALSE */
2518 /***********************************************************
2519 * Scanning OnDurationExpQ in DL
2520 ***********************************************************/
2522 /* Mark UE as Inactive based on OnDuration Expiry */
2523 node = drxCell->drxQ[dlIndex].onDurationExpQ.first;
2525 /* Initialize DL inactive list */
2526 cmLListInit(&dlInactvLst);
2530 ue = (RgSchUeCb*)node->node;
2532 drxUe = RG_SCH_DRX_GET_UE(ue);
2534 if ( delInUlScan == TRUE )
2536 drxUe->onDurExpDistance--;
2539 if ( drxUe->onDurExpDistance != DRX_TMR_EXPRD )
2545 /* UE is inactive as onduration has expired */
2546 drxUe->drxDlInactvMask |= (RG_SCH_DRX_ONDUR_BITMASK);
2548 if( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
2550 /* set the inactive bit to indicate UE has now become inactive */
2551 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
2553 /* Add to DL inactive list */
2554 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
2555 ue->dlDrxInactvLnk.node = (PTR)ue;
2558 if ( delInUlScan == FALSE )
2560 /*Remove from DRX queue*/
2561 cmLListDelFrm(&(drxCell->drxQ[dlIndex].onDurationExpQ),
2562 &(drxUe->onDurationExpEnt));
2564 drxUe->onDurExpIndx = DRX_INVALID;
2569 /* Send the list to the scheduler to mark UE as inactive */
2570 cellSch = RG_SCH_CMN_GET_CELL(cell);
2571 cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
2574 }/*rgSCHDrxTtiHdlOnDurDl*/
2576 /** @brief This function handles the Dl HARQ timer's processing per TTI.
2579 * Invoked by - rgSCHDrxTtiHdlDlHarq
2581 * Function: rgSCHDrxTtiHdlDlHarqRTT
2584 * - In addition per TTI DRX module must look at Downlink HARQ queues
2585 * maintained to track HARQ RTT timer and drx-RetransmissionTimer.
2586 * Every TTI at the scheduling index we shall check these queues and
2587 * process accordingly.
2589 * @param RgSchCellCb *cellCb
2590 * @param uint16_t dlIndex
2594 static Void rgSCHDrxTtiHdlDlHarqRTT(RgSchCellCb *cell,uint16_t dlIndex)
2597 RgSchDrxDlHqProcCb *drxHq;
2598 RgSchDlHqProcCb *dlHq;
2599 RgSchDRXCellCb *drxCell;
2600 RgSchDrxUeCb *drxUe;
2601 uint16_t reTxExpIndx;
2604 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
2605 RgSchCmnCell *cellSch = RG_SCH_CMN_GET_CELL(cell);
2607 uint32_t dlInactvMask;
2609 drxCell = cell->drxCb;
2610 delInUlScan = drxCell->delInUlScan;
2612 /***********************************************************
2613 * Scanning harqRTTQ in DL
2614 ***********************************************************/
2616 cmLListInit(&dlInactvLst);
2617 node = drxCell->drxQ[dlIndex].harqRTTQ.first;
2621 dlHq = (RgSchDlHqProcCb*)node->node;
2625 if(TRUE == ue->isEmtcUe)
2630 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2631 drxUe = RG_SCH_DRX_GET_UE(ue);
2632 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2633 /* add the UE to the cell's retransmission queuee before starting
2634 * reTx timer, because this will not depend on retx timer trigger*/
2635 rgSCHUtlDlProcAddToRetx(dlHq->hqE->cell, dlHq);
2637 if ( delInUlScan == FALSE)
2639 cmLListDelFrm (&(drxCell->drxQ[dlIndex].harqRTTQ),
2640 &(drxHq->harqRTTEnt));
2642 drxHq->rttIndx = DRX_INVALID;
2644 /* ccpu00134565: Starting retransmission timer only if timerLen is
2645 * having non-zero value after reduction, Adding to Retx queue is
2646 * independent of starting retransmission timer. Hence if part will
2647 * take care of starting retx timer only*/
2648 if (drxUe->drxRetransTmrLen > drxHq->retxTmrReduction)
2650 /* add the harq proc to the re-tx queue--*/
2652 /* ccpu00134196-[Add]-DRX retx timer changes */
2653 rgSCHDrxCalcNxtTmrExpry(cell,
2656 drxUe->drxRetransTmrLen-drxHq->retxTmrReduction,
2657 NULLP, /*retransQ does not maintain distance*/
2662 /* ccpu00134196-[Add]-DRX retx timer changes */
2663 reTxExpIndx = ((dlIndex +
2664 drxUe->drxRetransTmrLen-drxHq->retxTmrReduction) %
2665 RG_SCH_MAX_DRXQ_SIZE);
2667 /* TODO. Workaround to avoid duplicate entry */
2668 if(drxHq->reTxIndx == DRX_INVALID)
2670 cmLListAdd2Tail (&(drxCell->drxQ[reTxExpIndx].harqRetxQ),
2671 &(drxHq->harqRetxEnt));
2673 drxHq->harqRetxEnt.node = (PTR)dlHq;
2674 drxHq->reTxIndx = reTxExpIndx;
2678 DU_LOG("\nERROR --> SCH : CRNTI:%d "
2679 "Adding Retx Node to expire at RetxIndx: %d at dlIndex %d "
2680 "drxHq->reTxIndx %d", ue->ueId, reTxExpIndx, dlIndex,
2684 /*mark the ue as active for downlink--*/
2685 drxUe->drxDlInactvMask &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2686 drxUe->drxDlInactvMaskPerCell[cellIdx] &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2688 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2689 RG_SCH_CMN_DL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2693 /***********************************************************
2694 * Scanning harqRetxQ in DL
2695 ***********************************************************/
2697 node = drxCell->drxQ[dlIndex].harqRetxQ.first;
2700 dlHq = (RgSchDlHqProcCb*)node->node;
2702 drxUe = RG_SCH_DRX_GET_UE(ue);
2704 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2705 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2707 /*mark the ue as in-active for downlink*/
2708 drxUe->drxDlInactvMaskPerCell[cellIdx] |= (RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2710 dlInactvMask = RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId;
2712 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
2714 dlInactvMask &= drxUe->drxDlInactvMaskPerCell[cellIdx];
2717 drxUe->drxDlInactvMask |= dlInactvMask;
2719 /* if no other condition is keeping ue active,
2722 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
2724 ue->dl.dlInactvMask |= (RG_DRX_INACTIVE);
2726 /* Add to DL inactive list */
2727 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
2728 ue->dlDrxInactvLnk.node = (PTR)ue;
2731 /*remove the harq proc from this queue*/
2732 if ( delInUlScan == FALSE)
2734 cmLListDelFrm (&(drxCell->drxQ[dlIndex].harqRetxQ),
2735 &(drxHq->harqRetxEnt));
2736 drxHq->reTxIndx = DRX_INVALID;
2739 /*Call schedulers to inactivate ue*/
2740 cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
2745 /** @brief This function handles the Ul HARQ timer's processing per TTI.
2748 * Invoked by - rgSCHDrxTtiHdlDlHarq
2750 * Function: rgSCHDrxTtiHdlUlHarqRTT
2753 * - In addition per TTI DRX module must look at Downlink HARQ queues
2754 * maintained to track HARQ RTT timer and drx-RetransmissionTimer.
2755 * Every TTI at the scheduling index we shall check these queues and
2756 * process accordingly.
2758 * - Though these timers are related to downlink HARQ processing, they
2759 * have an impact on uplink scheduling. The reason is that the UE,
2760 * if active for downlink scheduling implies that it is reading
2761 * PDCCHs i.e. we can still send uplink allocations to the UE. Hence
2762 * every TTI Uplink too would look at the harqRTTQ and harqRetxQ.
2766 * @param RgSchCellCb *cellCb
2767 * @param uint16_t ulIndex
2771 static Void rgSCHDrxTtiHdlUlHarqRTT(RgSchCellCb *cell,uint16_t ulIndex)
2774 RgSchDrxDlHqProcCb *drxHq;
2775 RgSchDlHqProcCb *dlHq;
2776 RgSchDRXCellCb *drxCell;
2777 RgSchDrxUeCb *drxUe;
2780 CmLListCp ulInactvLst; /* list of UE's becoming DL-inactive */
2781 RgSchCmnCell *cellSch = RG_SCH_CMN_GET_CELL(cell);
2783 uint32_t ulInactvMask;
2786 drxCell = cell->drxCb;
2787 delInUlScan = drxCell->delInUlScan;
2789 cmLListInit(&ulInactvLst);
2791 /***********************************************************
2792 * Scanning harqRTTQ in UL
2793 ***********************************************************/
2796 Though these timers are related to downlink HARQ processing, they
2797 have an impact on uplink scheduling. The reason is that the UE,
2798 if active for downlink scheduling implies that it is reading
2799 PDCCHs i.e. we can still send uplink allocations to the UE. Hence
2800 every TTI Uplink too would look at the harqRTTQ and harqRetxQ.
2803 node = drxCell->drxQ[ulIndex].harqRTTQ.first;
2806 dlHq = (RgSchDlHqProcCb*)node->node;
2808 drxUe = RG_SCH_DRX_GET_UE(ue);
2810 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2811 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2813 if ( delInUlScan == TRUE )
2815 /* remove the harq proc from this queue--*/
2816 cmLListDelFrm (&(drxCell->drxQ[ulIndex].harqRTTQ),
2817 &(drxHq->harqRTTEnt));
2819 drxHq->rttIndx = DRX_INVALID;
2822 /* mark the ue as active for uplink--*/
2823 drxUe->drxUlInactvMask &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2824 drxUe->drxUlInactvMaskPerCell[cellIdx] &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2826 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2827 RG_SCH_CMN_UL_UPDT_INACTV_MASK( cell, ue, RG_DRX_INACTIVE);
2830 /***********************************************************
2831 * Scanning harqRetxQ in UL
2832 ***********************************************************/
2833 node = drxCell->drxQ[ulIndex].harqRetxQ.first;
2836 dlHq = (RgSchDlHqProcCb*)node->node;
2838 drxUe = RG_SCH_DRX_GET_UE(ue);
2839 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2840 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2842 /*mark the ue as in-active for uplink*/
2844 drxUe->drxUlInactvMaskPerCell[cellIdx] |= (RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2846 ulInactvMask = RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId;
2848 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
2850 ulInactvMask &= drxUe->drxUlInactvMaskPerCell[cellIdx];
2853 drxUe->drxUlInactvMask |= ulInactvMask;
2855 if(!RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
2857 ue->ul.ulInactvMask |= (RG_DRX_INACTIVE);
2859 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
2860 ue->ulDrxInactvLnk.node = (PTR)ue;
2863 /* remove the harq proc from this queue*/
2864 if ( delInUlScan == TRUE)
2866 cmLListDelFrm (&(drxCell->drxQ[ulIndex].harqRetxQ),
2867 &(drxHq->harqRetxEnt));
2868 drxHq->reTxIndx = DRX_INVALID;
2873 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
2879 /**********************************************************************
2882 **********************************************************************/