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 "envopt.h" /* environment options */
41 #include "envdep.h" /* environment dependent */
42 #include "envind.h" /* environment independent */
43 #include "gen.h" /* general layer */
44 #include "ssi.h" /* system service interface */
45 #include "cm_hash.h" /* common hash list */
46 #include "cm_llist.h" /* common linked list library */
47 #include "cm_err.h" /* common error */
48 #include "cm_lte.h" /* common LTE */
54 #include "rg_sch_inf.h"
55 #ifdef LTEMAC_PH3_HDFDD
56 #include "rg_sch_hdfdd.h"
57 #endif /*LTEMAC_PH3_HDFDD*/
59 #include "rg_sch_err.h"
60 #include "rg_sch_cmn.h"
61 #include "rl_interface.h"
62 #include "rl_common.h"
64 /* header/extern include files (.x) */
65 #include "gen.x" /* general layer typedefs */
66 #include "ssi.x" /* system services typedefs */
67 #include "cm5.x" /* common timers */
68 #include "cm_hash.x" /* common hash list */
69 #include "cm_lib.x" /* common library */
70 #include "cm_llist.x" /* common linked list */
71 #include "cm_mblk.x" /* memory management */
72 #include "cm_tkns.x" /* common tokens */
73 #include "cm_lte.x" /* common tokens */
74 #include "tfu.x" /* TFU types */
75 #include "lrg.x" /* layer management typedefs for MAC */
76 #include "rgr.x" /* layer management typedefs for MAC */
77 #include "rgm.x" /* layer management typedefs for MAC */
78 #include "rg_sch_inf.x" /* typedefs for Scheduler */
79 #ifdef LTEMAC_PH3_HDFDD
80 #include "rg_sch_hdfdd.x"
81 #endif /*LTEMAC_PH3_HDFDD*/
83 #include "rg_sch.x" /* typedefs for Scheduler */
84 #include "rg_sch_cmn.x"
87 * @file rg_sch_drx.c This file gives the describes the design for DRX feature.
89 * DRX is Discontinuous Reception i.e. the UE in order to save some battery
90 * would not monitor (decode) PDCCHs at all times. Instead the UE is configured
91 * with a periodically occuring duration wherein it shall monitor PDCCHs. The UE
92 * can be called ACTIVE at this time, this time is a minimum of a configurable
93 * value - onDuration and a maximum of Infinity.
95 * ACTIVE time MIN (onDuration) MAX (infinity)
97 * A sample configuration is periodicity of 10 subframes (ms) and an offset
98 * value of 3. This can be represented as the diagram given below. The portion
99 * marked as ACTIVE is the onDuration and the UE monitors PDCCHs.
103 * <-ACTIVE-><---IN-ACTIVE------><-ACTIVE-><---IN-ACTIVE--
105 * |__|__|__|--------|__|__|__|__|__|__|__|--------|__|__|__|__|__|
106 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
111 /******************************************************************************
112 * Structure definitions for TDD *
113 ******************************************************************************/
115 /** @brief : No of DL subframes in a particular TDD configuration
117 * @details : Special subframes in TDD can carry PDCCH if configured
118 * for DwPTS. For normal CP with subframe configruation (0-8)
119 * & extended CP with subframe configuration (0-6), Special
120 * Subframes can carry PDCCH and are represented in row 0.
121 * Extended CP with subframe configuraton (7-8), which do
122 * not carry PDCCH are represented in row 1.
123 * rgSchDrxDlSfTddCfg[1][2] represent number of DL subframes
124 * in TDD config 2 where DwPTS can carry PDCCH and
125 * rgSchDrxDlSfTddCfg[0][2] represent number of DL subframes
126 * in TDD config 2 where no DwPTS exits.
129 PRIVATE U8 rgSchDrxDlSfTddCfg[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG] =
135 /** @brief : No of DL subframes till next SFN from a particular subframe
137 * @details :For a given Special subframe config
138 * (refer rgSchDrxDlSfTddCfg for an explanation) and given
139 * TDD config, how many DL subframes till Next SFN from this
144 PRIVATE U8 rgSchDrxDLSfTillNxtSFN[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG]
145 [RGSCH_NUM_SUB_FRAMES]=
148 {2,1,1,1,1,1,0,0,0,0},
149 {4,3,3,3,3,2,1,1,1,1},
150 {6,5,5,5,4,3,2,2,2,1},
151 {6,5,5,5,5,5,4,3,2,1},
152 {7,6,6,6,6,5,4,3,2,1},
153 {8,7,7,7,6,5,4,3,2,1},
154 {3,2,2,2,2,2,1,1,1,1}
158 {4,3,2,2,2,2,1,0,0,0},
159 {6,5,4,4,4,3,2,1,1,1},
160 {8,7,6,6,5,4,3,2,1,1},
161 {7,6,5,5,5,5,4,3,2,1},
162 {8,7,6,6,6,5,4,3,2,1},
163 {9,8,7,7,6,5,4,3,2,1},
164 {5,4,3,3,3,3,2,1,1,1}
166 }; /*rgSchDrxDLSfTillNxtSFN*/
169 /** @brief : Lookup table for DL subframe given the number of subframes
171 * @details :For a given Special subframe config
172 * (refer rgSchDrxDlSfTddCfg for an explanation) and given
173 * TDD config, the DL subframe index given the number of subframes
177 PRIVATE U8 rgSchDrxDLSftoDLSfIdx[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG]
178 [RGSCH_NUM_SUB_FRAMES]=
198 };/* rgSchdrxDLSftoDLSfIdx*/
199 /* ccpu00134196-[Add]-DRX retx timer changes */
200 /* The k+4 th subframe in TDD at which HARQ RTT expires may be an Uplink SF.
201 In such case, the drx retx timer may start at the next pdcch sf instead
203 U8 rgSchDrxHarqRetxFirstPsf[RGSCH_MAX_TDD_CFG][RGSCH_NUM_SUB_FRAMES] = {
204 {0, 0, 4, 0, 6, 0, 0, 4, 0, 6},
205 {0, 0, 4, 6, 0, 0, 0, 4, 6, 0},
206 {0, 0, 4, 0, 0, 0, 0, 4, 0, 0},
207 {0, 0, 4, 4, 4, 0, 0, 0, 0, 0},
208 {0, 0, 4, 4, 0, 0, 0, 0, 0, 0},
209 {0, 0, 4, 0, 0, 0, 0, 0, 0, 0},
210 {0, 0, 4, 6, 5, 0, 0, 4, 7, 0},
214 /******************************************************************************
215 * Start of Function declarations *
216 ******************************************************************************/
217 PRIVATE Void rgSCHDrxTtiHdlOnDurUl ARGS((
221 PRIVATE Void rgSCHDrxTtiHdlOnDurDl ARGS((
225 PRIVATE Void rgSCHDrxTtiHdlDlHarqRTT ARGS((
229 PRIVATE Void rgSCHDrxTtiHdlUlHarqRTT ARGS((
233 PRIVATE S16 rgSCHDrxTtiHdlOnDur ARGS((RgSchCellCb *cellCb, U16 dlIndex,
235 PRIVATE S16 rgSCHDrxTtiHdlInActv ARGS((RgSchCellCb *cellCb, U16 dlIndex,
237 PRIVATE S16 rgSCHDrxTtiHdlShortCycle ARGS((RgSchCellCb *cell, U16 dlIndex,
239 PRIVATE S16 rgSCHDrxTtiHdlDlHarq ARGS((RgSchCellCb *cellCb, U16 dlIndex,
241 PRIVATE S16 rgSCHDrxCpyUeCfg ARGS((RgSchDrxUeCb *drxCb,
242 RgrUeDrxCfg* ueDrxCfg));
244 PRIVATE S16 rgSCHDrxGetNxtOnDur ARGS((RgSchCellCb* cell,RgSchDrxUeCb* drxCb,
245 CmLteTimingInfo* nxtOnDur,
248 PRIVATE Void rgSCHDrxMvToNxtOnDurOcc ARGS((RgSchCellCb* cell,
253 PRIVATE Void rgSCHDrxCalcNxtTmrExpry ARGS((RgSchCellCb *cell,
260 PRIVATE S16 rgSCHDrxGetNxtTmrExpry ARGS((RgSchCellCb *cell,U16 curTime,
262 CmLteTimingInfo* tmrExpryIdx));
265 EXTERN S16 rgSCHEmtcDrxCpyUeCfg
270 EXTERN S16 rgSCHDrxTtiHdlUlHarq
276 EXTERN Void rgSCHDrxUeUlHqReset
285 /** @brief This function handles the per TTI handling of the DRX module.
286 * Invoked by rgSCHTti @sa rgSCHTti.
288 * @details This function goes through the drxQ and marks the UE as ACTIVE or
289 * INACTIVE based on the timers and thier status.
291 * Function: rgSCHDrxTtiInd
294 * - Processing is divided into respective timer handling.
295 * - Calculate the DL and UL indices as follows
297 * dlIndex = (cell->crntTime.sfn * 10 + cell->crntTime.subframe +
298 * RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
300 * ulIndex = (cell->crntTime.sfn * 10 + cell->crntTime.subframe +
301 * RG_SCH_DRX_UL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
303 * - Call rgSCHDrxTtiHdlOnDur to handle onDurationTimer handling
304 * - Call rgSCHDrxTtiHdlInActv to handle drx-InactivityTimer handling
305 * - Call rgSCHDrxTtiHdlShortCycle to handle Short cycle timer.
306 * - Call rgSCHDrxTtiHdlDlHarq to handle HARQ RTT and drx-retransmission
308 * - Call rgSchDrxTtiHdlUlHarq to handle Uplink HARQ processing -
309 * related to ACTIVITY when a UE is expecting a grant for an uplink
311 * - Post this processing the ueCb->dlInactvMask's DRX Bit shall be set
312 * or reset to denote ACTIVITY or INACTIVITY respectively.
313 * - Post this processing the ueCb->ulInactvMask's DRX Bit shall be set
314 * or reset to denote ACTIVITY or INACTIVITY respectively.
315 * - Add the UE to the list of Active/inactive UEs.
317 * @param RgSchCellCb *cell
318 * @param [out] CmLListCp *dlInactvLst List to which the DL in-active UEs are
323 PUBLIC Void rgSCHDrxTtiInd
328 PUBLIC Void rgSCHDrxTtiInd (cell)
335 TRC2(rgSCHDrxTtiInd );
338 dlIndex = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.subframe +
339 RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
341 ulIndex = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.subframe +
342 RG_SCH_DRX_UL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
345 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex);
346 /* checks the Ul-Retransmission timer */
350 rgSCHDrxTtiHdlUlHarq (cell, dlIndex, ulIndex);
353 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex);
355 /*Process Short cycle expiry before On duration timer so that long cycles
356 * On Duration can be processed if timer has expired*/
357 rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex);
358 rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex);
361 rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex);
362 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex);
363 /* checks the Ul-Retransmission timer */
367 rgSCHDrxTtiHdlUlHarq (cell, dlIndex, ulIndex);
370 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex);
371 rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex);
379 /** @brief This function is called to handle onDurationTimer per TTI processing.
382 * Invoked by - rgSCHDrxTtiInd
384 * Function: rgSCHDrxTtiHdlOnDur
388 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
390 * - For Downlink we shall look at an index that is
391 * n + RG_SCH_DRX_DL_DELTA.
394 * - For Uplink we shall look at an index that is
395 * n + RG_SCH_DRX_UL_DELTA as
396 * we are concerned with the PDCCH and not the actual PUSCH.
399 * @param RgSchCellCb *cellCb
402 * @return ROK/RFAILED
406 PRIVATE S16 rgSCHDrxTtiHdlOnDur
413 PRIVATE S16 rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex)
420 TRC2(rgSCHDrxTtiHdlOnDur);
422 #if ( ERRCLASS & ERRCLS_INT_PAR )
423 if ( cell == (RgSchCellCb* )NULLP )
429 rgSCHDrxTtiHdlOnDurDl(cell,dlIndex);
431 rgSCHDrxTtiHdlOnDurUl(cell, ulIndex);
435 }/*rgSCHDrxTtiHdlOnDur*/
438 /** @brief This function handles the processing for drxInactityTimer per TTI
441 * Invoked by - rgSCHDrxTtiInd
443 * Function: rgSCHDrxTtiHdlInActv
447 * - For Downlink we shall look at an index that is
448 * n + RG_SCH_DRX_DL_DELTA of the drxQ.
450 * - MARK UE AS INACTIVE BASED ON DRX-INACTIVITY TIMER EXPIRY
453 * - For Uplink we shall look at an index that is
454 * n + RG_SCH_DRX_UL_DELTA as
455 * we are concerned with the PDCCH and not the actual PUSCH.
458 * @param RgSchCellCb *cellCb
461 * @return ROK/RFAILED
465 PUBLIC S16 rgSCHDrxTtiHdlInActv
472 PUBLIC S16 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex)
479 RgSchDRXCellCb *drxCell=NULLP;
481 RgSchDrxUeCb *drxUe=NULLP;
482 U16 shrtCycleExpIndx;
483 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
484 CmLListCp ulInactvLst; /* list of UE's becoming UL-inactive */
485 RgSchCmnCell *cellSch = NULLP;
486 Bool delInUlScan = FALSE;
488 TRC2(rgSCHDrxTtiHdlInActv);
490 #if ( ERRCLASS & ERRCLS_INT_PAR )
491 if ( cell == (RgSchCellCb* )NULLP)
498 drxCell = (cell->drxCb);
499 delInUlScan = drxCell->delInUlScan;
502 /***********************************************************
503 * Scanning inActvitiyQ in DL
504 ***********************************************************/
506 /* The DL loop will scan for UE's whose inactivity timer has
507 * expired. It will switch the cycle to short or long based
508 * on the cycle configured.
509 * Furhter,if !delInUlScan, then will remove the UE from the
513 node = drxCell->drxQ[dlIndex].inActvTmrQ.first;
515 /* Initialize DL inactive list */
516 cmLListInit(&dlInactvLst);
518 /* Initialize UL inactive list */
519 cmLListInit(&ulInactvLst);
523 ue = (RgSchUeCb*)node->node;
525 drxUe = RG_SCH_DRX_GET_UE(ue);
527 if ( delInUlScan == TRUE)
529 drxUe->drxInactDistance--;
532 if ( drxUe->drxInactDistance != DRX_TMR_EXPRD )
537 /* UE is inactive as inactivity timer has expired */
538 drxUe->drxDlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
541 /* update the ue mask only if no condition in drx
542 * is keeping ue active
544 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
546 /* set the UE has DRX inactive */
547 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
549 /* Add to DL inactive list */
550 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
551 ue->dlDrxInactvLnk.node = (PTR)ue;
554 /*Remove from the queue if !delInUlScan */
555 if( delInUlScan == FALSE )
557 cmLListDelFrm(&(drxCell->drxQ[dlIndex].inActvTmrQ),
558 &(drxUe->inActvTmrEnt));
560 drxUe->drxInactvIndx = DRX_INVALID;
562 }/* if (delInUlScan == FALSE) */
564 if (drxUe->isShortCycleCfgd)
566 /* add shorty cycle expirty */
567 drxUe->isLongCycle = FALSE;
569 shrtCycleExpIndx = (dlIndex + (drxUe->shortCycleTmrLen *
570 drxUe->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
572 drxUe->drxShortCycleDistance = (drxUe->shortCycleTmrLen *
573 drxUe->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
575 /*Remove the UE from existing index*/
576 if (drxUe->shortCycleIndx != DRX_INVALID)
578 cmLListDelFrm(&(drxCell->drxQ[drxUe->shortCycleIndx].shortCycleQ),
579 &(drxUe->shortCycleEnt));
582 cmLListAdd2Tail(&(drxCell->drxQ[shrtCycleExpIndx].shortCycleQ),
583 &(drxUe->shortCycleEnt));
585 drxUe->shortCycleEnt.node = (PTR)ue;
586 drxUe->shortCycleIndx = shrtCycleExpIndx;
588 /*Calculate onDuration again & move the
589 * ueCb to the next Onduration occurence
592 /*we maybe at any position in the RF timeline,
593 * need to calculate onDuration from the starting
596 rgSCHDrxMvToNxtOnDurOcc(cell,ue,RG_SCH_DRX_DL_DELTA,TRUE);
598 }/*isShortCycleCfgd */
601 /* use the long cycle */
602 drxUe->isLongCycle = TRUE;
608 /***********************************************************
609 * Scanning inActvitiyQ in UL
610 ***********************************************************/
612 /* The UL loop will scan for UE's whose inactivity timer has
613 * expired and mark the UE's UL inactive.
614 * Furhter,if delInUlScan, then will remove the UE from the
618 /* For Uplink we shall look at an index that is n + RG_SCH_DRX_UL_DELTA as
619 we are concerned with the PDCCH and not the actual PUSCH.*/
623 node = drxCell->drxQ[ulIndex].inActvTmrQ.first;
628 ue = (RgSchUeCb*)node->node;
630 drxUe = RG_SCH_DRX_GET_UE(ue);
632 if ( delInUlScan == FALSE)
634 drxUe->drxInactDistance--;
637 if ( drxUe->drxInactDistance != DRX_TMR_EXPRD )
642 /* Need to mark the UE as inactive due to expiry of
643 * DRX inactivity timer */
645 /* UE is inactive as inactivity timer has expired */
646 drxUe->drxUlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
648 /* update the ue mask only if no other condition in
649 * drx is keeping ue active */
651 if (!RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
653 /* set the inactivity bit */
654 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
656 /* Add to Ul inactive list */
657 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
658 ue->ulDrxInactvLnk.node = (PTR)ue;
661 if ( delInUlScan == TRUE)
663 /* remove from queue */
664 cmLListDelFrm(&(drxCell->drxQ[ulIndex].inActvTmrQ),
665 &(drxUe->inActvTmrEnt));
667 drxUe->drxInactvIndx = DRX_INVALID;
669 }/* if ( delInUlScan == TRUE) */
670 }/*while(node) for uplink */
673 /* Send the list to the scheduler to mark UE as inactive in UL*/
674 cellSch = RG_SCH_CMN_GET_CELL(cell);
675 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
677 /* Send the DL inactive list to the scheduler to mark UE as inactive */
678 cellSch = RG_SCH_CMN_GET_CELL(cell);
679 cellSch->apisDl->rgSCHDlInactvtUes(cell,&dlInactvLst);
682 }/*rgSCHDrxTtiHdlInActv*/
684 /** @brief This function handles the per TTI processing for DRX short cycle
688 * Invoked by - rgSCHDrxTtiInd
690 * Function: rgSCHDrxTtiHdlShortCycle
695 * in addition we have to mark the ues based on drx short cycle
699 * @param RgSchCellCb *cell
702 * @return ROK/RFAILED
706 PUBLIC S16 rgSCHDrxTtiHdlShortCycle
713 PUBLIC S16 rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex)
720 RgSchDRXCellCb *drxCell=NULLP;
722 RgSchDrxUeCb *drxUe=NULLP;
724 TRC2(rgSCHDrxTtiHdlShortCycle );
726 #if ( ERRCLASS & ERRCLS_INT_PAR )
727 if ( cell == (RgSchCellCb* )NULLP )
736 drxCell = RG_SCH_DRX_GET_CELL(cell);
738 node = drxCell->drxQ[dlIndex].shortCycleQ.first;
742 ue = (RgSchUeCb*)node->node;
744 drxUe = RG_SCH_DRX_GET_UE(ue);
746 if ( --drxUe->drxShortCycleDistance != DRX_TMR_EXPRD)
751 /* mark the UE's current cycle to be long */
752 drxUe->isLongCycle = TRUE;
754 /* remove from the shortCycleQ */
756 cmLListDelFrm(&(drxCell->drxQ[dlIndex].shortCycleQ),
757 &(drxUe->shortCycleEnt));
758 drxUe->shortCycleIndx = DRX_INVALID;
760 /* Remove from onDuration queue inserted based on short cycle
761 * and calculate onDuration based on long cycle.*/
762 rgSCHDrxMvToNxtOnDurOcc(cell,ue,RG_SCH_DRX_DL_DELTA,TRUE);
766 }/*rgSCHDrxTtiHdlShortCycle*/
769 /** @brief This function handles the HARQ timer's processing per TTI.
772 * Invoked by - rgSCHDrxTtiInd
774 * Function: rgSCHDrxTtiHdlDlHarq
777 * - In addition per TTI DRX module must look at Downlink HARQ queues
778 * maintained to track HARQ RTT timer and drx-RetransmissionTimer.
779 * Every TTI at the scheduling index we shall check these queues and
780 * process accordingly.
783 * - Though these timers are related to downlink HARQ processing, they
784 * have an impact on uplink scheduling. The reason is that the UE,
785 * if active for downlink scheduling implies that it is reading
786 * PDCCHs i.e. we can still send uplink allocations to the UE. Hence
787 * every TTI Uplink too would look at the harqRTTQ and harqRetxQ.
791 * @param RgSchCellCb *cellCb
794 * @return ROK/RFAILED
798 PRIVATE S16 rgSCHDrxTtiHdlDlHarq
805 PRIVATE S16 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex)
812 #if ( ERRCLASS & ERRCLS_INT_PAR)
813 if ( cell == (RgSchCellCb *)NULLP )
817 #endif /*ERRCLASS & ERRCLS_INT_PAR*/
820 TRC2(rgSCHDrxTtiHdlDlHarq );
822 rgSCHDrxTtiHdlDlHarqRTT(cell, dlIndex);
824 rgSCHDrxTtiHdlUlHarqRTT(cell, ulIndex);
829 /** @brief This function is called by the common scheduler as part of
830 * finalization of allocations in downlink.
835 * Function: rgSchDrxStrtInActvTmr
837 * This function is responsible to starting drx-InactivityTimer
842 * @param RgSchCellCb *cell
843 * @param CmLListCp *ueUlLst
844 * @param U8 direction
849 PUBLIC Void rgSCHDrxStrtInActvTmr
856 PUBLIC Void rgSCHDrxStrtInActvTmr(cell, ueLst, direction)
865 RgSchDrxUeCb *ueDrxCb;
869 U16 inActvTmrExpIndx;
871 U16 curTimeInSf; /* current time in number of subframes */
876 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
877 CmLListCp ulInactvLst; /* list of UE's becoming UL-inactive */
878 RgSchCmnCell *cellSch = NULLP;
879 Bool delInUlScan = FALSE;
882 TRC2(rgSCHDrxStrtInActvTmr);
885 if ( direction == RG_SCH_DRX_UL)
888 curTimeInSf = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
889 (cell->crntTime.subframe) +RG_SCH_DRX_UL_DELTA;
893 delta = RG_SCH_DRX_UL_DELTA;
899 curTimeInSf = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
900 (cell->crntTime.subframe) + RG_SCH_DRX_DL_DELTA;
904 delta = RG_SCH_DRX_DL_DELTA;
909 /* Initialize DL inactive list */
910 cmLListInit(&dlInactvLst);
912 /* Initialize UL inactive list */
913 cmLListInit(&ulInactvLst);
915 delInUlScan = cell->drxCb->delInUlScan;
918 index1 = (curTimeInSf) % RG_SCH_MAX_DRXQ_SIZE;
925 ueCb = (RgSchUeCb *)node->node;
926 ueDrxCb = ueCb->drxCb;
928 /* Stop inactivity timer */
929 if ( ueDrxCb->drxInactvIndx != DRX_INVALID )
931 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->drxInactvIndx].inActvTmrQ),
932 &(ueDrxCb->inActvTmrEnt));
936 rgSCHDrxCalcNxtTmrExpry(cell,
939 ueDrxCb->inactvtyTmrLen,
940 &(ueDrxCb->drxInactDistance),
945 inActvTmrExpIndx = (index1 + ueDrxCb->inactvtyTmrLen)
946 % RG_SCH_MAX_DRXQ_SIZE;
948 ueDrxCb->drxInactDistance = ueDrxCb->inactvtyTmrLen
949 / RG_SCH_MAX_DRXQ_SIZE;
952 cmLListAdd2Tail(&(cell->drxCb->drxQ[inActvTmrExpIndx].inActvTmrQ),
953 &(ueDrxCb->inActvTmrEnt));
955 ueDrxCb->inActvTmrEnt.node = (PTR)ueCb;
957 ueDrxCb->drxInactvIndx = inActvTmrExpIndx;
959 /* Update DRX InActive both masks */
960 ueDrxCb->drxUlInactvMask &= ~RG_SCH_DRX_INACTVTMR_BITMASK;
961 ueDrxCb->drxDlInactvMask &= ~RG_SCH_DRX_INACTVTMR_BITMASK;
963 /* Update UE's Inactive masks */
964 ueCb->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
965 ueCb->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
967 if ( delInUlScan == TRUE)
969 if ( ueDrxCb->inactvtyTmrLen == RGR_DRX_PRD_1PSF)
971 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
972 ueDrxCb->drxDlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
974 /* if no other condition is keeping ue inactive,
977 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(ueDrxCb) )
979 ueCb->dl.dlInactvMask |= RG_DRX_INACTIVE;
981 /* Add to DL inactive list */
982 cmLListAdd2Tail(&dlInactvLst,&(ueCb->dlDrxInactvLnk));
983 ueCb->dlDrxInactvLnk.node = (PTR)ueCb;
985 }/*if ( ueDrxCb->inactvyTmrLen...*/
987 }/*delInUlScan==TRUE*/
990 if ( ueDrxCb->inactvtyTmrLen == RGR_DRX_PRD_1PSF )
992 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
993 ueDrxCb->drxUlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
994 /* if no other condition is keeping ue inactive,
997 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(ueDrxCb) )
999 ueCb->ul.ulInactvMask |= RG_DRX_INACTIVE;
1001 if ( !RG_SCH_CMN_UL_IS_UE_ACTIVE(ueCb))
1003 /* Add to UL inactive list */
1004 cmLListAdd2Tail(&ulInactvLst,&(ueCb->ulDrxInactvLnk));
1005 ueCb->ulDrxInactvLnk.node = (PTR)ueCb;
1007 }/*if ( !RG_SCH_DRX....)*/
1008 }/*if (ueDrxCb->inactv...*/
1011 /* move the link list forward */
1015 cmLListDelFrm(ueLst, delNode);
1016 delNode->node = NULLP;
1020 /* Send the list to the scheduler to mark UE as inactive in UL*/
1021 cellSch = RG_SCH_CMN_GET_CELL(cell);
1022 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
1024 /* Send the DL inactive list to the scheduler to mark UE as inactive */
1025 cellSch = RG_SCH_CMN_GET_CELL(cell);
1026 cellSch->apisDl->rgSCHDlInactvtUes(cell,&dlInactvLst);
1029 }/*rgSCHDrxStrtInActvTmr*/
1031 /** @brief This function is called by the downlink HARQ module on receiving a
1032 * negative feedback from the UE for a PDSCH transmission.
1035 * Invoked by - rgSCHDhmHqTrnsFail
1037 * Function: rgSCHDrxStartHarqRTTTmr
1042 * @param RgSchCellCb *cell
1043 * @param RgSchDlHqProcCb *dlHq
1048 PUBLIC Void rgSCHDrxStartHarqRTTTmr
1051 RgSchDlHqProcCb *hqP,
1055 PUBLIC Void rgSCHDrxStartHarqRTTTmr(cell, hqP, tbCnt)
1057 RgSchDlHqProcCb *hqP;
1061 RgSchDRXCellCb *drxCell =NULLP;
1062 RgSchDrxDlHqProcCb *drxHq =NULLP;
1066 U8 firstDlTxOcassion;
1067 U8 drxRetxTmrStartSf;
1069 TRC2(rgSCHDrxStartHarqRTTTmr);
1072 drxCell = RG_SCH_DRX_GET_CELL(cell);
1073 drxHq = RG_SCH_DRX_GET_DL_HQ(hqP);
1076 /* ccpu00134196-[Add]-DRX retx timer changes */
1077 firstDlTxOcassion = rgSchDrxHarqRetxFirstPsf[cell->ulDlCfgIdx]
1078 [hqP->tbInfo[tbCnt].fdbkTime.subframe];
1080 harqRTTExpIndx = ((hqP->tbInfo[tbCnt].fdbkTime.sfn * 10) +
1081 hqP->tbInfo[tbCnt].fdbkTime.subframe + firstDlTxOcassion)
1082 % RG_SCH_MAX_DRXQ_SIZE;
1084 fdbkDelta = RGSCH_CALC_SF_DIFF(cell->crntTime, hqP->tbInfo[tbCnt].fdbkTime);
1087 /* For FDD HARQ RTT expiry index is 8 subframes from the time
1088 * corresponding PDSCH was scheduled. We are adding 1 subframe
1089 * so that UE is scheduled for retransmission in the next subframe*/
1090 /* ccpu00134196-[Add]-DRX retx timer changes */
1091 harqRTTExpIndx = ((hqP->tbInfo[tbCnt].timingInfo.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1092 hqP->tbInfo[tbCnt].timingInfo.subframe + RG_SCH_MIN_HARQ_RTT)
1093 % RG_SCH_MAX_DRXQ_SIZE;
1095 fdbkDelta = RGSCH_CALC_SF_DIFF(cell->crntTime, hqP->tbInfo[tbCnt].timingInfo);
1097 /* ccpu00134196-[Add]-DRX retx timer changes */
1098 /* ensure that the insertion into the queue happens at an index
1099 greater than the dl index, ie, do +1 */
1100 /* Instead of depending on TTI details of current time and HARQ RTT Expire
1101 * time, Handling this check with deltas, because with TTIs it is not possible
1102 * to handle wrap-around condition*/
1104 if(fdbkDelta + RG_SCH_DRX_DL_DELTA >= firstDlTxOcassion)
1106 /* The retx timer length should be reduced.
1107 This means based on the platforms delta between the DL HARQ
1108 processing and DL scheduling, drx retx timer lengths of 1ms/2ms
1109 may not be possible */
1110 drxRetxTmrStartSf = (hqP->tbInfo[tbCnt].fdbkTime.subframe +
1111 firstDlTxOcassion) % RGSCH_NUM_SUB_FRAMES;
1113 /* We are here because the Retx Timer start is moved by atleast one
1114 position. Hence the timer will be reduced by minimum one */
1115 drxHq->retxTmrReduction = 1;
1117 /* Now check the consecutive subframes starting from the actual
1118 starting position of the retx tmr till the new position. Reduce the
1119 timer value only if the sf is a Pdcch sf */
1120 for(i = 1; i <= fdbkDelta + RG_SCH_DRX_DL_DELTA-firstDlTxOcassion+ 1; i++)
1122 if (rgSchTddUlDlSubfrmTbl[cell->ulDlCfgIdx]
1123 [(drxRetxTmrStartSf+i)%RGSCH_NUM_SUB_FRAMES]
1124 != RG_SCH_TDD_UL_SUBFRAME)
1126 drxHq->retxTmrReduction++;
1130 if(fdbkDelta + RG_SCH_DRX_DL_DELTA >= RG_SCH_MIN_HARQ_RTT)
1132 drxHq->retxTmrReduction =
1133 fdbkDelta + RG_SCH_DRX_DL_DELTA - RG_SCH_MIN_HARQ_RTT+ 1;
1136 harqRTTExpIndx = (harqRTTExpIndx + drxHq->retxTmrReduction) %
1137 RG_SCH_MAX_DRXQ_SIZE;
1141 drxHq->retxTmrReduction = 0;
1143 cmLListAdd2Tail (&(drxCell->drxQ[harqRTTExpIndx].harqRTTQ),
1144 &(drxHq->harqRTTEnt));
1146 drxHq->harqRTTEnt.node = (PTR)hqP;
1147 drxHq->rttIndx = harqRTTExpIndx;
1151 }/*rgSCHDrxStartHarqRTTTmr*/
1154 /** @brief This function is called by the Configuration module to give a
1155 * trigger to DRX module for UE configuration.
1159 * Function: rgSCHDrxUeCfg
1162 * - Copy configuration information into drxUe structure.
1163 * - Calculate the first occurance of onDuration based on values
1164 * provided in the configuration structure.
1165 * - Append the UE to the onDurationQ at that index.
1166 * - The UE must be appened to the list based on the timing calculated
1167 * above (nxtSfn, nxtSubframe).
1169 * @param RgSchCellCb *cell Cell control block.
1170 * @param RgSchUeCb *ue UE control block.
1171 * @param RgrUeCfg *ueCfg RGR UE configuration information.
1177 PUBLIC S16 rgSCHDrxUeCfg
1184 PUBLIC S16 rgSCHDrxUeCfg (cell, ue, ueCfg)
1191 RgSchDrxUeCb *ueDrxCb;
1192 CmLteTimingInfo nxtOnDur;
1199 TRC2(rgSCHDrxUeCfg);
1202 #if ( ERRCLASS & ERRCLS_INT_PAR )
1203 if ( cell == (RgSchCellCb* )NULLP)
1208 if ((ue == (RgSchUeCb* )NULLP)
1210 (ueCfg == (RgrUeCfg* )NULLP))
1212 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId, "rgSCHDrxUeCfg():"
1213 "Invalid params.cell or ue or ueCfg is NULL ");
1219 /* allocate and initialize drxCb */
1220 ret = rgSCHUtlAllocSBuf(cell->instIdx, (Data**)&ue->drxCb,
1221 (sizeof(RgSchDrxUeCb)));
1225 RLOG_ARG1(L_ERROR,DBG_CELLID,cell->cellId,
1226 "Memory allocation FAILED for DRX UECB CRBTI:%d",ue->ueId);
1230 ueDrxCb = ue->drxCb;
1232 /* initialize the masks */
1233 ueDrxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1234 ueDrxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1235 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
1236 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
1238 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1240 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1241 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1244 /* Copy the configuration values into the UE's DRX CB. */
1245 rgSCHDrxCpyUeCfg (ueDrxCb, &ueCfg->ueDrxCfg);
1249 rgSCHEmtcDrxCpyUeCfg(ue ,&ueCfg->ueDrxCfg);
1253 /* set all indexes to default values */
1254 ueDrxCb->onDurIndx = DRX_INVALID;
1255 ueDrxCb->onDurExpIndx = DRX_INVALID;
1256 ueDrxCb->drxInactvIndx = DRX_INVALID;
1257 ueDrxCb->shortCycleIndx = DRX_INVALID;
1259 /* set all distances to timer expiry */
1260 ueDrxCb->onDurExpDistance = DRX_TMR_EXPRD;
1261 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
1262 ueDrxCb->drxShortCycleDistance = DRX_TMR_EXPRD;
1263 ueDrxCb->distance = DRX_TMR_EXPRD;
1265 /* Mark the UE in long/short cycle initially as per configuration*/
1266 if(FALSE == ueDrxCb->isShortCycleCfgd)
1268 ueDrxCb->isLongCycle = TRUE;
1272 ueDrxCb->isLongCycle = FALSE;
1275 /* Calculate the next occurance from this point */
1276 rgSCHDrxGetNxtOnDur (cell, ueDrxCb, &nxtOnDur,RG_SCH_NO_DELTA);
1279 nxtOnDurTime = ((nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur.subframe);
1280 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1281 cell->crntTime.subframe);
1283 onDurIndx = nxtOnDurTime % RG_SCH_MAX_DRXQ_SIZE;
1285 ueDrxCb->distance = (nxtOnDurTime - curTime) / RG_SCH_MAX_DRXQ_SIZE;
1286 if (ueDrxCb->distance < 0)
1288 RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId, "DRXUE. Invalid "
1289 "value for distance, %d CRNTI:%d", ueDrxCb->distance,ue->ueId);
1291 //printf("The onduartion index is: %d\n",(int)onDurIndx);
1292 cmLListAdd2Tail(&(cell->drxCb->drxQ[onDurIndx].onDurationQ),
1293 &(ueDrxCb->onDurationEnt));
1295 ueDrxCb->onDurationEnt.node = (PTR)ue;
1296 ueDrxCb->onDurIndx = onDurIndx;
1298 /* Starting Short Cycle Timer */
1299 if(TRUE == ueDrxCb->isShortCycleCfgd)
1301 ueDrxCb->drxShortCycleDistance = (ueDrxCb->shortCycleTmrLen *
1302 ueDrxCb->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
1303 ueDrxCb->shortCycleIndx = (curTime + (ueDrxCb->shortCycleTmrLen *
1304 ueDrxCb->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
1305 cmLListAdd2Tail(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1306 &(ueDrxCb->shortCycleEnt));
1307 ueDrxCb->shortCycleEnt.node = (PTR)ue;
1311 } /* end of rgSCHDrxUeCfg */
1313 /** @brief This function gets the next occurance of onDurationTimer from the
1316 * @details rgSCHDrxGetNxtOnDur
1318 * Function: rgSCHDrxGetNxtOnDur
1320 * Processing steps: -
1321 * Calculation of first occurance of onDuration is to be done as
1323 * Assume DRX configuration came at subframe (x, y) the periodicity is
1324 * offset = (perd, offset).
1325 * The (sfn, subframe) satisfying the following condition is the first
1326 * occurance from this point.
1328 * (sfn * 10 + subframe) mod perd = offset
1333 * @param RgSchCellCb *cell
1334 * @param RgSchDrxUeCb *drxCb
1335 * @param CmLteTimingInfo *nxtOnDur
1337 * @return ROK/RFAILED
1340 PRIVATE S16 rgSCHDrxGetNxtOnDur
1343 RgSchDrxUeCb *drxCb,
1344 CmLteTimingInfo *nxtOnDur,
1348 PRIVATE S16 rgSCHDrxGetNxtOnDur (cell, drxCb, nxtOnDur, delta)
1350 RgSchDrxUeCb *drxCb;
1351 CmLteTimingInfo *nxtOnDur;
1361 TRC3(rgSCHDrxGetNxtOnDur);
1363 #if ( ERRCLASS & ERRCLS_INT_PAR )
1364 if ( cell == (RgSchCellCb* )NULLP )
1369 if( (drxCb == (RgSchDrxUeCb* )NULLP)
1371 (nxtOnDur == (CmLteTimingInfo* )NULLP)
1374 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
1375 "rgSCHDrxGetNxOnDur():Invalid params."
1376 "cell/drxCb/nxtOnDur is NULL");
1382 if (TRUE == drxCb->isLongCycle)
1384 cycleLen = drxCb->longDrxCycle;
1388 cycleLen = drxCb->shortDrxCycle;
1391 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) + cell->crntTime.subframe);
1393 curTime += delta; /*TODO: see if we need to take care of wrap arounds */
1395 if ( curTime <= drxCb->drxStartOffset )
1397 /* offset is the nextOnDur */
1398 nxtOnDur->sfn = drxCb->drxStartOffset / RGSCH_NUM_SUB_FRAMES_5G;
1399 nxtOnDur->subframe = (U8)(drxCb->drxStartOffset % RGSCH_NUM_SUB_FRAMES_5G);
1400 nxtDist = ((nxtOnDur->sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur->subframe);
1404 curDist = curTime - drxCb->drxStartOffset;
1406 numOfCycles = curDist / cycleLen;
1408 if (0 == (curDist % cycleLen))
1410 /* Perfect match pick up the current time */
1411 /*nxtOnDur should be set to equal to currentTime + DELTA */
1412 nxtOnDur->sfn = (U16)curTime / RGSCH_NUM_SUB_FRAMES_5G;
1413 nxtOnDur->subframe = (U16)curTime % RGSCH_NUM_SUB_FRAMES_5G;
1414 nxtDist = ((nxtOnDur->sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur->subframe);
1419 nxtDist = drxCb->drxStartOffset + (numOfCycles + 1) *
1421 nxtOnDur->sfn = (U16)nxtDist / RGSCH_NUM_SUB_FRAMES_5G;
1422 nxtOnDur->subframe = (U16)nxtDist % RGSCH_NUM_SUB_FRAMES_5G;
1427 /*If next On Duration is less than DL DELTA ahead, we will miss it and
1428 * hence need to move to the On-Duration after that.*/
1429 if((nxtDist - (curTime - delta)) <= RG_SCH_DRX_MAX_DELTA)
1431 nxtDist = nxtDist + cycleLen;
1432 nxtOnDur->sfn = (U16)nxtDist / RGSCH_NUM_SUB_FRAMES_5G;
1433 nxtOnDur->subframe = (U16)nxtDist % RGSCH_NUM_SUB_FRAMES_5G;
1436 } /* end of rgSCHDrxGetNxtOnDur */
1438 /** @brief This function is a utility function to copy the UE configuration from
1439 * the RGR structure to the UE control block.
1442 * -Invoked by rgSCHDrxUeCfg
1444 * Function: rgSCHDrxCpyUeCfg
1447 * - Copies configuration values
1449 * @param RgSchDrxUeCb *ueCb
1450 * @param RgrUeDrxCfg *drxCfg
1451 * @return ROK/RFAILED
1454 PRIVATE S16 rgSCHDrxCpyUeCfg
1460 PRIVATE S16 rgSCHDrxCpyUeCfg (ueCb, drxCfg)
1462 RgrUeDrxCfg *drxCfg;
1465 TRC3(rgSCHDrxCpyUeCfg);
1467 #if ( ERRCLASS & ERRCLS_INT_PAR )
1468 if ( (ueCb == (RgSchDrxUeCb* )NULLP )
1470 (drxCfg == (RgrUeDrxCfg* )NULLP)
1478 /* Copy all values to UE control block */
1480 ueCb->cqiMask = drxCfg->cqiMask;
1481 #endif /*LTEMAC_R9*/
1482 ueCb->onDurTmrLen = drxCfg->drxOnDurTmr;
1483 ueCb->inactvtyTmrLen = drxCfg->drxInactvTmr;
1484 ueCb->drxRetransTmrLen = drxCfg->drxRetxTmr;
1485 ueCb->longDrxCycle = drxCfg->drxLongCycleOffst.longDrxCycle;
1486 ueCb->drxStartOffset = drxCfg->drxLongCycleOffst.drxStartOffst;
1487 ueCb->isShortCycleCfgd = drxCfg->drxShortDrx.pres;
1488 ueCb->shortDrxCycle = drxCfg->drxShortDrx.shortDrxCycle;
1489 ueCb->shortCycleTmrLen = drxCfg->drxShortDrx.drxShortCycleTmr;
1492 } /* end of rgSCHDrxCpyUeCfg */
1495 /** @brief This function is called by the configuration module when a UE is
1496 * reconfigured for DRX parameters.
1499 * Invoked By - rgSCHCfgRgrUeCfg
1501 * Function: rgSCHDrxUeReCfg
1502 * As per MAC specifications the new values of timers shall be applied only once
1503 * they are restarted, hence no processing is required for modified timer values.
1506 * - if offset and/or drxCycleLenght changes then recalculate the next
1508 * - remove the UE from current index
1509 * - add the UE to the new index.
1510 * - if short cycle is enabled
1511 * - set isShortCycleCfgd = TRUE
1513 * @param RgSchCellCb *cell
1514 * @param RgSchUeCb *ue
1515 * @param RgrUeRecfg *ueReCfg
1516 * @return ROK/RFAILED
1519 PUBLIC S16 rgSCHDrxUeReCfg
1526 PUBLIC S16 rgSCHDrxUeReCfg (cell, ue, ueReCfg)
1529 RgrUeRecfg *ueReCfg;
1533 RgSchCmnCell *cellSch = NULLP;
1534 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
1537 Inst instIdx = cell->instIdx;
1538 RgSchDrxUeCb *ueDrxCb;
1539 CmLteTimingInfo nxtOnDur;
1543 U16 shrtCycleExpIndx;
1549 TRC2(rgSCHDrxUeReCfg);
1552 /* drx was disabled but now enabled for this ue */
1553 if ( (ue->isDrxEnabled == FALSE)
1555 (ueReCfg->ueDrxRecfg.isDrxEnabled == TRUE)
1558 /* allocated and initialize drxCb */
1559 ret = rgSCHUtlAllocSBuf(instIdx, (Data**)&ue->drxCb,
1560 (sizeof(RgSchDrxUeCb)));
1564 RLOG_ARG1(L_ERROR,DBG_CELLID,cell->cellId,
1565 "rgSCHdrxUeReCfg():""Memory allocation FAILED for DRX UE Cb CRNTI:%d",
1570 ue->isDrxEnabled = TRUE; /* sachin */
1571 /* initialize the masks */
1572 ue->drxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1573 ue->drxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1574 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
1575 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
1577 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1579 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1580 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1583 /* set all indexes to default values */
1584 ue->drxCb->onDurIndx = DRX_INVALID;
1585 ue->drxCb->onDurExpIndx = DRX_INVALID;
1586 ue->drxCb->drxInactvIndx = DRX_INVALID;
1587 ue->drxCb->shortCycleIndx = DRX_INVALID;
1589 /* set all distances to timer expiry */
1590 ue->drxCb->onDurExpDistance = DRX_TMR_EXPRD;
1591 ue->drxCb->drxInactDistance = DRX_TMR_EXPRD;
1592 ue->drxCb->drxShortCycleDistance = DRX_TMR_EXPRD;
1593 ue->drxCb->distance = DRX_TMR_EXPRD;
1596 if( ue->drxCb == NULLP )
1600 ueDrxCb = ue->drxCb;
1602 /*drx was enabled but now disabled for this UE */
1603 if ( (ue->isDrxEnabled == TRUE )
1605 (ueReCfg->ueDrxRecfg.isDrxEnabled == FALSE)
1608 /* remove UE from all DRX Queues */
1609 (Void)rgSCHDrxUeDel(cell,ue);
1612 /* ccpu00117052 - MOD - Passing double pointer
1613 for proper NULLP assignment*/
1614 rgSCHUtlFreeSBuf(instIdx,(Data **)(&((ue->drxCb))),
1615 sizeof(RgSchDrxUeCb));
1617 /* Resetting the DRX Bit set in Inactv Mask */
1618 ue->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
1619 ue->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
1621 ue->isDrxEnabled = FALSE;
1623 }/*isDrxEnabled == FALSE */
1626 /* If Application is updating DRX params */
1627 if (ueReCfg->ueRecfgTypes & RGR_UE_DRX_RECFG )
1629 rgSCHDrxCpyUeCfg (ueDrxCb, &ueReCfg->ueDrxRecfg);
1633 rgSCHEmtcDrxCpyUeCfg(ue, &ueReCfg->ueDrxRecfg);
1639 /* Removing the UE from existing index of shortcycle, if any*/
1640 if(ueDrxCb->shortCycleIndx != DRX_INVALID)
1642 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1643 &(ueDrxCb->shortCycleEnt));
1645 ueDrxCb->shortCycleEnt.node = (PTR) NULLP;
1646 ueDrxCb->shortCycleIndx = DRX_INVALID;
1649 /* Mark for intiating long/short cycle as per received config */
1650 if(FALSE == ue->drxCb->isShortCycleCfgd)
1652 ue->drxCb->isLongCycle = TRUE;
1656 ue->drxCb->isLongCycle = FALSE;
1659 /* Calculate the next occurance from this point */
1660 rgSCHDrxGetNxtOnDur (cell, ueDrxCb, &nxtOnDur,RG_SCH_NO_DELTA);
1662 /* remove the UE from the current onDuration Queue */
1663 if ( ueDrxCb->onDurIndx != DRX_INVALID )
1665 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurIndx].onDurationQ),
1666 &(ueDrxCb->onDurationEnt));
1670 nxtOnDurTime = (nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur.subframe;
1671 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1672 cell->crntTime.subframe);
1674 /* If Onduration timer of old configuration is already running then waiting till it expires */
1675 if((ueDrxCb->onDurExpIndx != DRX_INVALID) && (ueDrxCb->onDurExpDistance != DRX_TMR_EXPRD))
1677 curIndx = (curTime + RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
1678 RLOG_ARG3(L_DEBUG,DBG_CELLID,cell->cellId,
1679 "OLD ONDUR RUNNING-EXPIRES at %d curIdx-%d nxtOnDurTime-%d",
1680 ueDrxCb->onDurExpIndx,
1684 /* Manipulating the time when old onDuration timer can expire */
1685 if(curIndx >= ueDrxCb->onDurExpIndx)
1687 onDurExpTime = curTime + ((ueDrxCb->onDurExpDistance+1) * RG_SCH_MAX_DRXQ_SIZE)+ (ueDrxCb->onDurExpIndx - curIndx + RG_SCH_DRX_DL_DELTA);
1691 onDurExpTime = curTime + (ueDrxCb->onDurExpDistance * RG_SCH_MAX_DRXQ_SIZE)+ (ueDrxCb->onDurExpIndx - curIndx + RG_SCH_DRX_DL_DELTA);
1694 if(nxtOnDurTime <= onDurExpTime)
1696 if(ueDrxCb->isLongCycle)
1698 cycleLen = ueDrxCb->longDrxCycle;
1702 cycleLen = ueDrxCb->shortDrxCycle;
1704 /* Moving to the possible occassion of onduration after current onduration expiry:
1705 * If both are aligning then going for next cycle */
1706 nxtOnDurTime += ((onDurExpTime - nxtOnDurTime)/cycleLen + 1 ) *cycleLen ;
1709 /* Add the UE to the index which corresponds to the next onduration start*/
1710 onDurIndx = nxtOnDurTime % RG_SCH_MAX_DRXQ_SIZE;
1712 ueDrxCb->distance = (nxtOnDurTime - curTime) / RG_SCH_MAX_DRXQ_SIZE;
1713 if (ueDrxCb->distance < 0)
1715 RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId,"DRXUE. Invalid "
1716 "value for distance, %d CRNTI:%d", ueDrxCb->distance,ue->ueId);
1719 cmLListAdd2Tail(&(cell->drxCb->drxQ[onDurIndx].onDurationQ),
1720 &(ueDrxCb->onDurationEnt));
1722 ueDrxCb->onDurationEnt.node = (PTR)ue;
1723 ueDrxCb->onDurIndx = onDurIndx;
1726 cmLListInit(&dlInactvLst);
1727 /* Add to DL inactive list */
1728 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
1729 ue->dlDrxInactvLnk.node = (PTR)ue;
1730 /* Send the list to the scheduler to mark UE as inactive */
1731 cellSch = RG_SCH_CMN_GET_CELL(cell);
1732 cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
1735 /* Starting short cycle timer as per the existence of old onDuration timer */
1736 if(TRUE == ueDrxCb->isShortCycleCfgd)
1738 /* Expiring short DRX cycle Tmr once the number of short DRX cycles done */
1739 ueDrxCb->drxShortCycleDistance = (nxtOnDurTime + ueDrxCb->onDurTmrLen + (ueDrxCb->shortCycleTmrLen -1 )*
1740 ueDrxCb->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
1741 shrtCycleExpIndx = (nxtOnDurTime + ueDrxCb->onDurTmrLen + ((ueDrxCb->shortCycleTmrLen -1)*
1742 ueDrxCb->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
1743 cmLListAdd2Tail(&(cell->drxCb->drxQ[shrtCycleExpIndx].shortCycleQ),
1744 &(ueDrxCb->shortCycleEnt));
1745 ueDrxCb->shortCycleEnt.node = (PTR)ue;
1746 ueDrxCb->shortCycleIndx = shrtCycleExpIndx;
1752 } /* end of rgSCHDrxUeReCfg */
1755 /** @brief This function Loop through the list of HARQ processes for this
1756 * UE and delete from the harqRTTQ and harqRetxQ
1758 * Function: rgSCHDrxUeHqReset
1759 * Invoked by rgSCHDrxUeDel
1762 Loop through the list of HARQ processes for this UE and delete from
1763 * the harqRTTQ and harqRetxQ.
1765 * @param RgSchCellCb *cell
1766 * @return ROK/RFAILED
1769 PUBLIC Void rgSCHDrxUeHqReset
1777 PUBLIC Void rgSCHDrxUeHqReset(cell, ue, hqE, cellIdx)
1784 RgSchDlHqProcCb *hqP;
1785 RgSchDrxDlHqProcCb *drxHq =NULLP;
1788 TRC2(rgSCHDrxUeHqReset);
1790 for(i=0; i < hqE->numHqPrcs; i++)
1792 hqP = &hqE->procs[i];
1793 drxHq = RG_SCH_DRX_GET_DL_HQ(hqP);
1795 if(drxHq->rttIndx != DRX_INVALID)
1797 cmLListDelFrm (&(cell->drxCb->drxQ[drxHq->rttIndx].harqRTTQ),
1798 &(drxHq->harqRTTEnt));
1800 drxHq->rttIndx = DRX_INVALID;
1803 if(drxHq->reTxIndx != DRX_INVALID)
1805 cmLListDelFrm (&(cell->drxCb->drxQ[drxHq->reTxIndx].harqRetxQ),
1806 &(drxHq->harqRetxEnt));
1808 drxHq->reTxIndx = DRX_INVALID;
1812 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1813 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1816 /** @brief This function Deletes DRX specific context for a UE.
1818 * @details This funciton is invoked by the Configuration module on RGR UE Deletion.
1819 * This function removes the UE's context from all of the DRX Queues.
1820 * In addition it deletes context of UE's HARQ Processes present in the harqRTTQ
1824 * Function: rgSCHDrxUeDel
1825 * Invoked by rgSCHCfgRgrUeDel
1828 * - Remove the UE from the following queues
1829 * - onDurationQ - using onDurIndx
1830 * - onDurationExpQ - using onDurExpIndx
1831 * - inActvTmrQ - using drxInactvIndx
1832 * - shortCycleQ - using shortCycleIndx
1833 * - Loop through the list of HARQ processes for this UE and delete from
1834 * the harqRTTQ and harqRetxQ.
1836 * @param RgSchCellCb *cell
1837 * @param RgSchUeCb *ue
1838 * @return ROK/RFAILED
1841 PUBLIC S16 rgSCHDrxUeDel
1847 PUBLIC S16 rgSCHDrxUeDel (cell, ue)
1852 RgSchDrxUeCb *ueDrxCb;
1853 RgSchDlHqEnt *hqE = NULLP;
1855 RgSchUeCellInfo *cellInfo = NULLP;
1857 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
1859 TRC2(rgSCHDrxUeDel);
1862 /* ccpu00129899: Moved the drx-enabled check to the caller */
1863 ueDrxCb = ue->drxCb;
1865 /* Remove UE from all queues */
1866 if ( ueDrxCb->onDurIndx != DRX_INVALID )
1868 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurIndx].onDurationQ),
1869 &(ueDrxCb->onDurationEnt));
1871 ueDrxCb->onDurIndx = DRX_INVALID;
1874 if ( ueDrxCb->onDurExpIndx != DRX_INVALID )
1876 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurExpIndx].onDurationExpQ),
1877 &(ueDrxCb->onDurationExpEnt));
1879 ueDrxCb->onDurExpIndx = DRX_INVALID;
1882 if ( ueDrxCb->drxInactvIndx != DRX_INVALID )
1884 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->drxInactvIndx].inActvTmrQ),
1885 &(ueDrxCb->inActvTmrEnt));
1887 ueDrxCb->drxInactvIndx = DRX_INVALID;
1890 if ( ueDrxCb->shortCycleIndx != DRX_INVALID )
1892 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1893 &(ueDrxCb->shortCycleEnt));
1895 ueDrxCb->shortCycleIndx = DRX_INVALID;
1898 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1900 cellInfo = ue->cellInfo[cellIdx];
1904 hqE = cellInfo->hqEnt;
1905 rgSCHDrxUeHqReset(cell, ue, hqE, cellIdx);
1911 rgSCHDrxUeUlHqReset(cell, ue, &(ueUl->hqEnt));
1914 /* Resetting the DRX Bit set in Inactv Mask */
1915 ue->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
1916 ue->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
1917 ueDrxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1918 ueDrxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1923 /** @brief This function is called at the time of RGR cell configuration.
1926 * Invoked by - rgSCHCfgRgrCellCfg
1928 * Function: rgSCHDrxCellCfg
1931 * - Initializes the following drxQ (cmMemset would do).
1934 * @param RgSchCellCb *cell
1935 * @param RgrCellCfg *cellCfg
1936 * @return ROK/RFAILED
1939 PUBLIC S16 rgSCHDrxCellCfg
1945 PUBLIC S16 rgSCHDrxCellCfg (cell, cellCfg)
1947 RgrCellCfg *cellCfg;
1952 Inst instIdx = cell->instIdx;
1954 TRC2(rgSCHDrxCellCfg);
1957 #if ( ERRCLASS & ERRCLS_INT_PAR )
1958 /*KWORK_FIX :Removed check for cell being NULL*/
1959 if( (cellCfg == (RgrCellCfg* )NULLP))
1961 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
1962 "rgSCHDrxCellCfg():Invalid Params. cell/cellCfg is NULL");
1967 /* allocate and initialize drxCb */
1968 ret = rgSCHUtlAllocSBuf(instIdx, (Data**)&cell->drxCb,
1969 (sizeof(RgSchDRXCellCb)));
1973 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,"rgSCHDrxCellCfg():"
1974 "Memory allocation FAILED for DRX cell Cb");
1978 /* delInUlScan determines which index scans the queue last.
1979 * We look at onDurationQ both from ulIndex & dlIndex pov.
1980 * Consider, onDuration starts at index 5, and current index is 2,
1981 * while dlIndex is 2 & ulIndex is 3 i.e dl is looking 2 SF ahead
1982 * and ul is looking 3 SF ahead. In this case, dl will scan the queue
1983 * last and therefore DL will delete ueCb from onDuration q.
1984 * The reverse is true for the other case.*/
1986 if ( RG_SCH_DRX_UL_DELTA > RG_SCH_DRX_DL_DELTA )
1988 cell->drxCb->delInUlScan = FALSE;
1992 cell->drxCb->delInUlScan = TRUE;
1996 } /* end of rgSchDrxCellCfg */
2000 /** @brief This function to delete DRX specific context in the cell control
2004 * Invoked by - rgSCHCfgRgrCellDel
2006 * Function: rgSCHDrxCellDel
2009 * - De-Inits RgSchDRXCellCb (Nothing to be done)
2010 * - Assumption: The API is invoked after deletion of UEs from the cell.
2012 * @param RgSchCellCb *cell
2016 PUBLIC Void rgSCHDrxCellDel
2021 PUBLIC Void rgSCHDrxCellDel (cell)
2025 Inst instIdx = cell->instIdx;
2027 TRC2(rgSCHCfgRgrCellDel);
2032 /* ccpu00117052 - MOD - Passing double pointer
2033 for proper NULLP assignment*/
2034 rgSCHUtlFreeSBuf(instIdx, (Data **)(&(cell->drxCb)),
2035 sizeof(RgSchDRXCellCb));
2038 } /* end of rgSchDrxCellDel */
2040 /** @brief This function is called when an SR is received from the UE. In this
2041 * case the UE should be marked as ACTIVE till we send a UL allocation to the
2045 * Invoked by - rgSCHCmnSrRcvd
2046 * Must be called after calling the specific scheduler.
2048 * Function: rgSCHDrxSrInd
2051 * - Mark the UE as ACTIVE
2052 * ueCb->drxUlInactvMask |= (DRX_SR_ACTIVE);
2053 * - Optionally call schedulers to add this UE to their scheduling
2055 * - Set drxUe->srRcvd = TRUE
2057 * Note : the specification state that the UE shall start be active
2058 * listening for UL grant, this implies we could potentially exploit
2059 * this to send DL transmissions as well. However we have currently
2060 * chosen not to do so.
2062 * @param RgSchCellCb *cell
2063 * @param RgSchUeCb *ue
2064 * @return ROK/RFAILED
2067 PUBLIC S16 rgSCHDrxSrInd
2073 PUBLIC S16 rgSCHDrxSrInd (cell, ue)
2078 RgSchDrxUeCb *drxCb;
2080 TRC2(rgSCHDrxSrInd);
2083 #if ( ERRCLASS & ERRCLS_INT_PAR )
2084 if ( cell == (RgSchCellCb* )NULLP)
2089 if( (ue == (RgSchUeCb* )NULLP))
2091 RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
2092 "rgSCHDrxSrInd():Invalid Params. cell/ue is NULL");
2096 /* KWork fix - shifted this down */
2099 drxCb = RG_SCH_DRX_GET_UE(ue);
2101 /* Mark the UE as active for UL only */
2102 drxCb->drxUlInactvMask &= ~RG_SCH_DRX_SR_BITMASK;
2103 drxCb->srRcvd = TRUE;
2104 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2105 RG_SCH_CMN_UL_UPDT_INACTV_MASK( cell, ue, RG_DRX_INACTIVE);
2108 } /* rgSCHDrxSrInd */
2111 /** @brief This function handles ACTIVITY due to RACH using a dedicated preamble
2112 * (PDCCH order) OR Handover. A UE shall remain marked as active from the time
2113 * we successfully send out a RAR upto the time it receives a PDCCH indicating a
2117 * Invoked by - rgSCHCmnHdlHoPo
2119 * Function: rgSCHDrxDedRa
2122 * - MARK the UE as active
2123 * - set the raRcvd = TRUE for this UE.
2126 * ueCb->drxDlInactvMask |= (DRX_RA_ACTIVE);
2127 * ueCb->drxUlInactvMask |= (DRX_RA_ACTIVE);
2128 * ueCb->raRcvd = TRUE;
2131 * @param RgSchCellCb *cellCb
2132 * @param RgSchUeCb *ueCb
2136 PUBLIC Void rgSCHDrxDedRa
2138 RgSchCellCb *cellCb,
2142 PUBLIC Void rgSCHDrxDedRa (cellCb, ueCb)
2143 RgSchCellCb *cellCb;
2147 RgSchDrxUeCb *drxCb;
2149 TRC2(rgSCHDrxDedRa);
2152 drxCb = RG_SCH_DRX_GET_UE(ueCb);
2154 /* Mark the UE as active for UL & DL */
2155 drxCb->drxUlInactvMask &= ~RG_SCH_DRX_RA_BITMASK;
2156 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2157 RG_SCH_CMN_UL_UPDT_INACTV_MASK(cellCb, ueCb, RG_DRX_INACTIVE);
2159 drxCb->drxDlInactvMask &= ~RG_SCH_DRX_RA_BITMASK;
2160 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2161 RG_SCH_CMN_DL_UPDT_INACTV_MASK(cellCb, ueCb, RG_DRX_INACTIVE);
2163 drxCb->raRcvd = TRUE;
2166 } /* end of rgSCHDrxDedRa */
2169 /** @brief This function calculates the next onDuration Occurence
2170 * and removes & queue it again in onDurationQ
2175 * Function: rgSCHDrxMvToNxtOnDurOcc
2180 * @param RgSchCellCb *cell
2181 * @param RgSchUeCb *ueCb
2182 * @param U16 idx - if calcFrmOffst is TRUE,
2183 * idx is delta to be added
2184 * @param Bool calcFrmOffst
2188 PRIVATE Void rgSCHDrxMvToNxtOnDurOcc
2196 PRIVATE Void rgSCHDrxMvToNxtOnDurOcc (cell, ueCb, idx, calcFrmOffst)
2205 RgSchDrxUeCb *drxUe;
2206 RgSchDRXCellCb *drxCell;
2207 CmLteTimingInfo nxtOnDur; /* to be used when calcFrmOffset is set */
2208 U16 nxtOnDurInSf; /* next On Duration in no of subframes */
2210 drxCell = cell->drxCb;
2211 drxUe = ueCb->drxCb;
2213 TRC2(rgSCHDrxMvToNxtOnDurOcc)
2215 if(calcFrmOffst == FALSE)
2217 if (drxUe->isLongCycle)
2219 nxtOnDurIndex = ((idx + drxUe->longDrxCycle)
2220 % RG_SCH_MAX_DRXQ_SIZE );
2221 drxUe->distance = drxUe->longDrxCycle/RG_SCH_MAX_DRXQ_SIZE;
2225 nxtOnDurIndex = ((idx + drxUe->shortDrxCycle)% RG_SCH_MAX_DRXQ_SIZE);
2227 drxUe->distance = drxUe->shortDrxCycle / RG_SCH_MAX_DRXQ_SIZE;
2232 rgSCHDrxGetNxtOnDur(cell,drxUe,&nxtOnDur,(U8)idx);
2234 nxtOnDurInSf = ((nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
2237 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
2238 cell->crntTime.subframe);
2240 nxtOnDurIndex = nxtOnDurInSf % RG_SCH_MAX_DRXQ_SIZE;
2241 drxUe->distance = (nxtOnDurInSf-curTime) / RG_SCH_MAX_DRXQ_SIZE;
2242 if (drxUe->distance < 0)
2244 RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId,"DRXUE. Invalid "
2245 "value for distance, %d CRNTI:%d", drxUe->distance,ueCb->ueId);
2249 /* First remove from existing location */
2250 if ( drxUe->onDurIndx != DRX_INVALID )
2252 cmLListDelFrm(&(drxCell->drxQ[drxUe->onDurIndx].onDurationQ),
2253 &(drxUe->onDurationEnt));
2256 /* Add at new location */
2257 cmLListAdd2Tail(&(drxCell->drxQ[nxtOnDurIndex].onDurationQ),
2258 &(drxUe->onDurationEnt));
2260 drxUe->onDurationEnt.node = (PTR)ueCb;
2261 drxUe->onDurIndx = nxtOnDurIndex;
2264 }/*rgSCHDrxMvToNxtOnDurOcc*/
2267 /** @brief This function calculates the next SFN,subframe a given
2268 * timer is going to expire. Works for all TDD configurations.
2272 * Function: rgSCHDrxGetNxtTmrExpry
2273 * We need to count only PDCCH frames in a given TDD
2274 * configuration. This is true for onDuration, inActivity
2275 * & drx-retransmission timers.
2277 * Processing steps (assume timer starts at (12,2) and duration
2278 * is 23 DL subframes):
2279 * - based on TDD configuration, move to the next SFN and
2280 * count the number of DL subframes consumed. In our example,
2281 * moving to (12,9) will consume 6 DL subframes assuming TDD
2283 * - From this point on, determine how many exact Radio Frames
2284 * will be consumed for the remaining DL subframes. In our
2285 * example, remaining DL subframes are (23-6) are 17.
2286 * For config 2, the following holds true
2287 * 8 DLSF are in 1 RF
2288 * 1 DLSF in 1/8 DLSF
2289 * 17 DLSF in 17/8 i.e 2 RF + 1 subframe
2290 * In order to consume 17 DLSF, we need to move forward
2291 * 2 RFs + 1 subframe. Adding 2 RF's gives us (14,9)
2292 * - For the remaining subframe, we need to figure out the next
2293 * available DL subframe. For TDD_configuration, the first DL
2294 * subframe is at index 0. So, the timer will run till (15,0)
2295 * and will expire on (15,1)
2297 * @param RgSchUeCb *ue Ue control block.
2298 * @param U16 curTime current Time
2299 * @param U32 duration Timer duration
2300 * @param CmLteTimingInfo *tmrExpryIdx Timer expry (SFN,sf)
2301 * @return ROK/RFAILED
2304 PRIVATE S16 rgSCHDrxGetNxtTmrExpry
2309 CmLteTimingInfo *tmrExpryIdx
2312 PRIVATE S16 rgSCHDrxGetNxtTmrExpry (cell,curTime,duration,tmrExpryIdx)
2316 CmLteTimingInfo *tmrExpryIdx;
2319 U32 dlSfTillNxtSFN; /*!< DL subframes till next SFN */
2320 U8 tddCfgMode; /*!< tdd config mode */
2321 Bool isDwPtsCnted; /*!< is DwPts counted as PDCCH sf */
2322 CmLteTimingInfo crntTime; /*!< current SFN & sf */
2325 TRC2(rgSCHDrxGetNxtTmrExpry);
2327 #if ( ERRCLASS & ERRCLS_INT_PAR )
2328 if ( (cell == (RgSchCellCb* )NULLP)
2330 (tmrExpryIdx == (CmLteTimingInfo* )NULLP)
2338 isDwPtsCnted = cell->isDwPtsCnted ;
2340 tddCfgMode = cell->ulDlCfgIdx;
2341 crntTime.sfn = curTime / RGSCH_NUM_SUB_FRAMES_5G;
2342 crntTime.subframe = curTime % RGSCH_NUM_SUB_FRAMES_5G;
2346 /* First calculate the number of DL subframes till next SFN */
2348 dlSfTillNxtSFN = rgSchDrxDLSfTillNxtSFN[isDwPtsCnted][tddCfgMode]
2349 [(crntTime.subframe % RGSCH_NUM_SUB_FRAMES)];
2352 if ( dlSfTillNxtSFN >= duration )
2354 /* the timer would expire on the same RF */
2355 U32 diff = dlSfTillNxtSFN - duration;
2357 tmrExpryIdx->sfn = crntTime.sfn;
2361 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2367 /* to know the DL sf index based on diff */
2368 arrayIdx = rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2370 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2373 }/* if ( dlSfTillNxtSFN >= duration...*/
2376 U32 remSf; /*!< remaining subframes */
2377 U32 numRf; /*!< num of complete radio frames */
2378 U32 numRemSfs; /*!< num of remaining subframes */
2380 remSf = duration - dlSfTillNxtSFN;
2382 /* move to (currSFN,9) having consued dlSfTillNxtSFN DL subframes */
2383 tmrExpryIdx->sfn = crntTime.sfn;
2384 tmrExpryIdx->subframe = (U8)9;
2386 numRf = (1 * remSf)/rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2387 numRemSfs = (1 * remSf)%rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2389 tmrExpryIdx->sfn = tmrExpryIdx->sfn + numRf;
2391 /* we are now at (X,9) having consumed dlSfTillNxtSFN + numRf * num of DL
2392 * subframes in 1 RF */
2394 if ( numRemSfs == 0 )
2396 /* we are at subframe 9 i.e. the timer is going to expire using exact
2397 * radio frames. However, not all TDD_configurations have 9 as their
2398 * last DL subframe. We might have passed the last DL subfrme.
2399 * Therefore, move back */
2400 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2405 /* a reminder implies we have to move past this SFN as we are at the
2406 * last subframe on that SFN */
2408 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2411 }/*else if diff > duration */
2413 /* timer will expire 1 + tmrExpryIdx */
2415 if ( ( tmrExpryIdx->subframe + 1) == 10 )
2418 tmrExpryIdx->subframe = 0;
2422 tmrExpryIdx->subframe++;
2425 /* check to see if it sfn has crossed its max */
2426 if ( tmrExpryIdx->sfn > RG_SCH_CMN_MAX_SFN_NUM )
2428 tmrExpryIdx->sfn = tmrExpryIdx->sfn - (RG_SCH_CMN_MAX_SFN_NUM + 1);
2432 }/*rgSCHDrxGetNxtTmrExpry*/
2434 /** @brief This function calculates the next onDuration Occurence
2439 * Function: rgSCHDrxCalcNxtTmrExpry
2441 * Processing steps: a wrapper function to call
2442 * rgSCHDrxGetNxtTmrExpry
2444 * @param RgSchCellCb *cell
2445 * @param RgSchUeCb *ue
2448 * @param U16 *distance
2450 * @return ROK/RFAILED
2453 PRIVATE Void rgSCHDrxCalcNxtTmrExpry
2463 PRIVATE Void rgSCHDrxCalcNxtTmrExpry (cell,ue,delta,tmrLen,distance,idx)
2472 U16 curTimeInSf; /*current time in no of subframes*/
2473 CmLteTimingInfo tmrExpry;
2474 U16 tmrExpryInSf; /*timer expry in no of subframes*/
2476 TRC2(rgSCHDrxCalcNxtTmrExpry)
2478 curTimeInSf = cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G +
2479 cell->crntTime.subframe;
2481 /* add delta to curTime */
2482 curTimeInSf += delta;
2484 rgSCHDrxGetNxtTmrExpry(ue->cell,curTimeInSf,tmrLen,&tmrExpry);
2486 /* convert timre Expry in terms of subframes */
2487 tmrExpryInSf = tmrExpry.sfn * RGSCH_NUM_SUB_FRAMES_5G +
2491 *idx = (tmrExpryInSf) % RG_SCH_MAX_DRXQ_SIZE;
2493 if ( distance != NULLP ) /* hqReTx don't use the concept of distance.
2494 They can send NULLP for distance.
2497 if ( tmrExpryInSf > curTimeInSf )
2499 *distance = (tmrExpryInSf - curTimeInSf) /
2500 RG_SCH_MAX_DRXQ_SIZE;
2504 /* in case the RF is at its max and wraps around */
2506 *distance = ((tmrExpryInSf + (RG_SCH_CMN_MAX_NUM_OF_SFN - 1))
2508 curTimeInSf) / RG_SCH_MAX_DRXQ_SIZE;
2512 RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId, "DRXUE. Invalid "
2513 "value for distance, %d CRNTI:%d", *distance,ue->ueId);
2518 }/*rgSCHDrxCalcNxtTmrExpry*/
2520 /* ccpu00134670- Validating onduration timer versus DRX cycle*/
2521 /***********************************************************
2523 * Func : rgSCHCfgVldtTddDrxCycCfg
2526 * Desc : Validates DRX Cycle Length configuration against received
2527 * onDuration timer from RRC.
2538 **********************************************************/
2540 PUBLIC S16 rgSCHCfgVldtTddDrxCycCfg
2548 PUBLIC S16 rgSCHCfgVldtTddDrxCycCfg(cell, drxCycle, onDurTmr, offSet)
2557 CmLteTimingInfo endTime;
2558 TRC2(rgSCHCfgVldtTddDrxCycCfg)
2563 rgSCHDrxGetNxtTmrExpry(cell, startTime, onDurTmr, &endTime);
2565 endTimeInSf = (endTime.sfn* RGSCH_NUM_SUB_FRAMES)+endTime.subframe;
2567 if(((RGSCH_MAX_SUBFRM_5G + endTimeInSf- startTime) % RGSCH_MAX_SUBFRM_5G) >=
2573 startTime = (startTime + drxCycle);
2574 /* Going for next iteration if the DRX cycle is not multiple of 10. If it is
2575 multiple of 10(Number of Subframes in a SFN) then subframe, at which
2576 onduration timer can start, will be always same, Otherwise the possible
2577 subframe numbers, where the onDuration timer can start, is 5. Hence 4
2578 more iterations are required. */
2579 }while((drxCycle % RGSCH_NUM_SUB_FRAMES) &&
2580 (startTime < (drxCycle * RGSCH_NUM_SUB_FRAMES/2)));
2587 /** @brief This function is called to handle onDurationTimer per TTI processing.
2590 * Invoked by - rgSCHDrxTtiInd
2592 * Function: rgSCHDrxTtiHdlOnDurUl
2596 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
2598 * - For Uplink we shall look at an index that is
2599 * n + RG_SCH_DRX_UL_DELTA as
2600 * we are concerned with the PDCCH and not the actual PUSCH.
2603 * @param RgSchCellCb *cellCb
2604 * @param U16 ulIndex
2609 PRIVATE Void rgSCHDrxTtiHdlOnDurUl
2615 PRIVATE Void rgSCHDrxTtiHdlOnDurUl(cell, ulIndex)
2621 RgSchDRXCellCb *drxCell = NULLP;
2622 RgSchUeCb *ue = NULLP;
2623 RgSchDrxUeCb *drxUe = NULLP;
2624 CmLListCp ulInactvLst; /* list of UE's becoming DL-inactive */
2625 RgSchCmnCell *cellSch = NULLP;
2626 Bool delInUlScan = FALSE;
2628 TRC2(rgSCHDrxTtiHdlOnDurUl)
2630 drxCell = (cell->drxCb);
2631 delInUlScan = drxCell->delInUlScan;
2632 /***********************************************************
2633 * Scanning OnDurationQ in UL
2634 ***********************************************************/
2636 /* For Uplink we shall look at an index that is n + RG_SCH_DRX_UL_DELTA as
2637 we are concerned with the PDCCH and not the actual PUSCH.*/
2639 node = drxCell->drxQ[ulIndex].onDurationQ.first;
2643 ue = (RgSchUeCb*)node->node;
2645 drxUe = RG_SCH_DRX_GET_UE(ue);
2648 if ( delInUlScan == FALSE)
2653 if ( drxUe->distance != DRX_TMR_EXPRD )
2658 /* reset the bit mask to indicate that onduration has started */
2659 drxUe->drxUlInactvMask &= ~RG_SCH_DRX_ONDUR_BITMASK;
2661 /* if no other condition is keeping UE as inactive,
2664 RG_SCH_CMN_UL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2666 if ( delInUlScan == TRUE )
2668 /*calculate next on duration occurence
2669 * and it to the onDuration Queue*/
2670 rgSCHDrxMvToNxtOnDurOcc(cell,ue,ulIndex,FALSE);
2671 }/*delInUlScan == FALSE */
2674 /***********************************************************
2675 * Scanning OnDurationExpQ in UL
2676 ***********************************************************/
2678 node = drxCell->drxQ[ulIndex].onDurationExpQ.first;
2680 /* Initialize UL inactive list */
2681 cmLListInit(&ulInactvLst);
2685 ue = (RgSchUeCb*)node->node;
2687 drxUe = RG_SCH_DRX_GET_UE(ue);
2689 if ( delInUlScan == FALSE )
2691 drxUe->onDurExpDistance--;
2694 if ( drxUe->onDurExpDistance != DRX_TMR_EXPRD )
2699 /*UE is inactive as onduration has expired */
2700 drxUe->drxUlInactvMask |= RG_SCH_DRX_ONDUR_BITMASK;
2702 if( !RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
2704 /* set the inactive bit to indicate UE has now become inactive */
2705 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
2707 /* Add to DL inactive list */
2708 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
2709 ue->ulDrxInactvLnk.node = (PTR)ue;
2712 if ( delInUlScan == TRUE)
2714 /*Remove from DRX queue*/
2715 cmLListDelFrm(&(drxCell->drxQ[ulIndex].onDurationExpQ),
2716 &(drxUe->onDurationExpEnt));
2718 drxUe->onDurExpIndx = DRX_INVALID;
2723 /* Send the list to the scheduler to mark UE as inactive in UL*/
2724 cellSch = RG_SCH_CMN_GET_CELL(cell);
2725 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
2730 /** @brief This function is called to handle onDurationTimer per TTI processing.
2733 * Invoked by - rgSCHDrxTtiInd
2735 * Function: rgSCHDrxTtiHdlOnDurDl
2739 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
2741 * - For Downlink we shall look at an index that is
2742 * n + RG_SCH_DRX_DL_DELTA.
2745 * @param RgSchCellCb *cellCb
2746 * @param U16 dlIndex
2751 PRIVATE Void rgSCHDrxTtiHdlOnDurDl
2757 PRIVATE Void rgSCHDrxTtiHdlOnDurDl(cell, dlIndex)
2763 RgSchDRXCellCb *drxCell = NULLP;
2764 RgSchUeCb *ue = NULLP;
2765 RgSchDrxUeCb *drxUe = NULLP;
2766 RgSchCmnCell *cellSch = NULLP;
2768 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
2769 Bool delInUlScan = FALSE;
2771 /* The DL loop, if onDurationTimer has started, will add the UeCb
2772 * in the onDurationTmrExprQ. If !delInUlScan, then calculate the next
2773 * OnDuration occurence, q it there and remove it from the current location.
2775 TRC2(rgSCHDrxTtiHdlOnDurDl)
2776 /***********************************************************
2777 * Scanning OnDurationQ in DL
2778 ***********************************************************/
2779 drxCell = (cell->drxCb);
2781 delInUlScan = drxCell->delInUlScan;
2782 //printf("CELL Timer [SFN : %d],[SF : %d]\n",cell->crntTime.sfn,cell->crntTime.subframe);
2784 node = drxCell->drxQ[dlIndex].onDurationQ.first;
2789 ue = (RgSchUeCb* )node->node;
2793 drxUe = RG_SCH_DRX_GET_UE(ue);
2795 if ( delInUlScan == TRUE)
2800 if ( drxUe->distance != DRX_TMR_EXPRD )
2806 /* UE is active as onduration is to start */
2807 drxUe->drxDlInactvMask &= ~RG_SCH_DRX_ONDUR_BITMASK;
2809 /* set the UE as DRX active*/
2811 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2812 RG_SCH_CMN_DL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2814 /* Temporary fix to delete stale entry */
2815 if (drxUe->onDurExpIndx != DRX_INVALID)
2817 RLOG_ARG4(L_DEBUG,DBG_CELLID,cell->cellId,
2818 "UEID:%d PreExisted[%d:%d]in onDurExpQ new[%d]",
2820 drxUe->onDurExpIndx,
2821 drxUe->onDurExpDistance,
2823 cmLListDelFrm(&(drxCell->drxQ[drxUe->onDurExpIndx].onDurationExpQ),
2824 &(drxUe->onDurationExpEnt));
2826 drxUe->onDurExpIndx = DRX_INVALID;
2828 /*start the onduration expiry timer*/
2830 rgSCHDrxCalcNxtTmrExpry(cell,
2834 &(drxUe->onDurExpDistance),
2838 expiryIndex = ((dlIndex + drxUe->onDurTmrLen) %
2839 RG_SCH_MAX_DRXQ_SIZE);
2840 drxUe->onDurExpDistance = (drxUe->onDurTmrLen)/
2841 RG_SCH_MAX_DRXQ_SIZE;
2844 cmLListAdd2Tail(&(drxCell->drxQ[expiryIndex].onDurationExpQ),
2845 &(drxUe->onDurationExpEnt));
2846 //printf("DRXOnDuration Timer Started at [SFN : %d],[SF : %d]\n",cell->crntTime.sfn,cell->crntTime.subframe);
2847 drxUe->onDurationExpEnt.node = (PTR)ue;
2848 drxUe->onDurExpIndx = expiryIndex;
2850 //printf("DRxOnDuration will Expire = [%d]\n",(cell->crntTime.sfn*10+cell->crntTime.subframe+drxUe->onDurTmrLen));
2852 if ( delInUlScan == FALSE )
2854 /*calculate next on duration occurence
2855 * and it to the onDuration Queue*/
2856 rgSCHDrxMvToNxtOnDurOcc(cell,ue,dlIndex,FALSE);
2857 }/*delInUlScan == FALSE */
2861 /***********************************************************
2862 * Scanning OnDurationExpQ in DL
2863 ***********************************************************/
2865 /* Mark UE as Inactive based on OnDuration Expiry */
2866 node = drxCell->drxQ[dlIndex].onDurationExpQ.first;
2868 /* Initialize DL inactive list */
2869 cmLListInit(&dlInactvLst);
2873 ue = (RgSchUeCb*)node->node;
2875 drxUe = RG_SCH_DRX_GET_UE(ue);
2877 if ( delInUlScan == TRUE )
2879 drxUe->onDurExpDistance--;
2882 if ( drxUe->onDurExpDistance != DRX_TMR_EXPRD )
2888 /* UE is inactive as onduration has expired */
2889 drxUe->drxDlInactvMask |= (RG_SCH_DRX_ONDUR_BITMASK);
2891 if( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
2893 /* set the inactive bit to indicate UE has now become inactive */
2894 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
2896 /* Add to DL inactive list */
2897 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
2898 ue->dlDrxInactvLnk.node = (PTR)ue;
2901 if ( delInUlScan == FALSE )
2903 /*Remove from DRX queue*/
2904 cmLListDelFrm(&(drxCell->drxQ[dlIndex].onDurationExpQ),
2905 &(drxUe->onDurationExpEnt));
2907 drxUe->onDurExpIndx = DRX_INVALID;
2912 /* Send the list to the scheduler to mark UE as inactive */
2913 cellSch = RG_SCH_CMN_GET_CELL(cell);
2914 cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
2917 }/*rgSCHDrxTtiHdlOnDurDl*/
2919 /** @brief This function handles the Dl HARQ timer's processing per TTI.
2922 * Invoked by - rgSCHDrxTtiHdlDlHarq
2924 * Function: rgSCHDrxTtiHdlDlHarqRTT
2927 * - In addition per TTI DRX module must look at Downlink HARQ queues
2928 * maintained to track HARQ RTT timer and drx-RetransmissionTimer.
2929 * Every TTI at the scheduling index we shall check these queues and
2930 * process accordingly.
2932 * @param RgSchCellCb *cellCb
2933 * @param U16 dlIndex
2938 PRIVATE Void rgSCHDrxTtiHdlDlHarqRTT
2944 PRIVATE Void rgSCHDrxTtiHdlDlHarqRTT(cell, dlIndex)
2950 RgSchDrxDlHqProcCb *drxHq;
2951 RgSchDlHqProcCb *dlHq;
2952 RgSchDRXCellCb *drxCell;
2953 RgSchDrxUeCb *drxUe;
2957 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
2958 RgSchCmnCell *cellSch = RG_SCH_CMN_GET_CELL(cell);
2962 TRC2(rgSCHDrxTtiHdlDlHarqRTT);
2964 drxCell = cell->drxCb;
2965 delInUlScan = drxCell->delInUlScan;
2967 /***********************************************************
2968 * Scanning harqRTTQ in DL
2969 ***********************************************************/
2971 cmLListInit(&dlInactvLst);
2972 node = drxCell->drxQ[dlIndex].harqRTTQ.first;
2976 dlHq = (RgSchDlHqProcCb*)node->node;
2980 if(TRUE == ue->isEmtcUe)
2985 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2986 drxUe = RG_SCH_DRX_GET_UE(ue);
2987 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2988 /* add the UE to the cell's retransmission queuee before starting
2989 * reTx timer, because this will not depend on retx timer trigger*/
2990 rgSCHUtlDlProcAddToRetx(dlHq->hqE->cell, dlHq);
2992 if ( delInUlScan == FALSE)
2994 cmLListDelFrm (&(drxCell->drxQ[dlIndex].harqRTTQ),
2995 &(drxHq->harqRTTEnt));
2997 drxHq->rttIndx = DRX_INVALID;
2999 /* ccpu00134565: Starting retransmission timer only if timerLen is
3000 * having non-zero value after reduction, Adding to Retx queue is
3001 * independent of starting retransmission timer. Hence if part will
3002 * take care of starting retx timer only*/
3003 if (drxUe->drxRetransTmrLen > drxHq->retxTmrReduction)
3005 /* add the harq proc to the re-tx queue--*/
3007 /* ccpu00134196-[Add]-DRX retx timer changes */
3008 rgSCHDrxCalcNxtTmrExpry(cell,
3011 drxUe->drxRetransTmrLen-drxHq->retxTmrReduction,
3012 NULLP, /*retransQ does not maintain distance*/
3017 /* ccpu00134196-[Add]-DRX retx timer changes */
3018 reTxExpIndx = ((dlIndex +
3019 drxUe->drxRetransTmrLen-drxHq->retxTmrReduction) %
3020 RG_SCH_MAX_DRXQ_SIZE);
3022 /* TODO. Workaround to avoid duplicate entry */
3023 if(drxHq->reTxIndx == DRX_INVALID)
3025 cmLListAdd2Tail (&(drxCell->drxQ[reTxExpIndx].harqRetxQ),
3026 &(drxHq->harqRetxEnt));
3028 drxHq->harqRetxEnt.node = (PTR)dlHq;
3029 drxHq->reTxIndx = reTxExpIndx;
3033 RLOG_ARG4(L_ERROR,DBG_CELLID,cell->cellId,"CRNTI:%d "
3034 "Adding Retx Node to expire at RetxIndx: %d at dlIndex %d "
3035 "drxHq->reTxIndx %d", ue->ueId, reTxExpIndx, dlIndex,
3039 /*mark the ue as active for downlink--*/
3040 drxUe->drxDlInactvMask &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3041 drxUe->drxDlInactvMaskPerCell[cellIdx] &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3043 /* Update UE's inactive mask and if required move UE to ACTIVE state */
3044 RG_SCH_CMN_DL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
3048 /***********************************************************
3049 * Scanning harqRetxQ in DL
3050 ***********************************************************/
3052 node = drxCell->drxQ[dlIndex].harqRetxQ.first;
3055 dlHq = (RgSchDlHqProcCb*)node->node;
3057 drxUe = RG_SCH_DRX_GET_UE(ue);
3059 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
3060 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
3062 /*mark the ue as in-active for downlink*/
3063 drxUe->drxDlInactvMaskPerCell[cellIdx] |= (RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3065 dlInactvMask = RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId;
3067 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
3069 dlInactvMask &= drxUe->drxDlInactvMaskPerCell[cellIdx];
3072 drxUe->drxDlInactvMask |= dlInactvMask;
3074 /* if no other condition is keeping ue active,
3077 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
3079 ue->dl.dlInactvMask |= (RG_DRX_INACTIVE);
3081 /* Add to DL inactive list */
3082 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
3083 ue->dlDrxInactvLnk.node = (PTR)ue;
3086 /*remove the harq proc from this queue*/
3087 if ( delInUlScan == FALSE)
3089 cmLListDelFrm (&(drxCell->drxQ[dlIndex].harqRetxQ),
3090 &(drxHq->harqRetxEnt));
3091 drxHq->reTxIndx = DRX_INVALID;
3094 /*Call schedulers to inactivate ue*/
3095 cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
3100 /** @brief This function handles the Ul HARQ timer's processing per TTI.
3103 * Invoked by - rgSCHDrxTtiHdlDlHarq
3105 * Function: rgSCHDrxTtiHdlUlHarqRTT
3108 * - In addition per TTI DRX module must look at Downlink HARQ queues
3109 * maintained to track HARQ RTT timer and drx-RetransmissionTimer.
3110 * Every TTI at the scheduling index we shall check these queues and
3111 * process accordingly.
3113 * - Though these timers are related to downlink HARQ processing, they
3114 * have an impact on uplink scheduling. The reason is that the UE,
3115 * if active for downlink scheduling implies that it is reading
3116 * PDCCHs i.e. we can still send uplink allocations to the UE. Hence
3117 * every TTI Uplink too would look at the harqRTTQ and harqRetxQ.
3121 * @param RgSchCellCb *cellCb
3122 * @param U16 ulIndex
3127 PRIVATE Void rgSCHDrxTtiHdlUlHarqRTT
3133 PRIVATE Void rgSCHDrxTtiHdlUlHarqRTT(cell, ulIndex)
3139 RgSchDrxDlHqProcCb *drxHq;
3140 RgSchDlHqProcCb *dlHq;
3141 RgSchDRXCellCb *drxCell;
3142 RgSchDrxUeCb *drxUe;
3145 CmLListCp ulInactvLst; /* list of UE's becoming DL-inactive */
3146 RgSchCmnCell *cellSch = RG_SCH_CMN_GET_CELL(cell);
3151 TRC2(rgSCHDrxTtiHdlUlHarqRTT);
3153 drxCell = cell->drxCb;
3154 delInUlScan = drxCell->delInUlScan;
3156 cmLListInit(&ulInactvLst);
3158 /***********************************************************
3159 * Scanning harqRTTQ in UL
3160 ***********************************************************/
3163 Though these timers are related to downlink HARQ processing, they
3164 have an impact on uplink scheduling. The reason is that the UE,
3165 if active for downlink scheduling implies that it is reading
3166 PDCCHs i.e. we can still send uplink allocations to the UE. Hence
3167 every TTI Uplink too would look at the harqRTTQ and harqRetxQ.
3170 node = drxCell->drxQ[ulIndex].harqRTTQ.first;
3173 dlHq = (RgSchDlHqProcCb*)node->node;
3175 drxUe = RG_SCH_DRX_GET_UE(ue);
3177 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
3178 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
3180 if ( delInUlScan == TRUE )
3182 /* remove the harq proc from this queue--*/
3183 cmLListDelFrm (&(drxCell->drxQ[ulIndex].harqRTTQ),
3184 &(drxHq->harqRTTEnt));
3186 drxHq->rttIndx = DRX_INVALID;
3189 /* mark the ue as active for uplink--*/
3190 drxUe->drxUlInactvMask &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3191 drxUe->drxUlInactvMaskPerCell[cellIdx] &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3193 /* Update UE's inactive mask and if required move UE to ACTIVE state */
3194 RG_SCH_CMN_UL_UPDT_INACTV_MASK( cell, ue, RG_DRX_INACTIVE);
3197 /***********************************************************
3198 * Scanning harqRetxQ in UL
3199 ***********************************************************/
3200 node = drxCell->drxQ[ulIndex].harqRetxQ.first;
3203 dlHq = (RgSchDlHqProcCb*)node->node;
3205 drxUe = RG_SCH_DRX_GET_UE(ue);
3206 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
3207 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
3209 /*mark the ue as in-active for uplink*/
3211 drxUe->drxUlInactvMaskPerCell[cellIdx] |= (RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3213 ulInactvMask = RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId;
3215 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
3217 ulInactvMask &= drxUe->drxUlInactvMaskPerCell[cellIdx];
3220 drxUe->drxUlInactvMask |= ulInactvMask;
3222 if(!RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
3224 ue->ul.ulInactvMask |= (RG_DRX_INACTIVE);
3226 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
3227 ue->ulDrxInactvLnk.node = (PTR)ue;
3230 /* remove the harq proc from this queue*/
3231 if ( delInUlScan == TRUE)
3233 cmLListDelFrm (&(drxCell->drxQ[ulIndex].harqRetxQ),
3234 &(drxHq->harqRetxEnt));
3235 drxHq->reTxIndx = DRX_INVALID;
3240 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
3246 /**********************************************************************
3249 **********************************************************************/