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"
51 /* header/extern include files (.x) */
52 #include "tfu.x" /* TFU types */
53 #include "lrg.x" /* layer management typedefs for MAC */
54 #include "rgr.x" /* layer management typedefs for MAC */
55 #include "rgm.x" /* layer management typedefs for MAC */
56 #include "rg_sch_inf.x" /* typedefs for Scheduler */
57 #ifdef LTEMAC_PH3_HDFDD
58 #include "rg_sch_hdfdd.x"
59 #endif /*LTEMAC_PH3_HDFDD*/
61 #include "rg_sch.x" /* typedefs for Scheduler */
62 #include "rg_sch_cmn.x"
65 * @file rg_sch_drx.c This file gives the describes the design for DRX feature.
67 * DRX is Discontinuous Reception i.e. the UE in order to save some battery
68 * would not monitor (decode) PDCCHs at all times. Instead the UE is configured
69 * with a periodically occuring duration wherein it shall monitor PDCCHs. The UE
70 * can be called ACTIVE at this time, this time is a minimum of a configurable
71 * value - onDuration and a maximum of Infinity.
73 * ACTIVE time MIN (onDuration) MAX (infinity)
75 * A sample configuration is periodicity of 10 subframes (ms) and an offset
76 * value of 3. This can be represented as the diagram given below. The portion
77 * marked as ACTIVE is the onDuration and the UE monitors PDCCHs.
81 * <-ACTIVE-><---IN-ACTIVE------><-ACTIVE-><---IN-ACTIVE--
83 * |__|__|__|--------|__|__|__|__|__|__|__|--------|__|__|__|__|__|
84 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
89 /******************************************************************************
90 * Structure definitions for TDD *
91 ******************************************************************************/
93 /** @brief : No of DL subframes in a particular TDD configuration
95 * @details : Special subframes in TDD can carry PDCCH if configured
96 * for DwPTS. For normal CP with subframe configruation (0-8)
97 * & extended CP with subframe configuration (0-6), Special
98 * Subframes can carry PDCCH and are represented in row 0.
99 * Extended CP with subframe configuraton (7-8), which do
100 * not carry PDCCH are represented in row 1.
101 * rgSchDrxDlSfTddCfg[1][2] represent number of DL subframes
102 * in TDD config 2 where DwPTS can carry PDCCH and
103 * rgSchDrxDlSfTddCfg[0][2] represent number of DL subframes
104 * in TDD config 2 where no DwPTS exits.
107 static uint8_t rgSchDrxDlSfTddCfg[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG] =
113 /** @brief : No of DL subframes till next SFN from a particular subframe
115 * @details :For a given Special subframe config
116 * (refer rgSchDrxDlSfTddCfg for an explanation) and given
117 * TDD config, how many DL subframes till Next SFN from this
122 static uint8_t rgSchDrxDLSfTillNxtSFN[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG]
123 [RGSCH_NUM_SUB_FRAMES]=
126 {2,1,1,1,1,1,0,0,0,0},
127 {4,3,3,3,3,2,1,1,1,1},
128 {6,5,5,5,4,3,2,2,2,1},
129 {6,5,5,5,5,5,4,3,2,1},
130 {7,6,6,6,6,5,4,3,2,1},
131 {8,7,7,7,6,5,4,3,2,1},
132 {3,2,2,2,2,2,1,1,1,1}
136 {4,3,2,2,2,2,1,0,0,0},
137 {6,5,4,4,4,3,2,1,1,1},
138 {8,7,6,6,5,4,3,2,1,1},
139 {7,6,5,5,5,5,4,3,2,1},
140 {8,7,6,6,6,5,4,3,2,1},
141 {9,8,7,7,6,5,4,3,2,1},
142 {5,4,3,3,3,3,2,1,1,1}
144 }; /*rgSchDrxDLSfTillNxtSFN*/
147 /** @brief : Lookup table for DL subframe given the number of subframes
149 * @details :For a given Special subframe config
150 * (refer rgSchDrxDlSfTddCfg for an explanation) and given
151 * TDD config, the DL subframe index given the number of subframes
155 static uint8_t rgSchDrxDLSftoDLSfIdx[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG]
156 [RGSCH_NUM_SUB_FRAMES]=
176 };/* rgSchdrxDLSftoDLSfIdx*/
177 /* ccpu00134196-[Add]-DRX retx timer changes */
178 /* The k+4 th subframe in TDD at which HARQ RTT expires may be an Uplink SF.
179 In such case, the drx retx timer may start at the next pdcch sf instead
181 uint8_t rgSchDrxHarqRetxFirstPsf[RGSCH_MAX_TDD_CFG][RGSCH_NUM_SUB_FRAMES] = {
182 {0, 0, 4, 0, 6, 0, 0, 4, 0, 6},
183 {0, 0, 4, 6, 0, 0, 0, 4, 6, 0},
184 {0, 0, 4, 0, 0, 0, 0, 4, 0, 0},
185 {0, 0, 4, 4, 4, 0, 0, 0, 0, 0},
186 {0, 0, 4, 4, 0, 0, 0, 0, 0, 0},
187 {0, 0, 4, 0, 0, 0, 0, 0, 0, 0},
188 {0, 0, 4, 6, 5, 0, 0, 4, 7, 0},
192 /******************************************************************************
193 * Start of Function declarations *
194 ******************************************************************************/
195 static Void rgSCHDrxTtiHdlOnDurUl ARGS((
199 static Void rgSCHDrxTtiHdlOnDurDl ARGS((
203 static Void rgSCHDrxTtiHdlDlHarqRTT ARGS((
207 static Void rgSCHDrxTtiHdlUlHarqRTT ARGS((
211 static S16 rgSCHDrxTtiHdlOnDur ARGS((RgSchCellCb *cellCb, uint16_t dlIndex,
213 static S16 rgSCHDrxTtiHdlInActv ARGS((RgSchCellCb *cellCb, uint16_t dlIndex,
215 static S16 rgSCHDrxTtiHdlShortCycle ARGS((RgSchCellCb *cell, uint16_t dlIndex,
217 static S16 rgSCHDrxTtiHdlDlHarq ARGS((RgSchCellCb *cellCb, uint16_t dlIndex,
219 static S16 rgSCHDrxCpyUeCfg ARGS((RgSchDrxUeCb *drxCb,
220 RgrUeDrxCfg* ueDrxCfg));
222 static S16 rgSCHDrxGetNxtOnDur ARGS((RgSchCellCb* cell,RgSchDrxUeCb* drxCb,
223 CmLteTimingInfo* nxtOnDur,
226 static Void rgSCHDrxMvToNxtOnDurOcc ARGS((RgSchCellCb* cell,
231 static Void rgSCHDrxCalcNxtTmrExpry ARGS((RgSchCellCb *cell,
238 static S16 rgSCHDrxGetNxtTmrExpry ARGS((RgSchCellCb *cell,uint16_t curTime,
240 CmLteTimingInfo* tmrExpryIdx));
243 S16 rgSCHEmtcDrxCpyUeCfg
248 S16 rgSCHDrxTtiHdlUlHarq
254 Void rgSCHDrxUeUlHqReset
263 /** @brief This function handles the per TTI handling of the DRX module.
264 * Invoked by rgSCHTti @sa rgSCHTti.
266 * @details This function goes through the drxQ and marks the UE as ACTIVE or
267 * INACTIVE based on the timers and thier status.
269 * Function: rgSCHDrxTtiInd
272 * - Processing is divided into respective timer handling.
273 * - Calculate the DL and UL indices as follows
275 * dlIndex = (cell->crntTime.sfn * 10 + cell->crntTime.slot +
276 * RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
278 * ulIndex = (cell->crntTime.sfn * 10 + cell->crntTime.slot +
279 * RG_SCH_DRX_UL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
281 * - Call rgSCHDrxTtiHdlOnDur to handle onDurationTimer handling
282 * - Call rgSCHDrxTtiHdlInActv to handle drx-InactivityTimer handling
283 * - Call rgSCHDrxTtiHdlShortCycle to handle Short cycle timer.
284 * - Call rgSCHDrxTtiHdlDlHarq to handle HARQ RTT and drx-retransmission
286 * - Call rgSchDrxTtiHdlUlHarq to handle Uplink HARQ processing -
287 * related to ACTIVITY when a UE is expecting a grant for an uplink
289 * - Post this processing the ueCb->dlInactvMask's DRX Bit shall be set
290 * or reset to denote ACTIVITY or INACTIVITY respectively.
291 * - Post this processing the ueCb->ulInactvMask's DRX Bit shall be set
292 * or reset to denote ACTIVITY or INACTIVITY respectively.
293 * - Add the UE to the list of Active/inactive UEs.
295 * @param RgSchCellCb *cell
296 * @param [out] CmLListCp *dlInactvLst List to which the DL in-active UEs are
300 Void rgSCHDrxTtiInd(RgSchCellCb *cell)
305 dlIndex = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot +
306 RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
308 ulIndex = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot +
309 RG_SCH_DRX_UL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
312 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex);
313 /* checks the Ul-Retransmission timer */
317 rgSCHDrxTtiHdlUlHarq (cell, dlIndex, ulIndex);
320 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex);
322 /*Process Short cycle expiry before On duration timer so that long cycles
323 * On Duration can be processed if timer has expired*/
324 rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex);
325 rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex);
328 rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex);
329 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex);
330 /* checks the Ul-Retransmission timer */
334 rgSCHDrxTtiHdlUlHarq (cell, dlIndex, ulIndex);
337 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex);
338 rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex);
346 /** @brief This function is called to handle onDurationTimer per TTI processing.
349 * Invoked by - rgSCHDrxTtiInd
351 * Function: rgSCHDrxTtiHdlOnDur
355 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
357 * - For Downlink we shall look at an index that is
358 * n + RG_SCH_DRX_DL_DELTA.
361 * - For Uplink we shall look at an index that is
362 * n + RG_SCH_DRX_UL_DELTA as
363 * we are concerned with the PDCCH and not the actual PUSCH.
366 * @param RgSchCellCb *cellCb
367 * @param uint16_t dlIndex
368 * @param uint16_t ulIndex
369 * @return ROK/RFAILED
372 static S16 rgSCHDrxTtiHdlOnDur(RgSchCellCb *cell,uint16_t dlIndex,uint16_t ulIndex)
375 #if ( ERRCLASS & ERRCLS_INT_PAR )
376 if ( cell == (RgSchCellCb* )NULLP )
382 rgSCHDrxTtiHdlOnDurDl(cell,dlIndex);
384 rgSCHDrxTtiHdlOnDurUl(cell, ulIndex);
388 }/*rgSCHDrxTtiHdlOnDur*/
391 /** @brief This function handles the processing for drxInactityTimer per TTI
394 * Invoked by - rgSCHDrxTtiInd
396 * Function: rgSCHDrxTtiHdlInActv
400 * - For Downlink we shall look at an index that is
401 * n + RG_SCH_DRX_DL_DELTA of the drxQ.
403 * - MARK UE AS INACTIVE BASED ON DRX-INACTIVITY TIMER EXPIRY
406 * - For Uplink we shall look at an index that is
407 * n + RG_SCH_DRX_UL_DELTA as
408 * we are concerned with the PDCCH and not the actual PUSCH.
411 * @param RgSchCellCb *cellCb
412 * @param uint16_t dlIndex
413 * @param uint16_t ulIndex
414 * @return ROK/RFAILED
417 S16 rgSCHDrxTtiHdlInActv(RgSchCellCb *cell,uint16_t dlIndex,uint16_t ulIndex)
420 RgSchDRXCellCb *drxCell=NULLP;
422 RgSchDrxUeCb *drxUe=NULLP;
423 uint16_t shrtCycleExpIndx;
424 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
425 CmLListCp ulInactvLst; /* list of UE's becoming UL-inactive */
426 RgSchCmnCell *cellSch = NULLP;
427 Bool delInUlScan = FALSE;
429 #if ( ERRCLASS & ERRCLS_INT_PAR )
430 if ( cell == (RgSchCellCb* )NULLP)
437 drxCell = (cell->drxCb);
438 delInUlScan = drxCell->delInUlScan;
441 /***********************************************************
442 * Scanning inActvitiyQ in DL
443 ***********************************************************/
445 /* The DL loop will scan for UE's whose inactivity timer has
446 * expired. It will switch the cycle to short or long based
447 * on the cycle configured.
448 * Furhter,if !delInUlScan, then will remove the UE from the
452 node = drxCell->drxQ[dlIndex].inActvTmrQ.first;
454 /* Initialize DL inactive list */
455 cmLListInit(&dlInactvLst);
457 /* Initialize UL inactive list */
458 cmLListInit(&ulInactvLst);
462 ue = (RgSchUeCb*)node->node;
464 drxUe = RG_SCH_DRX_GET_UE(ue);
466 if ( delInUlScan == TRUE)
468 drxUe->drxInactDistance--;
471 if ( drxUe->drxInactDistance != DRX_TMR_EXPRD )
476 /* UE is inactive as inactivity timer has expired */
477 drxUe->drxDlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
480 /* update the ue mask only if no condition in drx
481 * is keeping ue active
483 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
485 /* set the UE has DRX inactive */
486 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
488 /* Add to DL inactive list */
489 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
490 ue->dlDrxInactvLnk.node = (PTR)ue;
493 /*Remove from the queue if !delInUlScan */
494 if( delInUlScan == FALSE )
496 cmLListDelFrm(&(drxCell->drxQ[dlIndex].inActvTmrQ),
497 &(drxUe->inActvTmrEnt));
499 drxUe->drxInactvIndx = DRX_INVALID;
501 }/* if (delInUlScan == FALSE) */
503 if (drxUe->isShortCycleCfgd)
505 /* add shorty cycle expirty */
506 drxUe->isLongCycle = FALSE;
508 shrtCycleExpIndx = (dlIndex + (drxUe->shortCycleTmrLen *
509 drxUe->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
511 drxUe->drxShortCycleDistance = (drxUe->shortCycleTmrLen *
512 drxUe->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
514 /*Remove the UE from existing index*/
515 if (drxUe->shortCycleIndx != DRX_INVALID)
517 cmLListDelFrm(&(drxCell->drxQ[drxUe->shortCycleIndx].shortCycleQ),
518 &(drxUe->shortCycleEnt));
521 cmLListAdd2Tail(&(drxCell->drxQ[shrtCycleExpIndx].shortCycleQ),
522 &(drxUe->shortCycleEnt));
524 drxUe->shortCycleEnt.node = (PTR)ue;
525 drxUe->shortCycleIndx = shrtCycleExpIndx;
527 /*Calculate onDuration again & move the
528 * ueCb to the next Onduration occurence
531 /*we maybe at any position in the RF timeline,
532 * need to calculate onDuration from the starting
535 rgSCHDrxMvToNxtOnDurOcc(cell,ue,RG_SCH_DRX_DL_DELTA,TRUE);
537 }/*isShortCycleCfgd */
540 /* use the long cycle */
541 drxUe->isLongCycle = TRUE;
547 /***********************************************************
548 * Scanning inActvitiyQ in UL
549 ***********************************************************/
551 /* The UL loop will scan for UE's whose inactivity timer has
552 * expired and mark the UE's UL inactive.
553 * Furhter,if delInUlScan, then will remove the UE from the
557 /* For Uplink we shall look at an index that is n + RG_SCH_DRX_UL_DELTA as
558 we are concerned with the PDCCH and not the actual PUSCH.*/
562 node = drxCell->drxQ[ulIndex].inActvTmrQ.first;
567 ue = (RgSchUeCb*)node->node;
569 drxUe = RG_SCH_DRX_GET_UE(ue);
571 if ( delInUlScan == FALSE)
573 drxUe->drxInactDistance--;
576 if ( drxUe->drxInactDistance != DRX_TMR_EXPRD )
581 /* Need to mark the UE as inactive due to expiry of
582 * DRX inactivity timer */
584 /* UE is inactive as inactivity timer has expired */
585 drxUe->drxUlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
587 /* update the ue mask only if no other condition in
588 * drx is keeping ue active */
590 if (!RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
592 /* set the inactivity bit */
593 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
595 /* Add to Ul inactive list */
596 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
597 ue->ulDrxInactvLnk.node = (PTR)ue;
600 if ( delInUlScan == TRUE)
602 /* remove from queue */
603 cmLListDelFrm(&(drxCell->drxQ[ulIndex].inActvTmrQ),
604 &(drxUe->inActvTmrEnt));
606 drxUe->drxInactvIndx = DRX_INVALID;
608 }/* if ( delInUlScan == TRUE) */
609 }/*while(node) for uplink */
612 /* Send the list to the scheduler to mark UE as inactive in UL*/
613 cellSch = RG_SCH_CMN_GET_CELL(cell);
614 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
616 /* Send the DL inactive list to the scheduler to mark UE as inactive */
617 cellSch = RG_SCH_CMN_GET_CELL(cell);
618 cellSch->apisDl->rgSCHDlInactvtUes(cell,&dlInactvLst);
621 }/*rgSCHDrxTtiHdlInActv*/
623 /** @brief This function handles the per TTI processing for DRX short cycle
627 * Invoked by - rgSCHDrxTtiInd
629 * Function: rgSCHDrxTtiHdlShortCycle
634 * in addition we have to mark the ues based on drx short cycle
638 * @param RgSchCellCb *cell
639 * @param uint16_t dlIndex
640 * @param uint16_t ulIndex
641 * @return ROK/RFAILED
644 S16 rgSCHDrxTtiHdlShortCycle(RgSchCellCb *cell,uint16_t dlIndex,uint16_t ulIndex)
647 RgSchDRXCellCb *drxCell=NULLP;
649 RgSchDrxUeCb *drxUe=NULLP;
651 #if ( ERRCLASS & ERRCLS_INT_PAR )
652 if ( cell == (RgSchCellCb* )NULLP )
661 drxCell = RG_SCH_DRX_GET_CELL(cell);
663 node = drxCell->drxQ[dlIndex].shortCycleQ.first;
667 ue = (RgSchUeCb*)node->node;
669 drxUe = RG_SCH_DRX_GET_UE(ue);
671 if ( --drxUe->drxShortCycleDistance != DRX_TMR_EXPRD)
676 /* mark the UE's current cycle to be long */
677 drxUe->isLongCycle = TRUE;
679 /* remove from the shortCycleQ */
681 cmLListDelFrm(&(drxCell->drxQ[dlIndex].shortCycleQ),
682 &(drxUe->shortCycleEnt));
683 drxUe->shortCycleIndx = DRX_INVALID;
685 /* Remove from onDuration queue inserted based on short cycle
686 * and calculate onDuration based on long cycle.*/
687 rgSCHDrxMvToNxtOnDurOcc(cell,ue,RG_SCH_DRX_DL_DELTA,TRUE);
691 }/*rgSCHDrxTtiHdlShortCycle*/
694 /** @brief This function handles the HARQ timer's processing per TTI.
697 * Invoked by - rgSCHDrxTtiInd
699 * Function: rgSCHDrxTtiHdlDlHarq
702 * - In addition per TTI DRX module must look at Downlink HARQ queues
703 * maintained to track HARQ RTT timer and drx-RetransmissionTimer.
704 * Every TTI at the scheduling index we shall check these queues and
705 * process accordingly.
708 * - Though these timers are related to downlink HARQ processing, they
709 * have an impact on uplink scheduling. The reason is that the UE,
710 * if active for downlink scheduling implies that it is reading
711 * PDCCHs i.e. we can still send uplink allocations to the UE. Hence
712 * every TTI Uplink too would look at the harqRTTQ and harqRetxQ.
716 * @param RgSchCellCb *cellCb
717 * @param uint16_t dlIndex
718 * @param uint16_t ulIndex
719 * @return ROK/RFAILED
722 static S16 rgSCHDrxTtiHdlDlHarq(RgSchCellCb *cell,uint16_t dlIndex,uint16_t ulIndex)
725 #if ( ERRCLASS & ERRCLS_INT_PAR)
726 if ( cell == (RgSchCellCb *)NULLP )
730 #endif /*ERRCLASS & ERRCLS_INT_PAR*/
733 rgSCHDrxTtiHdlDlHarqRTT(cell, dlIndex);
735 rgSCHDrxTtiHdlUlHarqRTT(cell, ulIndex);
740 /** @brief This function is called by the common scheduler as part of
741 * finalization of allocations in downlink.
746 * Function: rgSchDrxStrtInActvTmr
748 * This function is responsible to starting drx-InactivityTimer
753 * @param RgSchCellCb *cell
754 * @param CmLListCp *ueUlLst
755 * @param uint8_t direction
759 Void rgSCHDrxStrtInActvTmr(RgSchCellCb *cell,CmLListCp *ueLst,uint8_t direction)
764 RgSchDrxUeCb *ueDrxCb;
768 uint16_t inActvTmrExpIndx;
770 uint16_t curTimeInSf; /* current time in number of subframes */
775 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
776 CmLListCp ulInactvLst; /* list of UE's becoming UL-inactive */
777 RgSchCmnCell *cellSch = NULLP;
778 Bool delInUlScan = FALSE;
780 if ( direction == RG_SCH_DRX_UL)
783 curTimeInSf = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
784 (cell->crntTime.slot) +RG_SCH_DRX_UL_DELTA;
788 delta = RG_SCH_DRX_UL_DELTA;
794 curTimeInSf = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
795 (cell->crntTime.slot) + RG_SCH_DRX_DL_DELTA;
799 delta = RG_SCH_DRX_DL_DELTA;
804 /* Initialize DL inactive list */
805 cmLListInit(&dlInactvLst);
807 /* Initialize UL inactive list */
808 cmLListInit(&ulInactvLst);
810 delInUlScan = cell->drxCb->delInUlScan;
813 index1 = (curTimeInSf) % RG_SCH_MAX_DRXQ_SIZE;
820 ueCb = (RgSchUeCb *)node->node;
821 ueDrxCb = ueCb->drxCb;
823 /* Stop inactivity timer */
824 if ( ueDrxCb->drxInactvIndx != DRX_INVALID )
826 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->drxInactvIndx].inActvTmrQ),
827 &(ueDrxCb->inActvTmrEnt));
831 rgSCHDrxCalcNxtTmrExpry(cell,
834 ueDrxCb->inactvtyTmrLen,
835 &(ueDrxCb->drxInactDistance),
840 inActvTmrExpIndx = (index1 + ueDrxCb->inactvtyTmrLen)
841 % RG_SCH_MAX_DRXQ_SIZE;
843 ueDrxCb->drxInactDistance = ueDrxCb->inactvtyTmrLen
844 / RG_SCH_MAX_DRXQ_SIZE;
847 cmLListAdd2Tail(&(cell->drxCb->drxQ[inActvTmrExpIndx].inActvTmrQ),
848 &(ueDrxCb->inActvTmrEnt));
850 ueDrxCb->inActvTmrEnt.node = (PTR)ueCb;
852 ueDrxCb->drxInactvIndx = inActvTmrExpIndx;
854 /* Update DRX InActive both masks */
855 ueDrxCb->drxUlInactvMask &= ~RG_SCH_DRX_INACTVTMR_BITMASK;
856 ueDrxCb->drxDlInactvMask &= ~RG_SCH_DRX_INACTVTMR_BITMASK;
858 /* Update UE's Inactive masks */
859 ueCb->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
860 ueCb->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
862 if ( delInUlScan == TRUE)
864 if ( ueDrxCb->inactvtyTmrLen == RGR_DRX_PRD_1PSF)
866 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
867 ueDrxCb->drxDlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
869 /* if no other condition is keeping ue inactive,
872 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(ueDrxCb) )
874 ueCb->dl.dlInactvMask |= RG_DRX_INACTIVE;
876 /* Add to DL inactive list */
877 cmLListAdd2Tail(&dlInactvLst,&(ueCb->dlDrxInactvLnk));
878 ueCb->dlDrxInactvLnk.node = (PTR)ueCb;
880 }/*if ( ueDrxCb->inactvyTmrLen...*/
882 }/*delInUlScan==TRUE*/
885 if ( ueDrxCb->inactvtyTmrLen == RGR_DRX_PRD_1PSF )
887 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
888 ueDrxCb->drxUlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
889 /* if no other condition is keeping ue inactive,
892 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(ueDrxCb) )
894 ueCb->ul.ulInactvMask |= RG_DRX_INACTIVE;
896 if ( !RG_SCH_CMN_UL_IS_UE_ACTIVE(ueCb))
898 /* Add to UL inactive list */
899 cmLListAdd2Tail(&ulInactvLst,&(ueCb->ulDrxInactvLnk));
900 ueCb->ulDrxInactvLnk.node = (PTR)ueCb;
902 }/*if ( !RG_SCH_DRX....)*/
903 }/*if (ueDrxCb->inactv...*/
906 /* move the link list forward */
910 cmLListDelFrm(ueLst, delNode);
911 delNode->node = NULLP;
915 /* Send the list to the scheduler to mark UE as inactive in UL*/
916 cellSch = RG_SCH_CMN_GET_CELL(cell);
917 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
919 /* Send the DL inactive list to the scheduler to mark UE as inactive */
920 cellSch = RG_SCH_CMN_GET_CELL(cell);
921 cellSch->apisDl->rgSCHDlInactvtUes(cell,&dlInactvLst);
924 }/*rgSCHDrxStrtInActvTmr*/
926 /** @brief This function is called by the downlink HARQ module on receiving a
927 * negative feedback from the UE for a PDSCH transmission.
930 * Invoked by - rgSCHDhmHqTrnsFail
932 * Function: rgSCHDrxStartHarqRTTTmr
937 * @param RgSchCellCb *cell
938 * @param RgSchDlHqProcCb *dlHq
939 * @param uint8_t tbCnt
942 Void rgSCHDrxStartHarqRTTTmr(RgSchCellCb *cell,RgSchDlHqProcCb *hqP,uint8_t tbCnt)
944 RgSchDRXCellCb *drxCell =NULLP;
945 RgSchDrxDlHqProcCb *drxHq =NULLP;
946 uint16_t harqRTTExpIndx;
949 uint8_t firstDlTxOcassion;
950 uint8_t drxRetxTmrStartSf;
953 drxCell = RG_SCH_DRX_GET_CELL(cell);
954 drxHq = RG_SCH_DRX_GET_DL_HQ(hqP);
957 /* ccpu00134196-[Add]-DRX retx timer changes */
958 firstDlTxOcassion = rgSchDrxHarqRetxFirstPsf[cell->ulDlCfgIdx]
959 [hqP->tbInfo[tbCnt].fdbkTime.subframe];
961 harqRTTExpIndx = ((hqP->tbInfo[tbCnt].fdbkTime.sfn * 10) +
962 hqP->tbInfo[tbCnt].fdbkTime.subframe + firstDlTxOcassion)
963 % RG_SCH_MAX_DRXQ_SIZE;
965 fdbkDelta = RGSCH_CALC_SF_DIFF(cell->crntTime, hqP->tbInfo[tbCnt].fdbkTime);
968 /* For FDD HARQ RTT expiry index is 8 subframes from the time
969 * corresponding PDSCH was scheduled. We are adding 1 subframe
970 * so that UE is scheduled for retransmission in the next subframe*/
971 /* ccpu00134196-[Add]-DRX retx timer changes */
972 harqRTTExpIndx = ((hqP->tbInfo[tbCnt].timingInfo.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
973 hqP->tbInfo[tbCnt].timingInfo.slot + RG_SCH_MIN_HARQ_RTT)
974 % RG_SCH_MAX_DRXQ_SIZE;
976 fdbkDelta = RGSCH_CALC_SF_DIFF(cell->crntTime, hqP->tbInfo[tbCnt].timingInfo);
978 /* ccpu00134196-[Add]-DRX retx timer changes */
979 /* ensure that the insertion into the queue happens at an index
980 greater than the dl index, ie, do +1 */
981 /* Instead of depending on TTI details of current time and HARQ RTT Expire
982 * time, Handling this check with deltas, because with TTIs it is not possible
983 * to handle wrap-around condition*/
985 if(fdbkDelta + RG_SCH_DRX_DL_DELTA >= firstDlTxOcassion)
987 /* The retx timer length should be reduced.
988 This means based on the platforms delta between the DL HARQ
989 processing and DL scheduling, drx retx timer lengths of 1ms/2ms
990 may not be possible */
991 drxRetxTmrStartSf = (hqP->tbInfo[tbCnt].fdbkTime.subframe +
992 firstDlTxOcassion) % RGSCH_NUM_SUB_FRAMES;
994 /* We are here because the Retx Timer start is moved by atleast one
995 position. Hence the timer will be reduced by minimum one */
996 drxHq->retxTmrReduction = 1;
998 /* Now check the consecutive subframes starting from the actual
999 starting position of the retx tmr till the new position. Reduce the
1000 timer value only if the sf is a Pdcch sf */
1001 for(i = 1; i <= fdbkDelta + RG_SCH_DRX_DL_DELTA-firstDlTxOcassion+ 1; i++)
1003 if (rgSchTddUlDlSubfrmTbl[cell->ulDlCfgIdx]
1004 [(drxRetxTmrStartSf+i)%RGSCH_NUM_SUB_FRAMES]
1005 != RG_SCH_TDD_UL_SUBFRAME)
1007 drxHq->retxTmrReduction++;
1011 if(fdbkDelta + RG_SCH_DRX_DL_DELTA >= RG_SCH_MIN_HARQ_RTT)
1013 drxHq->retxTmrReduction =
1014 fdbkDelta + RG_SCH_DRX_DL_DELTA - RG_SCH_MIN_HARQ_RTT+ 1;
1017 harqRTTExpIndx = (harqRTTExpIndx + drxHq->retxTmrReduction) %
1018 RG_SCH_MAX_DRXQ_SIZE;
1022 drxHq->retxTmrReduction = 0;
1024 cmLListAdd2Tail (&(drxCell->drxQ[harqRTTExpIndx].harqRTTQ),
1025 &(drxHq->harqRTTEnt));
1027 drxHq->harqRTTEnt.node = (PTR)hqP;
1028 drxHq->rttIndx = harqRTTExpIndx;
1032 }/*rgSCHDrxStartHarqRTTTmr*/
1035 /** @brief This function is called by the Configuration module to give a
1036 * trigger to DRX module for UE configuration.
1040 * Function: rgSCHDrxUeCfg
1043 * - Copy configuration information into drxUe structure.
1044 * - Calculate the first occurance of onDuration based on values
1045 * provided in the configuration structure.
1046 * - Append the UE to the onDurationQ at that index.
1047 * - The UE must be appened to the list based on the timing calculated
1048 * above (nxtSfn, nxtSubframe).
1050 * @param RgSchCellCb *cell Cell control block.
1051 * @param RgSchUeCb *ue UE control block.
1052 * @param RgrUeCfg *ueCfg RGR UE configuration information.
1057 S16 rgSCHDrxUeCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeCfg *ueCfg)
1060 RgSchDrxUeCb *ueDrxCb;
1061 CmLteTimingInfo nxtOnDur;
1063 uint16_t nxtOnDurTime;
1068 #if ( ERRCLASS & ERRCLS_INT_PAR )
1069 if ( cell == (RgSchCellCb* )NULLP)
1074 if ((ue == (RgSchUeCb* )NULLP)
1076 (ueCfg == (RgrUeCfg* )NULLP))
1078 DU_LOG("\nERROR --> SCH : rgSCHDrxUeCfg():"
1079 "Invalid params.cell or ue or ueCfg is NULL ");
1085 /* allocate and initialize drxCb */
1086 ret = rgSCHUtlAllocSBuf(cell->instIdx, (Data**)&ue->drxCb,
1087 (sizeof(RgSchDrxUeCb)));
1091 DU_LOG("\nERROR --> SCH : Memory allocation FAILED for DRX UECB CRBTI:%d",ue->ueId);
1095 ueDrxCb = ue->drxCb;
1097 /* initialize the masks */
1098 ueDrxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1099 ueDrxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1100 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
1101 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
1103 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1105 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1106 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1109 /* Copy the configuration values into the UE's DRX CB. */
1110 rgSCHDrxCpyUeCfg (ueDrxCb, &ueCfg->ueDrxCfg);
1114 rgSCHEmtcDrxCpyUeCfg(ue ,&ueCfg->ueDrxCfg);
1118 /* set all indexes to default values */
1119 ueDrxCb->onDurIndx = DRX_INVALID;
1120 ueDrxCb->onDurExpIndx = DRX_INVALID;
1121 ueDrxCb->drxInactvIndx = DRX_INVALID;
1122 ueDrxCb->shortCycleIndx = DRX_INVALID;
1124 /* set all distances to timer expiry */
1125 ueDrxCb->onDurExpDistance = DRX_TMR_EXPRD;
1126 ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
1127 ueDrxCb->drxShortCycleDistance = DRX_TMR_EXPRD;
1128 ueDrxCb->distance = DRX_TMR_EXPRD;
1130 /* Mark the UE in long/short cycle initially as per configuration*/
1131 if(FALSE == ueDrxCb->isShortCycleCfgd)
1133 ueDrxCb->isLongCycle = TRUE;
1137 ueDrxCb->isLongCycle = FALSE;
1140 /* Calculate the next occurance from this point */
1141 rgSCHDrxGetNxtOnDur (cell, ueDrxCb, &nxtOnDur,RG_SCH_NO_DELTA);
1144 nxtOnDurTime = ((nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur.slot);
1145 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1146 cell->crntTime.slot);
1148 onDurIndx = nxtOnDurTime % RG_SCH_MAX_DRXQ_SIZE;
1150 ueDrxCb->distance = (nxtOnDurTime - curTime) / RG_SCH_MAX_DRXQ_SIZE;
1151 if (ueDrxCb->distance < 0)
1153 DU_LOG("\nERROR --> SCH : DRXUE. Invalid "
1154 "value for distance, %d CRNTI:%d", ueDrxCb->distance,ue->ueId);
1156 //DU_LOG("\nDEBUG --> SCH : The onduartion index is: %d\n",(int)onDurIndx);
1157 cmLListAdd2Tail(&(cell->drxCb->drxQ[onDurIndx].onDurationQ),
1158 &(ueDrxCb->onDurationEnt));
1160 ueDrxCb->onDurationEnt.node = (PTR)ue;
1161 ueDrxCb->onDurIndx = onDurIndx;
1163 /* Starting Short Cycle Timer */
1164 if(TRUE == ueDrxCb->isShortCycleCfgd)
1166 ueDrxCb->drxShortCycleDistance = (ueDrxCb->shortCycleTmrLen *
1167 ueDrxCb->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
1168 ueDrxCb->shortCycleIndx = (curTime + (ueDrxCb->shortCycleTmrLen *
1169 ueDrxCb->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
1170 cmLListAdd2Tail(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1171 &(ueDrxCb->shortCycleEnt));
1172 ueDrxCb->shortCycleEnt.node = (PTR)ue;
1176 } /* end of rgSCHDrxUeCfg */
1178 /** @brief This function gets the next occurance of onDurationTimer from the
1181 * @details rgSCHDrxGetNxtOnDur
1183 * Function: rgSCHDrxGetNxtOnDur
1185 * Processing steps: -
1186 * Calculation of first occurance of onDuration is to be done as
1188 * Assume DRX configuration came at subframe (x, y) the periodicity is
1189 * offset = (perd, offset).
1190 * The (sfn, subframe) satisfying the following condition is the first
1191 * occurance from this point.
1193 * (sfn * 10 + subframe) mod perd = offset
1198 * @param RgSchCellCb *cell
1199 * @param RgSchDrxUeCb *drxCb
1200 * @param CmLteTimingInfo *nxtOnDur
1201 * @param uint8_t delta
1202 * @return ROK/RFAILED
1204 static S16 rgSCHDrxGetNxtOnDur(RgSchCellCb *cell,RgSchDrxUeCb *drxCb,CmLteTimingInfo *nxtOnDur,uint8_t delta)
1209 uint32_t numOfCycles;
1213 #if ( ERRCLASS & ERRCLS_INT_PAR )
1214 if ( cell == (RgSchCellCb* )NULLP )
1219 if( (drxCb == (RgSchDrxUeCb* )NULLP)
1221 (nxtOnDur == (CmLteTimingInfo* )NULLP)
1224 DU_LOG("\nERROR --> SCH : rgSCHDrxGetNxOnDur():Invalid params."
1225 "cell/drxCb/nxtOnDur is NULL");
1231 if (TRUE == drxCb->isLongCycle)
1233 cycleLen = drxCb->longDrxCycle;
1237 cycleLen = drxCb->shortDrxCycle;
1240 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) + cell->crntTime.slot);
1242 curTime += delta; /*TODO: see if we need to take care of wrap arounds */
1244 if ( curTime <= drxCb->drxStartOffset )
1246 /* offset is the nextOnDur */
1247 nxtOnDur->sfn = drxCb->drxStartOffset / RGSCH_NUM_SUB_FRAMES_5G;
1248 nxtOnDur->slot = (uint8_t)(drxCb->drxStartOffset % RGSCH_NUM_SUB_FRAMES_5G);
1249 nxtDist = ((nxtOnDur->sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur->slot);
1253 curDist = curTime - drxCb->drxStartOffset;
1255 numOfCycles = curDist / cycleLen;
1257 if (0 == (curDist % cycleLen))
1259 /* Perfect match pick up the current time */
1260 /*nxtOnDur should be set to equal to currentTime + DELTA */
1261 nxtOnDur->sfn = (uint16_t)curTime / RGSCH_NUM_SUB_FRAMES_5G;
1262 nxtOnDur->slot = (uint16_t)curTime % RGSCH_NUM_SUB_FRAMES_5G;
1263 nxtDist = ((nxtOnDur->sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur->slot);
1268 nxtDist = drxCb->drxStartOffset + (numOfCycles + 1) *
1270 nxtOnDur->sfn = (uint16_t)nxtDist / RGSCH_NUM_SUB_FRAMES_5G;
1271 nxtOnDur->slot = (uint16_t)nxtDist % RGSCH_NUM_SUB_FRAMES_5G;
1276 /*If next On Duration is less than DL DELTA ahead, we will miss it and
1277 * hence need to move to the On-Duration after that.*/
1278 if((nxtDist - (curTime - delta)) <= RG_SCH_DRX_MAX_DELTA)
1280 nxtDist = nxtDist + cycleLen;
1281 nxtOnDur->sfn = (uint16_t)nxtDist / RGSCH_NUM_SUB_FRAMES_5G;
1282 nxtOnDur->slot = (uint16_t)nxtDist % RGSCH_NUM_SUB_FRAMES_5G;
1285 } /* end of rgSCHDrxGetNxtOnDur */
1287 /** @brief This function is a utility function to copy the UE configuration from
1288 * the RGR structure to the UE control block.
1291 * -Invoked by rgSCHDrxUeCfg
1293 * Function: rgSCHDrxCpyUeCfg
1296 * - Copies configuration values
1298 * @param RgSchDrxUeCb *ueCb
1299 * @param RgrUeDrxCfg *drxCfg
1300 * @return ROK/RFAILED
1302 static S16 rgSCHDrxCpyUeCfg(RgSchDrxUeCb *ueCb,RgrUeDrxCfg *drxCfg)
1305 #if ( ERRCLASS & ERRCLS_INT_PAR )
1306 if ( (ueCb == (RgSchDrxUeCb* )NULLP )
1308 (drxCfg == (RgrUeDrxCfg* )NULLP)
1316 /* Copy all values to UE control block */
1318 ueCb->cqiMask = drxCfg->cqiMask;
1319 #endif /*LTEMAC_R9*/
1320 ueCb->onDurTmrLen = drxCfg->drxOnDurTmr;
1321 ueCb->inactvtyTmrLen = drxCfg->drxInactvTmr;
1322 ueCb->drxRetransTmrLen = drxCfg->drxRetxTmr;
1323 ueCb->longDrxCycle = drxCfg->drxLongCycleOffst.longDrxCycle;
1324 ueCb->drxStartOffset = drxCfg->drxLongCycleOffst.drxStartOffst;
1325 ueCb->isShortCycleCfgd = drxCfg->drxShortDrx.pres;
1326 ueCb->shortDrxCycle = drxCfg->drxShortDrx.shortDrxCycle;
1327 ueCb->shortCycleTmrLen = drxCfg->drxShortDrx.drxShortCycleTmr;
1330 } /* end of rgSCHDrxCpyUeCfg */
1333 /** @brief This function is called by the configuration module when a UE is
1334 * reconfigured for DRX parameters.
1337 * Invoked By - rgSCHCfgRgrUeCfg
1339 * Function: rgSCHDrxUeReCfg
1340 * As per MAC specifications the new values of timers shall be applied only once
1341 * they are restarted, hence no processing is required for modified timer values.
1344 * - if offset and/or drxCycleLenght changes then recalculate the next
1346 * - remove the UE from current index
1347 * - add the UE to the new index.
1348 * - if short cycle is enabled
1349 * - set isShortCycleCfgd = TRUE
1351 * @param RgSchCellCb *cell
1352 * @param RgSchUeCb *ue
1353 * @param RgrUeRecfg *ueReCfg
1354 * @return ROK/RFAILED
1356 S16 rgSCHDrxUeReCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeRecfg *ueReCfg)
1359 RgSchCmnCell *cellSch = NULLP;
1360 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
1362 Inst instIdx = cell->instIdx;
1363 RgSchDrxUeCb *ueDrxCb;
1364 CmLteTimingInfo nxtOnDur;
1365 uint16_t nxtOnDurTime;
1368 uint16_t shrtCycleExpIndx;
1369 uint16_t onDurExpTime;
1375 /* drx was disabled but now enabled for this ue */
1376 if ( (ue->isDrxEnabled == FALSE)
1378 (ueReCfg->ueDrxRecfg.isDrxEnabled == TRUE)
1381 /* allocated and initialize drxCb */
1382 ret = rgSCHUtlAllocSBuf(instIdx, (Data**)&ue->drxCb,
1383 (sizeof(RgSchDrxUeCb)));
1387 DU_LOG("\nERROR --> SCH : rgSCHdrxUeReCfg():""Memory allocation FAILED for DRX UE Cb CRNTI:%d",
1392 ue->isDrxEnabled = TRUE; /* sachin */
1393 /* initialize the masks */
1394 ue->drxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1395 ue->drxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1396 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
1397 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
1399 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1401 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1402 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1405 /* set all indexes to default values */
1406 ue->drxCb->onDurIndx = DRX_INVALID;
1407 ue->drxCb->onDurExpIndx = DRX_INVALID;
1408 ue->drxCb->drxInactvIndx = DRX_INVALID;
1409 ue->drxCb->shortCycleIndx = DRX_INVALID;
1411 /* set all distances to timer expiry */
1412 ue->drxCb->onDurExpDistance = DRX_TMR_EXPRD;
1413 ue->drxCb->drxInactDistance = DRX_TMR_EXPRD;
1414 ue->drxCb->drxShortCycleDistance = DRX_TMR_EXPRD;
1415 ue->drxCb->distance = DRX_TMR_EXPRD;
1418 if( ue->drxCb == NULLP )
1422 ueDrxCb = ue->drxCb;
1424 /*drx was enabled but now disabled for this UE */
1425 if ( (ue->isDrxEnabled == TRUE )
1427 (ueReCfg->ueDrxRecfg.isDrxEnabled == FALSE)
1430 /* remove UE from all DRX Queues */
1431 (Void)rgSCHDrxUeDel(cell,ue);
1434 /* ccpu00117052 - MOD - Passing double pointer
1435 for proper NULLP assignment*/
1436 rgSCHUtlFreeSBuf(instIdx,(Data **)(&((ue->drxCb))),
1437 sizeof(RgSchDrxUeCb));
1439 /* Resetting the DRX Bit set in Inactv Mask */
1440 ue->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
1441 ue->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
1443 ue->isDrxEnabled = FALSE;
1445 }/*isDrxEnabled == FALSE */
1448 /* If Application is updating DRX params */
1449 if (ueReCfg->ueRecfgTypes & RGR_UE_DRX_RECFG )
1451 rgSCHDrxCpyUeCfg (ueDrxCb, &ueReCfg->ueDrxRecfg);
1455 rgSCHEmtcDrxCpyUeCfg(ue, &ueReCfg->ueDrxRecfg);
1461 /* Removing the UE from existing index of shortcycle, if any*/
1462 if(ueDrxCb->shortCycleIndx != DRX_INVALID)
1464 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1465 &(ueDrxCb->shortCycleEnt));
1467 ueDrxCb->shortCycleEnt.node = (PTR) NULLP;
1468 ueDrxCb->shortCycleIndx = DRX_INVALID;
1471 /* Mark for intiating long/short cycle as per received config */
1472 if(FALSE == ue->drxCb->isShortCycleCfgd)
1474 ue->drxCb->isLongCycle = TRUE;
1478 ue->drxCb->isLongCycle = FALSE;
1481 /* Calculate the next occurance from this point */
1482 rgSCHDrxGetNxtOnDur (cell, ueDrxCb, &nxtOnDur,RG_SCH_NO_DELTA);
1484 /* remove the UE from the current onDuration Queue */
1485 if ( ueDrxCb->onDurIndx != DRX_INVALID )
1487 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurIndx].onDurationQ),
1488 &(ueDrxCb->onDurationEnt));
1492 nxtOnDurTime = (nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur.slot;
1493 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1494 cell->crntTime.slot);
1496 /* If Onduration timer of old configuration is already running then waiting till it expires */
1497 if((ueDrxCb->onDurExpIndx != DRX_INVALID) && (ueDrxCb->onDurExpDistance != DRX_TMR_EXPRD))
1499 curIndx = (curTime + RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
1500 DU_LOG("\nDEBUG --> SCH : OLD ONDUR RUNNING-EXPIRES at %d curIdx-%d nxtOnDurTime-%d",
1501 ueDrxCb->onDurExpIndx,
1505 /* Manipulating the time when old onDuration timer can expire */
1506 if(curIndx >= ueDrxCb->onDurExpIndx)
1508 onDurExpTime = curTime + ((ueDrxCb->onDurExpDistance+1) * RG_SCH_MAX_DRXQ_SIZE)+\
1509 (ueDrxCb->onDurExpIndx - curIndx + RG_SCH_DRX_DL_DELTA);
1513 onDurExpTime = curTime + (ueDrxCb->onDurExpDistance * RG_SCH_MAX_DRXQ_SIZE)+\
1514 (ueDrxCb->onDurExpIndx - curIndx + RG_SCH_DRX_DL_DELTA);
1517 if(nxtOnDurTime <= onDurExpTime)
1519 if(ueDrxCb->isLongCycle)
1521 cycleLen = ueDrxCb->longDrxCycle;
1525 cycleLen = ueDrxCb->shortDrxCycle;
1527 /* Moving to the possible occassion of onduration after current onduration expiry:
1528 * If both are aligning then going for next cycle */
1529 nxtOnDurTime += ((onDurExpTime - nxtOnDurTime)/cycleLen + 1 ) *cycleLen ;
1532 /* Add the UE to the index which corresponds to the next onduration start*/
1533 onDurIndx = nxtOnDurTime % RG_SCH_MAX_DRXQ_SIZE;
1535 ueDrxCb->distance = (nxtOnDurTime - curTime) / RG_SCH_MAX_DRXQ_SIZE;
1536 if (ueDrxCb->distance < 0)
1538 DU_LOG("\nERROR --> SCH : DRXUE. Invalid "
1539 "value for distance, %d CRNTI:%d", ueDrxCb->distance,ue->ueId);
1542 cmLListAdd2Tail(&(cell->drxCb->drxQ[onDurIndx].onDurationQ),
1543 &(ueDrxCb->onDurationEnt));
1545 ueDrxCb->onDurationEnt.node = (PTR)ue;
1546 ueDrxCb->onDurIndx = onDurIndx;
1549 cmLListInit(&dlInactvLst);
1550 /* Add to DL inactive list */
1551 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
1552 ue->dlDrxInactvLnk.node = (PTR)ue;
1553 /* Send the list to the scheduler to mark UE as inactive */
1554 cellSch = RG_SCH_CMN_GET_CELL(cell);
1555 cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
1558 /* Starting short cycle timer as per the existence of old onDuration timer */
1559 if(TRUE == ueDrxCb->isShortCycleCfgd)
1561 /* Expiring short DRX cycle Tmr once the number of short DRX cycles done */
1562 ueDrxCb->drxShortCycleDistance = (nxtOnDurTime + ueDrxCb->onDurTmrLen + (ueDrxCb->shortCycleTmrLen -1 )*
1563 ueDrxCb->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
1564 shrtCycleExpIndx = (nxtOnDurTime + ueDrxCb->onDurTmrLen + ((ueDrxCb->shortCycleTmrLen -1)*
1565 ueDrxCb->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
1566 cmLListAdd2Tail(&(cell->drxCb->drxQ[shrtCycleExpIndx].shortCycleQ),
1567 &(ueDrxCb->shortCycleEnt));
1568 ueDrxCb->shortCycleEnt.node = (PTR)ue;
1569 ueDrxCb->shortCycleIndx = shrtCycleExpIndx;
1575 } /* end of rgSCHDrxUeReCfg */
1578 /** @brief This function Loop through the list of HARQ processes for this
1579 * UE and delete from the harqRTTQ and harqRetxQ
1581 * Function: rgSCHDrxUeHqReset
1582 * Invoked by rgSCHDrxUeDel
1585 Loop through the list of HARQ processes for this UE and delete from
1586 * the harqRTTQ and harqRetxQ.
1588 * @param RgSchCellCb *cell
1589 * @return ROK/RFAILED
1591 Void rgSCHDrxUeHqReset(RgSchCellCb *cell,RgSchUeCb *ue,RgSchDlHqEnt *hqE,uint8_t cellIdx)
1593 RgSchDlHqProcCb *hqP;
1594 RgSchDrxDlHqProcCb *drxHq =NULLP;
1597 for(i=0; i < hqE->numHqPrcs; i++)
1599 hqP = &hqE->procs[i];
1600 drxHq = RG_SCH_DRX_GET_DL_HQ(hqP);
1602 if(drxHq->rttIndx != DRX_INVALID)
1604 cmLListDelFrm (&(cell->drxCb->drxQ[drxHq->rttIndx].harqRTTQ),
1605 &(drxHq->harqRTTEnt));
1607 drxHq->rttIndx = DRX_INVALID;
1610 if(drxHq->reTxIndx != DRX_INVALID)
1612 cmLListDelFrm (&(cell->drxCb->drxQ[drxHq->reTxIndx].harqRetxQ),
1613 &(drxHq->harqRetxEnt));
1615 drxHq->reTxIndx = DRX_INVALID;
1619 ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1620 ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1623 /** @brief This function Deletes DRX specific context for a UE.
1625 * @details This funciton is invoked by the Configuration module on RGR UE Deletion.
1626 * This function removes the UE's context from all of the DRX Queues.
1627 * In addition it deletes context of UE's HARQ Processes present in the harqRTTQ
1631 * Function: rgSCHDrxUeDel
1632 * Invoked by rgSCHCfgRgrUeDel
1635 * - Remove the UE from the following queues
1636 * - onDurationQ - using onDurIndx
1637 * - onDurationExpQ - using onDurExpIndx
1638 * - inActvTmrQ - using drxInactvIndx
1639 * - shortCycleQ - using shortCycleIndx
1640 * - Loop through the list of HARQ processes for this UE and delete from
1641 * the harqRTTQ and harqRetxQ.
1643 * @param RgSchCellCb *cell
1644 * @param RgSchUeCb *ue
1645 * @return ROK/RFAILED
1647 S16 rgSCHDrxUeDel(RgSchCellCb *cell,RgSchUeCb *ue)
1649 RgSchDrxUeCb *ueDrxCb;
1650 RgSchDlHqEnt *hqE = NULLP;
1652 RgSchUeCellInfo *cellInfo = NULLP;
1654 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
1658 /* ccpu00129899: Moved the drx-enabled check to the caller */
1659 ueDrxCb = ue->drxCb;
1661 /* Remove UE from all queues */
1662 if ( ueDrxCb->onDurIndx != DRX_INVALID )
1664 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurIndx].onDurationQ),
1665 &(ueDrxCb->onDurationEnt));
1667 ueDrxCb->onDurIndx = DRX_INVALID;
1670 if ( ueDrxCb->onDurExpIndx != DRX_INVALID )
1672 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurExpIndx].onDurationExpQ),
1673 &(ueDrxCb->onDurationExpEnt));
1675 ueDrxCb->onDurExpIndx = DRX_INVALID;
1678 if ( ueDrxCb->drxInactvIndx != DRX_INVALID )
1680 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->drxInactvIndx].inActvTmrQ),
1681 &(ueDrxCb->inActvTmrEnt));
1683 ueDrxCb->drxInactvIndx = DRX_INVALID;
1686 if ( ueDrxCb->shortCycleIndx != DRX_INVALID )
1688 cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1689 &(ueDrxCb->shortCycleEnt));
1691 ueDrxCb->shortCycleIndx = DRX_INVALID;
1694 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1696 cellInfo = ue->cellInfo[cellIdx];
1700 hqE = cellInfo->hqEnt;
1701 rgSCHDrxUeHqReset(cell, ue, hqE, cellIdx);
1707 rgSCHDrxUeUlHqReset(cell, ue, &(ueUl->hqEnt));
1710 /* Resetting the DRX Bit set in Inactv Mask */
1711 ue->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
1712 ue->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
1713 ueDrxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1714 ueDrxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1719 /** @brief This function is called at the time of RGR cell configuration.
1722 * Invoked by - rgSCHCfgRgrCellCfg
1724 * Function: rgSCHDrxCellCfg
1727 * - Initializes the following drxQ (memset would do).
1730 * @param RgSchCellCb *cell
1731 * @param RgrCellCfg *cellCfg
1732 * @return ROK/RFAILED
1734 S16 rgSCHDrxCellCfg(RgSchCellCb *cell,RgrCellCfg *cellCfg)
1738 Inst instIdx = cell->instIdx;
1740 #if ( ERRCLASS & ERRCLS_INT_PAR )
1741 /*KWORK_FIX :Removed check for cell being NULL*/
1742 if( (cellCfg == (RgrCellCfg* )NULLP))
1744 DU_LOG("\nERROR --> SCH : rgSCHDrxCellCfg():Invalid Params. cell/cellCfg is NULL");
1749 /* allocate and initialize drxCb */
1750 ret = rgSCHUtlAllocSBuf(instIdx, (Data**)&cell->drxCb,
1751 (sizeof(RgSchDRXCellCb)));
1755 DU_LOG("\nERROR --> SCH : rgSCHDrxCellCfg():"
1756 "Memory allocation FAILED for DRX cell Cb");
1760 /* delInUlScan determines which index scans the queue last.
1761 * We look at onDurationQ both from ulIndex & dlIndex pov.
1762 * Consider, onDuration starts at index 5, and current index is 2,
1763 * while dlIndex is 2 & ulIndex is 3 i.e dl is looking 2 SF ahead
1764 * and ul is looking 3 SF ahead. In this case, dl will scan the queue
1765 * last and therefore DL will delete ueCb from onDuration q.
1766 * The reverse is true for the other case.*/
1768 if ( RG_SCH_DRX_UL_DELTA > RG_SCH_DRX_DL_DELTA )
1770 cell->drxCb->delInUlScan = FALSE;
1774 cell->drxCb->delInUlScan = TRUE;
1778 } /* end of rgSchDrxCellCfg */
1782 /** @brief This function to delete DRX specific context in the cell control
1786 * Invoked by - rgSCHCfgRgrCellDel
1788 * Function: rgSCHDrxCellDel
1791 * - De-Inits RgSchDRXCellCb (Nothing to be done)
1792 * - Assumption: The API is invoked after deletion of UEs from the cell.
1794 * @param RgSchCellCb *cell
1797 Void rgSCHDrxCellDel(RgSchCellCb *cell)
1799 Inst instIdx = cell->instIdx;
1803 /* ccpu00117052 - MOD - Passing double pointer
1804 for proper NULLP assignment*/
1805 rgSCHUtlFreeSBuf(instIdx, (Data **)(&(cell->drxCb)),
1806 sizeof(RgSchDRXCellCb));
1809 } /* end of rgSchDrxCellDel */
1811 /** @brief This function is called when an SR is received from the UE. In this
1812 * case the UE should be marked as ACTIVE till we send a UL allocation to the
1816 * Invoked by - rgSCHCmnSrRcvd
1817 * Must be called after calling the specific scheduler.
1819 * Function: rgSCHDrxSrInd
1822 * - Mark the UE as ACTIVE
1823 * ueCb->drxUlInactvMask |= (DRX_SR_ACTIVE);
1824 * - Optionally call schedulers to add this UE to their scheduling
1826 * - Set drxUe->srRcvd = TRUE
1828 * Note : the specification state that the UE shall start be active
1829 * listening for UL grant, this implies we could potentially exploit
1830 * this to send DL transmissions as well. However we have currently
1831 * chosen not to do so.
1833 * @param RgSchCellCb *cell
1834 * @param RgSchUeCb *ue
1835 * @return ROK/RFAILED
1837 S16 rgSCHDrxSrInd(RgSchCellCb *cell,RgSchUeCb *ue)
1839 RgSchDrxUeCb *drxCb;
1841 #if ( ERRCLASS & ERRCLS_INT_PAR )
1842 if ( cell == (RgSchCellCb* )NULLP)
1847 if( (ue == (RgSchUeCb* )NULLP))
1849 DU_LOG("\nERROR --> SCH : rgSCHDrxSrInd():Invalid Params. cell/ue is NULL");
1853 /* KWork fix - shifted this down */
1856 drxCb = RG_SCH_DRX_GET_UE(ue);
1858 /* Mark the UE as active for UL only */
1859 drxCb->drxUlInactvMask &= ~RG_SCH_DRX_SR_BITMASK;
1860 drxCb->srRcvd = TRUE;
1861 /* Update UE's inactive mask and if required move UE to ACTIVE state */
1862 RG_SCH_CMN_UL_UPDT_INACTV_MASK( cell, ue, RG_DRX_INACTIVE);
1865 } /* rgSCHDrxSrInd */
1868 /** @brief This function handles ACTIVITY due to RACH using a dedicated preamble
1869 * (PDCCH order) OR Handover. A UE shall remain marked as active from the time
1870 * we successfully send out a RAR upto the time it receives a PDCCH indicating a
1874 * Invoked by - rgSCHCmnHdlHoPo
1876 * Function: rgSCHDrxDedRa
1879 * - MARK the UE as active
1880 * - set the raRcvd = TRUE for this UE.
1883 * ueCb->drxDlInactvMask |= (DRX_RA_ACTIVE);
1884 * ueCb->drxUlInactvMask |= (DRX_RA_ACTIVE);
1885 * ueCb->raRcvd = TRUE;
1888 * @param RgSchCellCb *cellCb
1889 * @param RgSchUeCb *ueCb
1892 Void rgSCHDrxDedRa(RgSchCellCb *cellCb, RgSchUeCb *ueCb)
1894 RgSchDrxUeCb *drxCb;
1896 drxCb = RG_SCH_DRX_GET_UE(ueCb);
1898 /* Mark the UE as active for UL & DL */
1899 drxCb->drxUlInactvMask &= ~RG_SCH_DRX_RA_BITMASK;
1900 /* Update UE's inactive mask and if required move UE to ACTIVE state */
1901 RG_SCH_CMN_UL_UPDT_INACTV_MASK(cellCb, ueCb, RG_DRX_INACTIVE);
1903 drxCb->drxDlInactvMask &= ~RG_SCH_DRX_RA_BITMASK;
1904 /* Update UE's inactive mask and if required move UE to ACTIVE state */
1905 RG_SCH_CMN_DL_UPDT_INACTV_MASK(cellCb, ueCb, RG_DRX_INACTIVE);
1907 drxCb->raRcvd = TRUE;
1910 } /* end of rgSCHDrxDedRa */
1913 /** @brief This function calculates the next onDuration Occurence
1914 * and removes & queue it again in onDurationQ
1919 * Function: rgSCHDrxMvToNxtOnDurOcc
1924 * @param RgSchCellCb *cell
1925 * @param RgSchUeCb *ueCb
1926 * @param uint16_t idx - if calcFrmOffst is TRUE,
1927 * idx is delta to be added
1928 * @param Bool calcFrmOffst
1931 static Void rgSCHDrxMvToNxtOnDurOcc(RgSchCellCb *cell,RgSchUeCb *ueCb,uint16_t idx,Bool calcFrmOffst)
1933 uint16_t nxtOnDurIndex;
1935 RgSchDrxUeCb *drxUe;
1936 RgSchDRXCellCb *drxCell;
1937 CmLteTimingInfo nxtOnDur; /* to be used when calcFrmOffset is set */
1938 uint16_t nxtOnDurInSf; /* next On Duration in no of subframes */
1940 drxCell = cell->drxCb;
1941 drxUe = ueCb->drxCb;
1944 if(calcFrmOffst == FALSE)
1946 if (drxUe->isLongCycle)
1948 nxtOnDurIndex = ((idx + drxUe->longDrxCycle)
1949 % RG_SCH_MAX_DRXQ_SIZE );
1950 drxUe->distance = drxUe->longDrxCycle/RG_SCH_MAX_DRXQ_SIZE;
1954 nxtOnDurIndex = ((idx + drxUe->shortDrxCycle)% RG_SCH_MAX_DRXQ_SIZE);
1956 drxUe->distance = drxUe->shortDrxCycle / RG_SCH_MAX_DRXQ_SIZE;
1961 rgSCHDrxGetNxtOnDur(cell,drxUe,&nxtOnDur,(uint8_t)idx);
1963 nxtOnDurInSf = ((nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1966 curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1967 cell->crntTime.slot);
1969 nxtOnDurIndex = nxtOnDurInSf % RG_SCH_MAX_DRXQ_SIZE;
1970 drxUe->distance = (nxtOnDurInSf-curTime) / RG_SCH_MAX_DRXQ_SIZE;
1971 if (drxUe->distance < 0)
1973 DU_LOG("\nERROR --> SCH : DRXUE. Invalid "
1974 "value for distance, %d CRNTI:%d", drxUe->distance,ueCb->ueId);
1978 /* First remove from existing location */
1979 if ( drxUe->onDurIndx != DRX_INVALID )
1981 cmLListDelFrm(&(drxCell->drxQ[drxUe->onDurIndx].onDurationQ),
1982 &(drxUe->onDurationEnt));
1985 /* Add at new location */
1986 cmLListAdd2Tail(&(drxCell->drxQ[nxtOnDurIndex].onDurationQ),
1987 &(drxUe->onDurationEnt));
1989 drxUe->onDurationEnt.node = (PTR)ueCb;
1990 drxUe->onDurIndx = nxtOnDurIndex;
1993 }/*rgSCHDrxMvToNxtOnDurOcc*/
1996 /** @brief This function calculates the next SFN,subframe a given
1997 * timer is going to expire. Works for all TDD configurations.
2001 * Function: rgSCHDrxGetNxtTmrExpry
2002 * We need to count only PDCCH frames in a given TDD
2003 * configuration. This is true for onDuration, inActivity
2004 * & drx-retransmission timers.
2006 * Processing steps (assume timer starts at (12,2) and duration
2007 * is 23 DL subframes):
2008 * - based on TDD configuration, move to the next SFN and
2009 * count the number of DL subframes consumed. In our example,
2010 * moving to (12,9) will consume 6 DL subframes assuming TDD
2012 * - From this point on, determine how many exact Radio Frames
2013 * will be consumed for the remaining DL subframes. In our
2014 * example, remaining DL subframes are (23-6) are 17.
2015 * For config 2, the following holds true
2016 * 8 DLSF are in 1 RF
2017 * 1 DLSF in 1/8 DLSF
2018 * 17 DLSF in 17/8 i.e 2 RF + 1 subframe
2019 * In order to consume 17 DLSF, we need to move forward
2020 * 2 RFs + 1 subframe. Adding 2 RF's gives us (14,9)
2021 * - For the remaining subframe, we need to figure out the next
2022 * available DL subframe. For TDD_configuration, the first DL
2023 * subframe is at index 0. So, the timer will run till (15,0)
2024 * and will expire on (15,1)
2026 * @param RgSchUeCb *ue Ue control block.
2027 * @param uint16_t curTime current Time
2028 * @param uint32_t duration Timer duration
2029 * @param CmLteTimingInfo *tmrExpryIdx Timer expry (SFN,sf)
2030 * @return ROK/RFAILED
2032 static S16 rgSCHDrxGetNxtTmrExpry(RgSchCellCb *cell, uint16_t curTime, uint32_t duration,CmLteTimingInfo *tmrExpryIdx)
2034 uint32_t dlSfTillNxtSFN; /*!< DL subframes till next SFN */
2035 uint8_t tddCfgMode; /*!< tdd config mode */
2036 Bool isDwPtsCnted; /*!< is DwPts counted as PDCCH sf */
2037 CmLteTimingInfo crntTime; /*!< current SFN & sf */
2040 #if ( ERRCLASS & ERRCLS_INT_PAR )
2041 if ( (cell == (RgSchCellCb* )NULLP)
2043 (tmrExpryIdx == (CmLteTimingInfo* )NULLP)
2051 isDwPtsCnted = cell->isDwPtsCnted ;
2053 tddCfgMode = cell->ulDlCfgIdx;
2054 crntTime.sfn = curTime / RGSCH_NUM_SUB_FRAMES_5G;
2055 crntTime.slot = curTime % RGSCH_NUM_SUB_FRAMES_5G;
2059 /* First calculate the number of DL subframes till next SFN */
2061 dlSfTillNxtSFN = rgSchDrxDLSfTillNxtSFN[isDwPtsCnted][tddCfgMode]
2062 [(crntTime.slot % RGSCH_NUM_SUB_FRAMES)];
2065 if ( dlSfTillNxtSFN >= duration )
2067 /* the timer would expire on the same RF */
2068 uint32_t diff = dlSfTillNxtSFN - duration;
2070 tmrExpryIdx->sfn = crntTime.sfn;
2074 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2080 /* to know the DL sf index based on diff */
2081 arrayIdx = rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2083 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2086 }/* if ( dlSfTillNxtSFN >= duration...*/
2089 uint32_t remSf; /*!< remaining subframes */
2090 uint32_t numRf; /*!< num of complete radio frames */
2091 uint32_t numRemSfs; /*!< num of remaining subframes */
2093 remSf = duration - dlSfTillNxtSFN;
2095 /* move to (currSFN,9) having consued dlSfTillNxtSFN DL subframes */
2096 tmrExpryIdx->sfn = crntTime.sfn;
2097 tmrExpryIdx->subframe = (uint8_t)9;
2099 numRf = (1 * remSf)/rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2100 numRemSfs = (1 * remSf)%rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2102 tmrExpryIdx->sfn = tmrExpryIdx->sfn + numRf;
2104 /* we are now at (X,9) having consumed dlSfTillNxtSFN + numRf * num of DL
2105 * subframes in 1 RF */
2107 if ( numRemSfs == 0 )
2109 /* we are at subframe 9 i.e. the timer is going to expire using exact
2110 * radio frames. However, not all TDD_configurations have 9 as their
2111 * last DL subframe. We might have passed the last DL subfrme.
2112 * Therefore, move back */
2113 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2118 /* a reminder implies we have to move past this SFN as we are at the
2119 * last subframe on that SFN */
2121 tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2124 }/*else if diff > duration */
2126 /* timer will expire 1 + tmrExpryIdx */
2128 if ( ( tmrExpryIdx->subframe + 1) == 10 )
2131 tmrExpryIdx->subframe = 0;
2135 tmrExpryIdx->subframe++;
2138 /* check to see if it sfn has crossed its max */
2139 if ( tmrExpryIdx->sfn > RG_SCH_CMN_MAX_SFN_NUM )
2141 tmrExpryIdx->sfn = tmrExpryIdx->sfn - (RG_SCH_CMN_MAX_SFN_NUM + 1);
2145 }/*rgSCHDrxGetNxtTmrExpry*/
2147 /** @brief This function calculates the next onDuration Occurence
2152 * Function: rgSCHDrxCalcNxtTmrExpry
2154 * Processing steps: a wrapper function to call
2155 * rgSCHDrxGetNxtTmrExpry
2157 * @param RgSchCellCb *cell
2158 * @param RgSchUeCb *ue
2159 * @param uint16_t delta
2160 * @param uint32_t tmrLen
2161 * @param uint16_t *distance
2163 * @return ROK/RFAILED
2165 static Void rgSCHDrxCalcNxtTmrExpry(RgSchCellCb *cell, RgSchUeCb *ue, uint16_t delta, uint32_t tmrLen, S16 *distance, uint16_t *idx)
2167 uint16_t curTimeInSf; /*current time in no of subframes*/
2168 CmLteTimingInfo tmrExpry;
2169 uint16_t tmrExpryInSf; /*timer expry in no of subframes*/
2171 curTimeInSf = cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G +
2172 cell->crntTime.slot;
2174 /* add delta to curTime */
2175 curTimeInSf += delta;
2177 rgSCHDrxGetNxtTmrExpry(ue->cell,curTimeInSf,tmrLen,&tmrExpry);
2179 /* convert timre Expry in terms of subframes */
2180 tmrExpryInSf = tmrExpry.sfn * RGSCH_NUM_SUB_FRAMES_5G +
2184 *idx = (tmrExpryInSf) % RG_SCH_MAX_DRXQ_SIZE;
2186 if ( distance != NULLP ) /* hqReTx don't use the concept of distance.
2187 They can send NULLP for distance.
2190 if ( tmrExpryInSf > curTimeInSf )
2192 *distance = (tmrExpryInSf - curTimeInSf) /
2193 RG_SCH_MAX_DRXQ_SIZE;
2197 /* in case the RF is at its max and wraps around */
2199 *distance = ((tmrExpryInSf + (RG_SCH_CMN_MAX_NUM_OF_SFN - 1))
2201 curTimeInSf) / RG_SCH_MAX_DRXQ_SIZE;
2205 DU_LOG("\nERROR --> SCH : DRXUE. Invalid "
2206 "value for distance, %d CRNTI:%d", *distance,ue->ueId);
2211 }/*rgSCHDrxCalcNxtTmrExpry*/
2213 /* ccpu00134670- Validating onduration timer versus DRX cycle*/
2214 /***********************************************************
2216 * Func : rgSCHCfgVldtTddDrxCycCfg
2219 * Desc : Validates DRX Cycle Length configuration against received
2220 * onDuration timer from RRC.
2231 **********************************************************/
2232 S16 rgSCHCfgVldtTddDrxCycCfg(RgSchCellCb *cell,uint16_t drxCycle,uint8_t onDurTmr, uint16_t offSet)
2235 uint16_t endTimeInSf;
2236 CmLteTimingInfo endTime;
2241 rgSCHDrxGetNxtTmrExpry(cell, startTime, onDurTmr, &endTime);
2243 endTimeInSf = (endTime.sfn* RGSCH_NUM_SUB_FRAMES)+endTime.subframe;
2245 if(((RGSCH_MAX_SUBFRM_5G + endTimeInSf- startTime) % RGSCH_MAX_SUBFRM_5G) >=
2251 startTime = (startTime + drxCycle);
2252 /* Going for next iteration if the DRX cycle is not multiple of 10. If it is
2253 multiple of 10(Number of Subframes in a SFN) then subframe, at which
2254 onduration timer can start, will be always same, Otherwise the possible
2255 subframe numbers, where the onDuration timer can start, is 5. Hence 4
2256 more iterations are required. */
2257 }while((drxCycle % RGSCH_NUM_SUB_FRAMES) &&
2258 (startTime < (drxCycle * RGSCH_NUM_SUB_FRAMES/2)));
2265 /** @brief This function is called to handle onDurationTimer per TTI processing.
2268 * Invoked by - rgSCHDrxTtiInd
2270 * Function: rgSCHDrxTtiHdlOnDurUl
2274 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
2276 * - For Uplink we shall look at an index that is
2277 * n + RG_SCH_DRX_UL_DELTA as
2278 * we are concerned with the PDCCH and not the actual PUSCH.
2281 * @param RgSchCellCb *cellCb
2282 * @param uint16_t ulIndex
2286 static Void rgSCHDrxTtiHdlOnDurUl(RgSchCellCb *cell,uint16_t ulIndex)
2289 RgSchDRXCellCb *drxCell = NULLP;
2290 RgSchUeCb *ue = NULLP;
2291 RgSchDrxUeCb *drxUe = NULLP;
2292 CmLListCp ulInactvLst; /* list of UE's becoming DL-inactive */
2293 RgSchCmnCell *cellSch = NULLP;
2294 Bool delInUlScan = FALSE;
2296 drxCell = (cell->drxCb);
2297 delInUlScan = drxCell->delInUlScan;
2298 /***********************************************************
2299 * Scanning OnDurationQ in UL
2300 ***********************************************************/
2302 /* For Uplink we shall look at an index that is n + RG_SCH_DRX_UL_DELTA as
2303 we are concerned with the PDCCH and not the actual PUSCH.*/
2305 node = drxCell->drxQ[ulIndex].onDurationQ.first;
2309 ue = (RgSchUeCb*)node->node;
2311 drxUe = RG_SCH_DRX_GET_UE(ue);
2314 if ( delInUlScan == FALSE)
2319 if ( drxUe->distance != DRX_TMR_EXPRD )
2324 /* reset the bit mask to indicate that onduration has started */
2325 drxUe->drxUlInactvMask &= ~RG_SCH_DRX_ONDUR_BITMASK;
2327 /* if no other condition is keeping UE as inactive,
2330 RG_SCH_CMN_UL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2332 if ( delInUlScan == TRUE )
2334 /*calculate next on duration occurence
2335 * and it to the onDuration Queue*/
2336 rgSCHDrxMvToNxtOnDurOcc(cell,ue,ulIndex,FALSE);
2337 }/*delInUlScan == FALSE */
2340 /***********************************************************
2341 * Scanning OnDurationExpQ in UL
2342 ***********************************************************/
2344 node = drxCell->drxQ[ulIndex].onDurationExpQ.first;
2346 /* Initialize UL inactive list */
2347 cmLListInit(&ulInactvLst);
2351 ue = (RgSchUeCb*)node->node;
2353 drxUe = RG_SCH_DRX_GET_UE(ue);
2355 if ( delInUlScan == FALSE )
2357 drxUe->onDurExpDistance--;
2360 if ( drxUe->onDurExpDistance != DRX_TMR_EXPRD )
2365 /*UE is inactive as onduration has expired */
2366 drxUe->drxUlInactvMask |= RG_SCH_DRX_ONDUR_BITMASK;
2368 if( !RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
2370 /* set the inactive bit to indicate UE has now become inactive */
2371 ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
2373 /* Add to DL inactive list */
2374 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
2375 ue->ulDrxInactvLnk.node = (PTR)ue;
2378 if ( delInUlScan == TRUE)
2380 /*Remove from DRX queue*/
2381 cmLListDelFrm(&(drxCell->drxQ[ulIndex].onDurationExpQ),
2382 &(drxUe->onDurationExpEnt));
2384 drxUe->onDurExpIndx = DRX_INVALID;
2389 /* Send the list to the scheduler to mark UE as inactive in UL*/
2390 cellSch = RG_SCH_CMN_GET_CELL(cell);
2391 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
2396 /** @brief This function is called to handle onDurationTimer per TTI processing.
2399 * Invoked by - rgSCHDrxTtiInd
2401 * Function: rgSCHDrxTtiHdlOnDurDl
2405 * - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
2407 * - For Downlink we shall look at an index that is
2408 * n + RG_SCH_DRX_DL_DELTA.
2411 * @param RgSchCellCb *cellCb
2412 * @param uint16_t dlIndex
2416 static Void rgSCHDrxTtiHdlOnDurDl(RgSchCellCb *cell,uint16_t dlIndex)
2419 RgSchDRXCellCb *drxCell = NULLP;
2420 RgSchUeCb *ue = NULLP;
2421 RgSchDrxUeCb *drxUe = NULLP;
2422 RgSchCmnCell *cellSch = NULLP;
2423 uint16_t expiryIndex;
2424 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
2425 Bool delInUlScan = FALSE;
2427 /* The DL loop, if onDurationTimer has started, will add the UeCb
2428 * in the onDurationTmrExprQ. If !delInUlScan, then calculate the next
2429 * OnDuration occurence, q it there and remove it from the current location.
2431 /***********************************************************
2432 * Scanning OnDurationQ in DL
2433 ***********************************************************/
2434 drxCell = (cell->drxCb);
2436 delInUlScan = drxCell->delInUlScan;
2437 //DU_LOG("\nINFO --> SCH : CELL Timer [SFN : %d],[SF : %d]\n",cell->crntTime.sfn,cell->crntTime.slot);
2439 node = drxCell->drxQ[dlIndex].onDurationQ.first;
2444 ue = (RgSchUeCb* )node->node;
2448 drxUe = RG_SCH_DRX_GET_UE(ue);
2450 if ( delInUlScan == TRUE)
2455 if ( drxUe->distance != DRX_TMR_EXPRD )
2461 /* UE is active as onduration is to start */
2462 drxUe->drxDlInactvMask &= ~RG_SCH_DRX_ONDUR_BITMASK;
2464 /* set the UE as DRX active*/
2466 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2467 RG_SCH_CMN_DL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2469 /* Temporary fix to delete stale entry */
2470 if (drxUe->onDurExpIndx != DRX_INVALID)
2472 DU_LOG("\nDEBUG --> SCH : UEID:%d PreExisted[%d:%d]in onDurExpQ new[%d]",
2474 drxUe->onDurExpIndx,
2475 drxUe->onDurExpDistance,
2477 cmLListDelFrm(&(drxCell->drxQ[drxUe->onDurExpIndx].onDurationExpQ),
2478 &(drxUe->onDurationExpEnt));
2480 drxUe->onDurExpIndx = DRX_INVALID;
2482 /*start the onduration expiry timer*/
2484 rgSCHDrxCalcNxtTmrExpry(cell,
2488 &(drxUe->onDurExpDistance),
2492 expiryIndex = ((dlIndex + drxUe->onDurTmrLen) %
2493 RG_SCH_MAX_DRXQ_SIZE);
2494 drxUe->onDurExpDistance = (drxUe->onDurTmrLen)/
2495 RG_SCH_MAX_DRXQ_SIZE;
2498 cmLListAdd2Tail(&(drxCell->drxQ[expiryIndex].onDurationExpQ),
2499 &(drxUe->onDurationExpEnt));
2500 //DU_LOG("\nINFO --> SCH : DRXOnDuration Timer Started at [SFN : %d],[SF : %d]\n",cell->crntTime.sfn,cell->crntTime.slot);
2501 drxUe->onDurationExpEnt.node = (PTR)ue;
2502 drxUe->onDurExpIndx = expiryIndex;
2504 //DU_LOG("\nINFO --> SCH : DRxOnDuration will Expire = [%d]\n",\
2505 (cell->crntTime.sfn*10+cell->crntTime.slot+drxUe->onDurTmrLen));
2507 if ( delInUlScan == FALSE )
2509 /*calculate next on duration occurence
2510 * and it to the onDuration Queue*/
2511 rgSCHDrxMvToNxtOnDurOcc(cell,ue,dlIndex,FALSE);
2512 }/*delInUlScan == FALSE */
2516 /***********************************************************
2517 * Scanning OnDurationExpQ in DL
2518 ***********************************************************/
2520 /* Mark UE as Inactive based on OnDuration Expiry */
2521 node = drxCell->drxQ[dlIndex].onDurationExpQ.first;
2523 /* Initialize DL inactive list */
2524 cmLListInit(&dlInactvLst);
2528 ue = (RgSchUeCb*)node->node;
2530 drxUe = RG_SCH_DRX_GET_UE(ue);
2532 if ( delInUlScan == TRUE )
2534 drxUe->onDurExpDistance--;
2537 if ( drxUe->onDurExpDistance != DRX_TMR_EXPRD )
2543 /* UE is inactive as onduration has expired */
2544 drxUe->drxDlInactvMask |= (RG_SCH_DRX_ONDUR_BITMASK);
2546 if( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
2548 /* set the inactive bit to indicate UE has now become inactive */
2549 ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
2551 /* Add to DL inactive list */
2552 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
2553 ue->dlDrxInactvLnk.node = (PTR)ue;
2556 if ( delInUlScan == FALSE )
2558 /*Remove from DRX queue*/
2559 cmLListDelFrm(&(drxCell->drxQ[dlIndex].onDurationExpQ),
2560 &(drxUe->onDurationExpEnt));
2562 drxUe->onDurExpIndx = DRX_INVALID;
2567 /* Send the list to the scheduler to mark UE as inactive */
2568 cellSch = RG_SCH_CMN_GET_CELL(cell);
2569 cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
2572 }/*rgSCHDrxTtiHdlOnDurDl*/
2574 /** @brief This function handles the Dl HARQ timer's processing per TTI.
2577 * Invoked by - rgSCHDrxTtiHdlDlHarq
2579 * Function: rgSCHDrxTtiHdlDlHarqRTT
2582 * - In addition per TTI DRX module must look at Downlink HARQ queues
2583 * maintained to track HARQ RTT timer and drx-RetransmissionTimer.
2584 * Every TTI at the scheduling index we shall check these queues and
2585 * process accordingly.
2587 * @param RgSchCellCb *cellCb
2588 * @param uint16_t dlIndex
2592 static Void rgSCHDrxTtiHdlDlHarqRTT(RgSchCellCb *cell,uint16_t dlIndex)
2595 RgSchDrxDlHqProcCb *drxHq;
2596 RgSchDlHqProcCb *dlHq;
2597 RgSchDRXCellCb *drxCell;
2598 RgSchDrxUeCb *drxUe;
2599 uint16_t reTxExpIndx;
2602 CmLListCp dlInactvLst; /* list of UE's becoming DL-inactive */
2603 RgSchCmnCell *cellSch = RG_SCH_CMN_GET_CELL(cell);
2605 uint32_t dlInactvMask;
2607 drxCell = cell->drxCb;
2608 delInUlScan = drxCell->delInUlScan;
2610 /***********************************************************
2611 * Scanning harqRTTQ in DL
2612 ***********************************************************/
2614 cmLListInit(&dlInactvLst);
2615 node = drxCell->drxQ[dlIndex].harqRTTQ.first;
2619 dlHq = (RgSchDlHqProcCb*)node->node;
2623 if(TRUE == ue->isEmtcUe)
2628 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2629 drxUe = RG_SCH_DRX_GET_UE(ue);
2630 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2631 /* add the UE to the cell's retransmission queuee before starting
2632 * reTx timer, because this will not depend on retx timer trigger*/
2633 rgSCHUtlDlProcAddToRetx(dlHq->hqE->cell, dlHq);
2635 if ( delInUlScan == FALSE)
2637 cmLListDelFrm (&(drxCell->drxQ[dlIndex].harqRTTQ),
2638 &(drxHq->harqRTTEnt));
2640 drxHq->rttIndx = DRX_INVALID;
2642 /* ccpu00134565: Starting retransmission timer only if timerLen is
2643 * having non-zero value after reduction, Adding to Retx queue is
2644 * independent of starting retransmission timer. Hence if part will
2645 * take care of starting retx timer only*/
2646 if (drxUe->drxRetransTmrLen > drxHq->retxTmrReduction)
2648 /* add the harq proc to the re-tx queue--*/
2650 /* ccpu00134196-[Add]-DRX retx timer changes */
2651 rgSCHDrxCalcNxtTmrExpry(cell,
2654 drxUe->drxRetransTmrLen-drxHq->retxTmrReduction,
2655 NULLP, /*retransQ does not maintain distance*/
2660 /* ccpu00134196-[Add]-DRX retx timer changes */
2661 reTxExpIndx = ((dlIndex +
2662 drxUe->drxRetransTmrLen-drxHq->retxTmrReduction) %
2663 RG_SCH_MAX_DRXQ_SIZE);
2665 /* TODO. Workaround to avoid duplicate entry */
2666 if(drxHq->reTxIndx == DRX_INVALID)
2668 cmLListAdd2Tail (&(drxCell->drxQ[reTxExpIndx].harqRetxQ),
2669 &(drxHq->harqRetxEnt));
2671 drxHq->harqRetxEnt.node = (PTR)dlHq;
2672 drxHq->reTxIndx = reTxExpIndx;
2676 DU_LOG("\nERROR --> SCH : CRNTI:%d "
2677 "Adding Retx Node to expire at RetxIndx: %d at dlIndex %d "
2678 "drxHq->reTxIndx %d", ue->ueId, reTxExpIndx, dlIndex,
2682 /*mark the ue as active for downlink--*/
2683 drxUe->drxDlInactvMask &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2684 drxUe->drxDlInactvMaskPerCell[cellIdx] &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2686 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2687 RG_SCH_CMN_DL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2691 /***********************************************************
2692 * Scanning harqRetxQ in DL
2693 ***********************************************************/
2695 node = drxCell->drxQ[dlIndex].harqRetxQ.first;
2698 dlHq = (RgSchDlHqProcCb*)node->node;
2700 drxUe = RG_SCH_DRX_GET_UE(ue);
2702 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2703 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2705 /*mark the ue as in-active for downlink*/
2706 drxUe->drxDlInactvMaskPerCell[cellIdx] |= (RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2708 dlInactvMask = RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId;
2710 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
2712 dlInactvMask &= drxUe->drxDlInactvMaskPerCell[cellIdx];
2715 drxUe->drxDlInactvMask |= dlInactvMask;
2717 /* if no other condition is keeping ue active,
2720 if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
2722 ue->dl.dlInactvMask |= (RG_DRX_INACTIVE);
2724 /* Add to DL inactive list */
2725 cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
2726 ue->dlDrxInactvLnk.node = (PTR)ue;
2729 /*remove the harq proc from this queue*/
2730 if ( delInUlScan == FALSE)
2732 cmLListDelFrm (&(drxCell->drxQ[dlIndex].harqRetxQ),
2733 &(drxHq->harqRetxEnt));
2734 drxHq->reTxIndx = DRX_INVALID;
2737 /*Call schedulers to inactivate ue*/
2738 cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
2743 /** @brief This function handles the Ul HARQ timer's processing per TTI.
2746 * Invoked by - rgSCHDrxTtiHdlDlHarq
2748 * Function: rgSCHDrxTtiHdlUlHarqRTT
2751 * - In addition per TTI DRX module must look at Downlink HARQ queues
2752 * maintained to track HARQ RTT timer and drx-RetransmissionTimer.
2753 * Every TTI at the scheduling index we shall check these queues and
2754 * process accordingly.
2756 * - Though these timers are related to downlink HARQ processing, they
2757 * have an impact on uplink scheduling. The reason is that the UE,
2758 * if active for downlink scheduling implies that it is reading
2759 * PDCCHs i.e. we can still send uplink allocations to the UE. Hence
2760 * every TTI Uplink too would look at the harqRTTQ and harqRetxQ.
2764 * @param RgSchCellCb *cellCb
2765 * @param uint16_t ulIndex
2769 static Void rgSCHDrxTtiHdlUlHarqRTT(RgSchCellCb *cell,uint16_t ulIndex)
2772 RgSchDrxDlHqProcCb *drxHq;
2773 RgSchDlHqProcCb *dlHq;
2774 RgSchDRXCellCb *drxCell;
2775 RgSchDrxUeCb *drxUe;
2778 CmLListCp ulInactvLst; /* list of UE's becoming DL-inactive */
2779 RgSchCmnCell *cellSch = RG_SCH_CMN_GET_CELL(cell);
2781 uint32_t ulInactvMask;
2784 drxCell = cell->drxCb;
2785 delInUlScan = drxCell->delInUlScan;
2787 cmLListInit(&ulInactvLst);
2789 /***********************************************************
2790 * Scanning harqRTTQ in UL
2791 ***********************************************************/
2794 Though these timers are related to downlink HARQ processing, they
2795 have an impact on uplink scheduling. The reason is that the UE,
2796 if active for downlink scheduling implies that it is reading
2797 PDCCHs i.e. we can still send uplink allocations to the UE. Hence
2798 every TTI Uplink too would look at the harqRTTQ and harqRetxQ.
2801 node = drxCell->drxQ[ulIndex].harqRTTQ.first;
2804 dlHq = (RgSchDlHqProcCb*)node->node;
2806 drxUe = RG_SCH_DRX_GET_UE(ue);
2808 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2809 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2811 if ( delInUlScan == TRUE )
2813 /* remove the harq proc from this queue--*/
2814 cmLListDelFrm (&(drxCell->drxQ[ulIndex].harqRTTQ),
2815 &(drxHq->harqRTTEnt));
2817 drxHq->rttIndx = DRX_INVALID;
2820 /* mark the ue as active for uplink--*/
2821 drxUe->drxUlInactvMask &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2822 drxUe->drxUlInactvMaskPerCell[cellIdx] &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2824 /* Update UE's inactive mask and if required move UE to ACTIVE state */
2825 RG_SCH_CMN_UL_UPDT_INACTV_MASK( cell, ue, RG_DRX_INACTIVE);
2828 /***********************************************************
2829 * Scanning harqRetxQ in UL
2830 ***********************************************************/
2831 node = drxCell->drxQ[ulIndex].harqRetxQ.first;
2834 dlHq = (RgSchDlHqProcCb*)node->node;
2836 drxUe = RG_SCH_DRX_GET_UE(ue);
2837 drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2838 cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2840 /*mark the ue as in-active for uplink*/
2842 drxUe->drxUlInactvMaskPerCell[cellIdx] |= (RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2844 ulInactvMask = RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId;
2846 for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
2848 ulInactvMask &= drxUe->drxUlInactvMaskPerCell[cellIdx];
2851 drxUe->drxUlInactvMask |= ulInactvMask;
2853 if(!RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
2855 ue->ul.ulInactvMask |= (RG_DRX_INACTIVE);
2857 cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
2858 ue->ulDrxInactvLnk.node = (PTR)ue;
2861 /* remove the harq proc from this queue*/
2862 if ( delInUlScan == TRUE)
2864 cmLListDelFrm (&(drxCell->drxQ[ulIndex].harqRetxQ),
2865 &(drxHq->harqRetxEnt));
2866 drxHq->reTxIndx = DRX_INVALID;
2871 cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
2877 /**********************************************************************
2880 **********************************************************************/