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 Scheduler common functions
29 **********************************************************************/
31 /** @file rg_sch_mga.c
32 @brief This module handles schedulers' measurement gap and ack-nack repetiton functionality */
35 /* header include files -- defines (.h) */
36 #include "common_def.h"
41 #include "rg_sch_inf.h"
42 #include "rg_sch_err.h"
44 #include "rg_sch_cmn.h"
45 #include "rl_interface.h"
46 #include "rl_common.h"
48 /* header/extern include files (.x) */
49 #include "tfu.x" /* RGU types */
50 #include "lrg.x" /* layer management typedefs for MAC */
51 #include "rgr.x" /* layer management typedefs for MAC */
52 #include "rg_sch_inf.x" /* typedefs for Scheduler */
53 #include "rg_sch.x" /* typedefs for Scheduler */
56 static S16 rgSCHMeasGapANRepUtlAddUe ARGS((
59 RgrUeMeasGapCfg *cfg));
61 static S16 rgSCHMeasGapANRepUtlRmvUe ARGS((
65 static S16 rgSchAckNackRepUtlRmvUe ARGS((
69 static Void rgSchAckNackRepUtlHdlTti ARGS((
71 CmLListCp *ackNackRepQ));
73 static Void rgSCHMeasGapANRepUtlHdlTti ARGS((
75 CmLListCp *measGapQ));
77 static uint8_t rgSCHAckNakRepFindUlDuration ARGS((
80 CmLteTimingInfo repTime,
82 static Void rgSCHAckNakRepGetUlOffsetFrmDl ARGS((
84 CmLteTimingInfo crntDlTime,
89 * @brief Handles Measurement gap and ack-nack repetition related
90 * configuration for a UE.
94 * Function : rgSCHMeasGapANRepUeCfg
96 * Invoking Module Processing:
97 * - This shall be invoked by SCH_GOM at UE configuration. It shall do the
98 * validations for the spec-defined values.
101 * - For UE-specific measurement gap related configuration,
102 * - If measurementGap is configured,
103 * - Update UE with the configured values.
104 * - Add Ue to cell->measGapCb->gapPrdQ depending on the gap period
105 * configuration at index = the configured gap offset.
106 * - measGapOffst = the configured gap offset
107 * - Initialize timers.
109 * - measGapOffst = RG_INVALID_MEASGAPQ_ID
110 * - For UE-specific ACK-NACK repetition related configuration,
111 * - Update the configured value. Set 'cfgRepCnt' variable value.
112 * - repCntr = cfgRepCnt.
113 * - qOffst = RG_INVALID_ACKNACKREPQ_ID
116 * @param[in] RgSchCellCb *cell
117 * @param[in] RgSchUeCb *ue
118 * @param[in] RgrUeCfg *ueCfg
124 S16 rgSCHMeasGapANRepUeCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeCfg *ueCfg)
127 ue->measGapCb.isMesGapEnabled = ueCfg->ueMesGapCfg.isMesGapEnabled;
129 if (ueCfg->ueMesGapCfg.isMesGapEnabled)
131 ue->measGapCb.gapPrd = ueCfg->ueMesGapCfg.gapPrd;
132 ue->measGapCb.gapOffst = ueCfg->ueMesGapCfg.gapOffst;
133 rgSCHMeasGapANRepUtlAddUe (cell, ue, &(ueCfg->ueMesGapCfg));
134 cmInitTimers (&ue->measGapCb.measGapTmr, 1);
135 cmInitTimers (&ue->measGapCb.measGapUlInactvTmr, 1);
136 cmInitTimers (&ue->measGapCb.measGapDlInactvTmr, 1);
139 /* ACK NACK repetition part */
140 if (ueCfg->ueAckNackCfg.isAckNackEnabled)
142 ue->ackNakRepCb.cfgRepCnt = ueCfg->ueAckNackCfg.ackNackRepFactor;
143 ue->ackNakRepCb.repCntr = ue->ackNakRepCb.cfgRepCnt;
144 ue->ackNakRepCb.isAckNackEnabled = TRUE;
145 ue->ackNakRepCb.pucchRes = ueCfg->ueAckNackCfg.pucchAckNackRep;
146 cmInitTimers (&ue->ackNakRepCb.ackNakRepUlInactvTmr, 1);
147 cmInitTimers (&ue->ackNakRepCb.ackNakRepDlInactvTmr, 1);
148 cmInitTimers (&ue->ackNakRepCb.ackNakRepTmr, 1);
154 * @brief Handles Measurement gap and ack-nack repetition related
155 * re-configuration for a UE.
159 * Function : rgSCHMeasGapANRepUeRecfg
161 * Invoking Module Processing:
162 * - This shall be invoked by SCH_GOM at UE re-configuration. It shall do the
163 * validations for the spec-defined values.
166 * - For measurement gap,
167 * - If measurement gap period or offset is re-configured, remove UE from
168 * the previous list, if any and add it to the new list.
169 * - Update configured values appropriately.
170 * - For ACK-NACK repetition,
171 * - Update the configured value. Set 'cfgRepCnt' variable value.
172 * - If (repCntr == 0)
173 * - repCntr = cfgRepCnt.
174 * - qOffst = RG_INVALID_ACKNACKREPQ_ID
176 * @param[in] RgSchCellCb *cell
177 * @param[in] RgSchUeCb *ue
178 * @param[in] RgrUeRecfg *ueRecfg
185 S16 rgSCHMeasGapANRepUeRecfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeRecfg *ueRecfg)
187 RgrUeMeasGapCfg *reCfg;
188 RgSchUeMeasGapCb *ueMeasCb;
189 RgrUeAckNackRepCfg *ackNackReCfg = &(ueRecfg->ueAckNackRecfg);
190 RgSchUeAckNakRepCb *ackNakRepCb = &(ue->ackNakRepCb);
192 reCfg = &(ueRecfg->ueMeasGapRecfg);
193 ueMeasCb = &(ue->measGapCb);
195 /* Removed extra comments
196 * Check this once again Check to see if anything changed or not */
197 if ((reCfg->isMesGapEnabled == TRUE) &&
198 (ueMeasCb->isMesGapEnabled == TRUE) &&
199 (reCfg->gapPrd == ueMeasCb->gapPrd) &&
200 (reCfg->gapOffst == ueMeasCb->gapOffst))
202 /* Nothing changed hence nothing to do */
206 if (reCfg->isMesGapEnabled)
208 if (ueMeasCb->isMesGapEnabled)
210 rgSCHMeasGapANRepUtlRmvUe (cell, ue);
214 cmInitTimers (&ueMeasCb->measGapTmr, 1);
215 cmInitTimers (&ueMeasCb->measGapUlInactvTmr, 1);
216 cmInitTimers (&ueMeasCb->measGapDlInactvTmr, 1);
219 /* Add to the correct Measurement gap queue */
220 rgSCHMeasGapANRepUtlAddUe (cell, ue, reCfg);
222 ueMeasCb->gapPrd = reCfg->gapPrd;
223 ueMeasCb->gapOffst = reCfg->gapOffst;
224 ueMeasCb->isMesGapEnabled = TRUE;
225 } /* if new config has Measurement gap enabled */
228 if (ueMeasCb->isMesGapEnabled)
230 /* check if return value needed or not */
231 rgSCHMeasGapANRepUtlRmvUe (cell, ue);
232 ueMeasCb->isMesGapEnabled = FALSE;
234 } /* if new config has Measurement gap disabled */
235 } /* For MeasGap configuration */
237 if (ackNackReCfg->isAckNackEnabled)
239 if (!ackNakRepCb->isAckNackEnabled)
241 ackNakRepCb->isAckNackEnabled = TRUE;
242 /* Timers need to be init immediately after config*/
243 cmInitTimers (&ue->ackNakRepCb.ackNakRepUlInactvTmr, 1);
244 cmInitTimers (&ue->ackNakRepCb.ackNakRepDlInactvTmr, 1);
245 cmInitTimers (&ue->ackNakRepCb.ackNakRepTmr, 1);
246 } /* repetition was disabled */
247 ackNakRepCb->pucchRes = ackNackReCfg->pucchAckNackRep;
248 ackNakRepCb->cfgRepCnt = ackNackReCfg->ackNackRepFactor;
249 if (ackNakRepCb->repCntr == 0)
251 ackNakRepCb->repCntr = ackNackReCfg->ackNackRepFactor;
253 } /* repetition enabled in re configuration */
256 ackNakRepCb->isAckNackEnabled = FALSE;
257 } /* repetition disabled in re configuration */
262 /** @brief This function is a utility to add the UE to the correct Measurement
263 * queue present in the cellCb.
277 static S16 rgSCHMeasGapANRepUtlAddUe(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeMeasGapCfg *cfg)
282 case RG_MEAS_GAPPRD_40:
283 /* Insert the UE into the linked list based on the gap Offset */
284 ue->measGapCb.measQLnk.node = (PTR)ue;
285 cmLListAdd2Tail (&(cell->measGapCb.gapPrd40Q[cfg->gapOffst]),
286 &(ue->measGapCb.measQLnk));
288 case RG_MEAS_GAPPRD_80:
289 ue->measGapCb.measQLnk.node = (PTR)ue;
290 cmLListAdd2Tail (&(cell->measGapCb.gapPrd80Q[cfg->gapOffst]),
291 &(ue->measGapCb.measQLnk));
294 DU_LOG("\nERROR --> SCH : rgSCHMeasGapANRepUeRecfg() Incorrect GAP Period"
295 "CRNTI:%d",ue->ueId);
299 } /* end of rgSCHMeasGapANRepUtlAddUe */
302 /** @brief This function is a utility function to remove the ue from the measQ
303 * preset in tthe cell Cb.
316 static S16 rgSCHMeasGapANRepUtlRmvUe(RgSchCellCb *cell,RgSchUeCb *ue)
319 switch (ue->measGapCb.gapPrd)
321 case RG_MEAS_GAPPRD_40:
322 /* Remove from the existing list */
323 cmLListDelFrm (&(cell->measGapCb.gapPrd40Q[ue->measGapCb.gapOffst]),
324 &(ue->measGapCb.measQLnk));
325 ue->measGapCb.measQLnk.node = NULLP;
327 case RG_MEAS_GAPPRD_80:
328 /* Remove from the existing list */
329 cmLListDelFrm (&(cell->measGapCb.gapPrd80Q[ue->measGapCb.gapOffst]),
330 &(ue->measGapCb.measQLnk));
331 ue->measGapCb.measQLnk.node = NULLP;
335 } /* end of rgSCHMeasGapANRepUtlRmvUe */
338 * @brief Frees Measurement gap and ack-nack repetition related data structures in UE
342 * Function : rgSCHMeasGapANRepUeDel
344 * Invoking Module Processing:
345 * - This shall be invoked by SCH_GOM at Ue deletion.
348 * - For measurement gap,
349 * - if (measGapOffst != RG_INVALID_MEASGAPQ_ID)
350 * - Remove from the measurement queue depending on the measGapPrd
352 * - Delete all timers
353 * - For ACK-NACK repetition,
354 * - if (qOffst != RG_INVALID_ACKNACKREPQ_ID)
355 * - Remove from the ackNakRepQ queue
356 * - Delete all timers
359 * @param[in] RgSchCellCb *cell
360 * @param[in] RgSchUeCb *ue
366 Void rgSCHMeasGapANRepUeDel(RgSchCellCb *cell,RgSchUeCb *ue,Bool isUeDel)
369 if (ue->measGapCb.isMesGapEnabled)
371 rgSCHMeasGapANRepUtlRmvUe (cell, ue);
372 /* Must stop the timer if its running */
373 if (ue->measGapCb.isMeasuring)
375 rgSCHTmrStopTmr (cell, RG_SCH_TMR_MEASGAP, ue);
378 ue->measGapCb.isMesGapEnabled = FALSE;
381 /* Stop timers if running */
382 if (ue->dl.dlInactvMask)
384 if (ue->dl.dlInactvMask & RG_MEASGAP_INACTIVE)
386 rgSCHTmrStopTmr (cell, RG_SCH_TMR_DL_MEASGAP, ue);
388 if (ue->dl.dlInactvMask & RG_ACKNAKREP_INACTIVE)
390 rgSCHTmrStopTmr (cell, RG_SCH_TMR_DL_ACKNACK, ue);
392 ue->dl.dlInactvLnk.node = NULLP;
394 if (ue->ul.ulInactvMask)
396 if (ue->ul.ulInactvMask & RG_MEASGAP_INACTIVE)
398 rgSCHTmrStopTmr (cell, RG_SCH_TMR_UL_MEASGAP, ue);
400 if (ue->ul.ulInactvMask & RG_ACKNAKREP_INACTIVE)
402 rgSCHTmrStopTmr (cell, RG_SCH_TMR_UL_ACKNACK, ue);
404 ue->ul.ulInactvLnk.node = NULLP;
407 /* ccpu00133470- Releasing ACKNACK Rep UE Deleted */
408 if (isUeDel & ue->ackNakRepCb.isAckNakRep)
410 rgSCHTmrStopTmr (cell, RG_SCH_TMR_ACKNACK_REP, ue);
411 rgSchAckNackRepUtlRmvUe (cell, ue);
416 /** @brief This function deletes the UEs information related to ACK NACK
424 * - Mainly we need to remove the UEs hqProcs from the ackNackQ(s)
425 * present in the subframes.
432 static S16 rgSchAckNackRepUtlRmvUe(RgSchCellCb *cell,RgSchUeCb *ue)
438 RgSchDlHqProcCb *hqP;
441 RgSchDlHqEnt *hqEnt = RG_SCH_CMN_GET_UE_HQE(ue, cell);
443 for (hqIdx = 0; hqIdx < hqEnt->numHqPrcs; hqIdx++)
445 hqP = &hqEnt->procs[hqIdx];
446 /* Starting from index 1 as index 0 isn't used */
447 for (repIdx = 1; repIdx < ue->ackNakRepCb.cfgRepCnt; repIdx++)
449 for (tbCnt = 0; tbCnt < 2; tbCnt++)
451 if ((hqP->tbInfo[tbCnt].crntSubfrm[repIdx] != NULLP) &&
452 (hqP->tbInfo[tbCnt].anRepLnk[repIdx].node != NULLP))
454 cmLListDelFrm(&((hqP->tbInfo[tbCnt].crntSubfrm[repIdx])->\
455 ackNakRepQ), &hqP->tbInfo[tbCnt].anRepLnk[repIdx]);
456 hqP->tbInfo[tbCnt].anRepLnk[repIdx].node = NULLP;
457 hqP->tbInfo[tbCnt].crntSubfrm[repIdx] = NULLP;
468 * @brief Per TTI processing for measurement gap and ack nack repetition
473 * Function : rgSCHMeasGapANRepTtiHndl
475 * Invoking Module Processing:
476 * - This shall be invoked by SCH_TOM on recieving TTI indication from PHY
477 * . SCH_TOM shall update the cell->crntTime before invoking this API.
480 * - Compute qOffset for 40ms queue as =
481 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe)%RG_MEAS_GAPPRD_40.
482 * - Mark all the UEs at computed offset for performing measurement. Set
483 * isMeasuring = TRUE.
484 * - Start measGapTmr for each UE:
485 * - length = RG_MEAS_GAP_LEN.
486 * - event = RG_MEASGAP_ON
487 * - handler = rgSCHMeasGapANRepTmrExpry
488 * - Reinitalize the list at the offset.
489 * - Compute qOffset for 80ms queue as =
490 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe)%RG_MEAS_GAPPRD_80.
491 * - Mark all the UEs at computed offset for performing measurement. Set
492 * isMeasuring = TRUE.
493 * - Start measGapTmr for each UE:
494 * - length = RG_MEAS_GAP_LEN.
495 * - event = RG_MEASGAP_ON
496 * - handler = rgSCHMeasGapANRepTmrExpry
497 * - Reinitalize the list at the offset.
498 * - Compute qOffset for ACK NACK repetition queue as =
499 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe)%RG_MAX_NUM_DLSF.
500 * - Mark all the UEs at computed offset for performing ack-nack repetition. Set
501 * isAckNakRep = TRUE.
502 * - Start ackNakRepTmr for each UE:
503 * - length = repCntr.
504 * - event = RG_ACKNAKREP_ON
505 * - handler = rgSchAckNakRepTmrExpry
506 * - Reinitalize the list at the offset.
507 * - 'isMeasuring' bool value shall be cheked
508 * - While sending dataRecpReq to PHY for non-adaptive uplink re-tx
509 * and if 'TRUE', no dataRecpReq shall be sent.
510 * - While sending NACK as feedback to UE and if 'TRUE' no PHICH shall
511 * be sent and shall mark the UE for adaptive re-tx.
512 * - While sending HqFbkRecpReq for a UE (applicable only if ACK NACK
513 * repetition coincides) and if 'TRUE',
514 * - The request shall not be sent.
515 * - Decrement repCntr
516 * - if (repCntr == 0)
517 * - Delete UE from the list.
518 * - Move the Ue to next subframe's list of ACK-NACK repeating UEs.
519 * - 'isAckNakRep' bool value shall be cheked
520 * - While sending dataRecpReq to PHY for non-adaptive uplink re-tx
521 * and if 'TRUE', no dataRecpReq shall be sent.
522 * - Check if any refresh for these cell-specific queues is needed
523 * anywhere else as well.
524 * - Check if TTI miss needs some trigger to the module.
527 * @param[in] RgSchCellCb *cell
533 S16 rgSCHMeasGapANRepTtiHndl(RgSchCellCb *cell)
538 CmLteTimingInfo repTime;
540 /* Measurement GAP Starts at offSet - however at MAC we are concerned at
541 * subframe + TFU_DELTA.
544 /* Introduced timing delta for DL control in FDD */
546 offset = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + TFU_DELTA) %
549 offset = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + TFU_DLCNTRL_DLDELTA) %
552 queue = &(cell->measGapCb.gapPrd40Q[offset]);
553 rgSCHMeasGapANRepUtlHdlTti (cell, queue);
555 /* Introduced timing delta for DL control in FDD */
557 offset = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + TFU_DELTA) %
560 offset = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + TFU_DLCNTRL_DLDELTA) %
563 queue = &(cell->measGapCb.gapPrd80Q[offset]);
564 rgSCHMeasGapANRepUtlHdlTti (cell, queue);
566 /* for ACK NACK repetition starts at offset - however at MAC we are
567 * concerned with subframe - TFU_DELTA */
568 /* offset = ((cell->crntTime.sfn * 10) + cell->crntTime.slot) %
569 * RG_MAX_NUM_DLSF; */
570 /* We wish to get the subframe whose HARQ Reception request would go out in
571 * this subframe. HARQ_RTT - TFU_DELTA
573 /* Introduced timing delta for reception req */
576 //RGSCHSUBFRMCRNTTIME(cell->crntTime, repTime, (4 - TFU_DELTA));
577 RGSCHDECRFRMCRNTTIME(cell->crntTime, repTime, (RG_SCH_CMN_HARQ_INTERVAL - TFU_RECPREQ_DLDELTA));
579 RGSCHDECRFRMCRNTTIME(cell->crntTime, repTime, (RG_SCH_CMN_HARQ_INTERVAL - TFU_RECPREQ_DLDELTA));
581 dlSf = rgSCHUtlSubFrmGet (cell, repTime);
582 queue = &(dlSf->ueLst);
583 rgSchAckNackRepUtlHdlTti (cell, queue);
588 /** @brief This function Marks the UE as ackNakRep so that Reception request
589 * isnt sent for any other thing than HARQ.
596 * - Loop through HARQ procs of the DlSf.
597 * - If the UE is a repeating one
598 * - Mark as ackNakRep = TRUE
601 * @param RgSchCellCb *cell
602 * @param CmLListCp *ackNakRepQ
605 static Void rgSchAckNackRepUtlHdlTti(RgSchCellCb *cell,CmLListCp *ackNackRepQ)
610 node = ackNackRepQ->first;
613 ue = (RgSchUeCb *)(node->node);
614 if ((NULLP != ue) && (ue->ackNakRepCb.isAckNackEnabled))
616 ue->ackNakRepCb.isAckNakRep = TRUE;
617 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_ACKNACK_REP,
618 ue->ackNakRepCb.repCntr);
626 /** @brief This function
640 static Void rgSCHMeasGapANRepUtlHdlTti(RgSchCellCb *cell,CmLListCp *measGapQ)
645 node = measGapQ->first;
648 ue = (RgSchUeCb*)node->node;
649 ue->measGapCb.isMeasuring = TRUE;
650 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_MEASGAP, RG_SCH_MEAS_GAP_LEN);
658 * @brief Determines the list of UEs inactive for DL scheduling due to
659 * measurement gap and ack nack repetitions
663 * Function : rgSCHMeasGapANRepGetDlInactvUe
665 * Invoking Module Processing:
666 * - This API shall be invoked to get list of inactive UEs for downlink
667 * scheduling due to measurement gaps and ACK NACK repetitions.
670 * - Compute qOffset for 40ms or 80ms queue as =
671 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe + DL_DELTA +
672 * RG_SCH_CMN_HARQ_INTERVAL)
673 * % RG_MEAS_GAPPRD_40 or RG_MEAS_GAPPRD_80.
674 * - Add all the UEs at computed offset to dlInactvUeLst since the
675 * DL transmission or feedback transmission from UE for DL
676 * transmissions shall collide with measurement gap.
677 * - Mark each UE. Set dlInactvMask |= RG_MEASGAP_INACTIVE
678 * - Start measGapDlInactvTmr timer for each UE,
679 * - length = RG_MEAS_GAP_LEN + RG_SCH_CMN_HARQ_INTERVAL
680 * - event = RG_MEASGAP_DLINACTV
681 * - handler = rgSCHMeasGapANRepDlInactvTmrExpry
682 * - Compute qOffset for ACK NACK repetition queue as =
683 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe + DL_DELTA +
684 * RG_SCH_CMN_HARQ_INTERVAL -1)
686 * - Add all the UEs at computed offset to dlInactvUeLst since the
687 * feedback transmission from UE for DL transmissions shall
688 * collide with ACK NACK repetition of the UE.
689 * - Mark each UE. Set dlInactvMask |= RG_ACKNAKREP_INACTIVE
690 * - Start ackNakRepDlInactvTmr timer for each UE,
691 * - length = repCntr - 1
692 * - event = RG_ACKNAKREP_DLINACTV
693 * - handler = rgSCHMeasGapANRepDlInactvTmrExpry
694 * - Verify the above computations before coding
698 * @param[in] RgSchCellCb *cell
699 * @param[out] CmLListCp *dlInactvUeLst
703 S16 rgSCHMeasGapANRepGetDlInactvUe(RgSchCellCb *cell,CmLListCp *dlInactvUeLst)
711 CmLteTimingInfo ackNakTime;
713 uint8_t harqFdbkOffset;
717 RgSchDlHqProcCb *hqP;
721 schedTime = cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + RG_DL_DELTA;
724 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, RG_DL_DELTA);
725 if(rgSchTddUlDlSubfrmTbl[cell->ulDlCfgIdx][ackNakTime.subframe] !=
726 RG_SCH_TDD_DL_SUBFRAME)
731 dlSf = rgSCHUtlSubFrmGet (cell, ackNakTime);
732 if(dlSf->dlFdbkInfo.sfnOffset > 0)
735 (dlSf->dlFdbkInfo.sfnOffset - 1) * RGSCH_NUM_SUB_FRAMES+ \
736 RGSCH_NUM_SUB_FRAMES - ackNakTime.subframe + \
737 dlSf->dlFdbkInfo.subframe;
741 harqFdbkOffset = dlSf->dlFdbkInfo.subframe - ackNakTime.subframe;
744 harqFdbkOffset = RG_SCH_CMN_HARQ_INTERVAL;
746 /* Calc offset for Measurement gap 40 */
747 offset = (schedTime + harqFdbkOffset) % RG_MEAS_GAPPRD_40;
748 queue = &(cell->measGapCb.gapPrd40Q[offset]);
753 ue = (RgSchUeCb*)node->node;
754 ue->dl.dlInactvMask |= RG_MEASGAP_INACTIVE;
755 /* Add to the inactv list */
756 ue->dl.dlInactvLnk.node = (PTR)ue;
757 cmLListAdd2Tail (dlInactvUeLst, &(ue->dl.dlInactvLnk));
759 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_DL_MEASGAP,
760 (RG_SCH_MEAS_GAP_LEN + harqFdbkOffset));
764 /* Calc offset for Measurement gap 80 */
765 offset = (schedTime + harqFdbkOffset) % RG_MEAS_GAPPRD_80;
766 queue = &(cell->measGapCb.gapPrd80Q[offset]);
771 ue = (RgSchUeCb*)node->node;
772 ue->dl.dlInactvMask |= RG_MEASGAP_INACTIVE;
773 /* Add to the inactv list */
774 ue->dl.dlInactvLnk.node = (PTR)ue;
775 cmLListAdd2Tail (dlInactvUeLst, &(ue->dl.dlInactvLnk));
777 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_DL_MEASGAP,
778 (RG_SCH_MEAS_GAP_LEN + harqFdbkOffset));
782 /* Calc offset for ACK NACK repetition */
783 /*offset = (cell->crntTime.sfn * 10 +
784 cell->crntTime.slot + RG_DL_DELTA + RG_SCH_CMN_HARQ_INTERVAL - 1)
786 /* The ackNakRepQ resides in each dlSf corresponding to the repStart */
787 /* Must pick up the subframe that was scheduled in the last TTI */
789 if(cell->ulDlCfgIdx == 5)
793 rgSCHUtlGetPrevDlSfInfo(cell, ackNakTime, &ackNakTime, &repCntr);
794 dlSf = rgSCHUtlSubFrmGet (cell, ackNakTime);
795 /* crnt DL subframe */
796 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, RG_DL_DELTA);
800 /* Go to the subframe being scheduled */
801 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, RG_DL_DELTA);
802 /* Go to the previous subframe */
803 RGSCHDECRFRMCRNTTIME(ackNakTime, ackNakTime, 1);
807 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime,
810 dlSf = rgSCHUtlSubFrmGet (cell, ackNakTime);
812 queue = &(dlSf->ueLst);
817 ue = (RgSchUeCb *)(node->node);
819 hqNode = ue->dl.dlSfHqInfo[cell->cellId][dlSf->dlIdx].hqPLst.first;
822 hqP = (RgSchDlHqProcCb *)hqNode->node;
823 hqNode = hqNode->next;
824 for (i = 0;(i<2) && (hqP->tbInfo[i].state == HQ_TB_WAITING);i++)
826 tbCb = &hqP->tbInfo[i];
827 if (tbCb->fbkRepCntr > 0)
829 ue->dl.dlInactvMask |= RG_ACKNAKREP_INACTIVE;
830 /* Check if already added to the list */
831 if (!(ue->dl.dlInactvMask & RG_MEASGAP_INACTIVE))
833 /* Add to the inactv list */
834 ue->dl.dlInactvLnk.node = (PTR)ue;
835 cmLListAdd2Tail (dlInactvUeLst, &(ue->dl.dlInactvLnk));
839 repCntr = rgSCHAckNakRepFindUlDuration(cell, dlSf, ackNakTime,
840 (uint8_t)(ue->ackNakRepCb.repCntr - 1));
841 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_DL_ACKNACK, repCntr);
843 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_DL_ACKNACK,
844 (ue->ackNakRepCb.repCntr - 1));
854 * @brief Determines the list of UEs inactive for UL scheduling due to
855 * measurement gap and ack nack repetitions
859 * Function : rgSCHMeasGapANRepGetUlInactvUe
861 * Invoking Module Processing:
862 * - This API shall be invoked to get list of inactive UEs for uplink
863 * scheduling due to measurement gaps and ACK NACK repetitions.
866 * - Compute qOffset for 40ms or 80ms queue as =
867 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe + TFU_DELTA +
868 * RG_SCH_CMN_HARQ_INTERVAL)
869 * % RG_MEAS_GAPPRD_40 or RG_MEAS_GAPPRD_80.
870 * - Add all the UEs at computed offset to ulInactvUeLst since the UL
871 * transmissions shall collide with measurement gap.
872 * - Mark each UE. Set ulInactvMask |= RG_MEASGAP_INACTIVE
873 * - Start measGapUlInactvTmr timer for each UE
874 * - length = RG_MEAS_GAP_LEN
875 * - event = RG_MEASGAP_ULINACTV
876 * - handler = rgSCHMeasGapANRepUlInactvTmrExpry
877 * - Compute qOffset for ACK NACK repetition queue as =
878 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe + TFU_DELTA +
879 * RG_SCH_CMN_HARQ_INTERVAL)
881 * - Add all the UEs at computed offset to ulInactvUeLst since the
882 * feedback transmission from UE for DL transmissions shall
883 * collide with repeating ACK ACK-NACKs.
884 * - Mark each UE. Set ulInactvMask |= RG_ACKNAKREP_INACTIVE
885 * - Start ackNakRepUlInactv timer for each UE
887 * - event = RG_ACKNAKREP_ULINACTV
888 * - handler = rgSCHMeasGapANRepUlInactvTmrExpry
889 * - Verify the above computations before coding
892 * @param[in] RgSchCellCb *cell
893 * @param[out] CmLListCp *ulInactvUeLst
898 S16 rgSCHMeasGapANRepGetUlInactvUe(RgSchCellCb *cell,CmLListCp *ulInactvUeLst)
906 CmLteTimingInfo ackNakTime;
909 uint8_t pdcchToPuschGap;
914 RgSchDlHqProcCb *hqP;
918 /*ccpu00139481- Meas Gap should be monitored in UL with TFU_ULCNTRL_DLDELTA*/
919 schedTime = cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + \
922 pdcchToPuschGap = RGSCH_PDCCH_PUSCH_DELTA;
924 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, TFU_ULCNTRL_DLDELTA);
925 pdcchToPuschGap = rgSchTddPuschTxKTbl[cell->ulDlCfgIdx][ackNakTime.subframe];
926 for(idx=0; pdcchToPuschGap && (idx< (pdcchToPuschGap+RG_SCH_MEAS_GAP_LEN)) ; idx++)
929 /* Calc offset for Measurement gap 40 */
930 offset = (schedTime + pdcchToPuschGap -idx + RG_MEAS_GAPPRD_40) % RG_MEAS_GAPPRD_40;
931 queue = &(cell->measGapCb.gapPrd40Q[offset]);
935 ue = (RgSchUeCb*)node->node;
936 if(!(ue->ul.ulInactvMask & RG_MEASGAP_INACTIVE))
938 ue->ul.ulInactvMask |= RG_MEASGAP_INACTIVE;
939 /* Add to the inactv list */
940 ue->ul.ulInactvLnk.node = (PTR)ue;
941 cmLListAdd2Tail (ulInactvUeLst, &(ue->ul.ulInactvLnk));
942 /* Start timer Note the timer is started for a value GAP_LEN +
943 * RG_SCH_CMN_HARQ_INTERVAL. The "4"
944 * is added because for UE to transmit, the PDCCH must be sent 4 subframes
945 * ahead - UE cant read PDCCH format0 if it is in measurement gap. */
946 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_UL_MEASGAP,
947 (RG_SCH_MEAS_GAP_LEN + pdcchToPuschGap - idx));
948 //DU_LOG("\nINFO --> SCH : Starting Meas Gap 40 @ DL TTI- (%d:%d) K-%d offset-%d Len %d \n", ackNakTime.sfn,\
949 ackNakTime.subframe, harqFdbkOffset, offset, RG_SCH_MEAS_GAP_LEN + harqFdbkOffset-idx);
954 /* Calc offset for Measurement gap 80 */
955 offset = (schedTime + pdcchToPuschGap - idx + RG_MEAS_GAPPRD_80) % RG_MEAS_GAPPRD_80;
956 queue = &(cell->measGapCb.gapPrd80Q[offset]);
961 ue = (RgSchUeCb*)node->node;
962 if(!(ue->ul.ulInactvMask & RG_MEASGAP_INACTIVE))
964 ue->ul.ulInactvMask |= RG_MEASGAP_INACTIVE;
965 /* Add to the inactv list */
966 ue->ul.ulInactvLnk.node = (PTR)ue;
967 cmLListAdd2Tail (ulInactvUeLst, &(ue->ul.ulInactvLnk));
969 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_UL_MEASGAP,
970 (RG_SCH_MEAS_GAP_LEN + pdcchToPuschGap - idx));
971 //DU_LOG("\nINFO --> SCH : Starting Meas Gap 80 @ DL TTI- (%d:%d) K-%d offset-%d Len %d \n", ackNakTime.sfn,\
972 ackNakTime.subframe, harqFdbkOffset, offset, RG_SCH_MEAS_GAP_LEN + harqFdbkOffset-idx);
977 /* Calc offset for ACK NACK repetition */
978 /*offset = (cell->crntTime.sfn * 10 +
979 cell->crntTime.slot + RG_UL_SCHED_DELTA +
980 RG_SCH_CMN_HARQ_INTERVAL ) % RG_MAX_NUM_DLSF;*/
982 /* Must get the DLSF that is scheduled at TFU_DELTA Away */
984 if(cell->ulDlCfgIdx == 5)
988 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, TFU_DELTA);
989 if(rgSchTddUlDlSubfrmTbl[cell->ulDlCfgIdx][ackNakTime.subframe] !=
990 RG_SCH_TDD_DL_SUBFRAME)
995 /* Introduced timing delta for DL control in FDD */
996 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, TFU_DLCNTRL_DLDELTA);
998 dlSf = rgSCHUtlSubFrmGet (cell, ackNakTime);
999 queue = &(dlSf->ueLst);
1001 node = queue->first;
1004 ue = (RgSchUeCb *)(node->node);
1006 hqNode = ue->dl.dlSfHqInfo[cell->cellId][dlSf->dlIdx].hqPLst.first;
1009 hqP = (RgSchDlHqProcCb *)hqNode->node;
1010 hqNode = hqNode->next;
1011 for (i = 0;(i<2) && (hqP->tbInfo[i].state == HQ_TB_WAITING);i++)
1013 tbCb = &hqP->tbInfo[i];
1014 if (tbCb->fbkRepCntr > 0)
1016 ue->ul.ulInactvMask |= RG_ACKNAKREP_INACTIVE;
1017 /* Check if already added to the list */
1018 if (!(ue->ul.ulInactvMask & RG_MEASGAP_INACTIVE))
1020 /* Add to the inactv list */
1021 ue->ul.ulInactvLnk.node = (PTR)ue;
1022 cmLListAdd2Tail (ulInactvUeLst, &(ue->ul.ulInactvLnk));
1026 repCntr = rgSCHAckNakRepFindUlDuration(cell, dlSf, ackNakTime,
1027 ue->ackNakRepCb.repCntr);
1028 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_UL_ACKNACK, repCntr);
1030 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_UL_ACKNACK,
1031 (ue->ackNakRepCb.repCntr));
1041 * @brief Handles processing of DL Inactive timer expiry at the end of
1042 * measurement gap or ack nack repetition for a UE
1046 * Function : rgSCHMeasGapANRepDlInactvTmrExpry
1048 * Invoking Module Processing:
1049 * - This API shall be invoked to process DL inactive timer expiry
1052 * - If timer event is RG_MEASGAP_DLINACTV,
1053 * - dlInactvMask &= ~RG_MEASGAP_INACTIVE
1054 * - If timer event is RG_ACKNAKREP_DLINACTV,
1055 * - dlInactvMask &= ~RG_ACKNAKREP_INACTIVE
1056 * - if (!dlInactvMask)
1057 * - Invoke DL scheduler to put the UE back into the scheduling queues.
1058 * - Re-initialize timer.
1061 * @param[in] RgSchUeCb *ue
1062 * @param[in] Check if some timer related parameter needs to be passed
1067 Void rgSCHMeasGapANRepDlInactvTmrExpry(RgSchUeCb *ue,uint8_t tmrEvnt)
1070 RgSchCellCb *cell = ue->cell;
1074 case RG_SCH_TMR_DL_MEASGAP:
1075 RG_SCH_CMN_DL_UPDT_INACTV_MASK ( cell, ue, RG_MEASGAP_INACTIVE);
1077 case RG_SCH_TMR_DL_ACKNACK:
1078 RG_SCH_CMN_DL_UPDT_INACTV_MASK ( cell, ue, RG_ACKNAKREP_INACTIVE);
1081 if (!ue->dl.dlInactvMask)
1083 cmInitTimers (&ue->measGapCb.measGapDlInactvTmr, 1);
1084 cmInitTimers (&ue->ackNakRepCb.ackNakRepDlInactvTmr, 1);
1090 * @brief Handles processing of UL Inactive timer expiry at the end of
1091 * measurement gap or ack nack repetition for a UE
1095 * Function : rgSCHMeasGapANRepUlInactvTmrExpry
1097 * Invoking Module Processing:
1098 * - This API shall be invoked to process UL inactive timer expiry
1101 * - If timer event is RG_MEASGAP_ULINACTV,
1102 * - ulInactvMask &= ~RG_MEASGAP_INACTIVE
1103 * - If timer event is RG_ACKNAKREP_ULINACTV,
1104 * - ulInactvMask &= ~RG_ACKNAKREP_INACTIVE
1105 * - if (!ulInactvMask)
1106 * - Invoke UL scheduler to put the UE back into the scheduling queues.
1107 * - Re-initialize timer.
1110 * @param[in] RgSchUeCb *ue
1111 * @param[in] Check if some timer related parameter needs to be passed
1116 Void rgSCHMeasGapANRepUlInactvTmrExpry(RgSchUeCb *ue,uint8_t tmrEvnt)
1118 RgSchCellCb *cell = ue->cell;
1122 case RG_SCH_TMR_UL_MEASGAP:
1123 RG_SCH_CMN_UL_UPDT_INACTV_MASK ( cell, ue, RG_MEASGAP_INACTIVE);
1125 case RG_SCH_TMR_UL_ACKNACK:
1126 RG_SCH_CMN_UL_UPDT_INACTV_MASK ( cell, ue, RG_ACKNAKREP_INACTIVE);
1129 if (!ue->ul.ulInactvMask)
1131 cmInitTimers (&ue->measGapCb.measGapUlInactvTmr, 1);
1132 cmInitTimers (&ue->ackNakRepCb.ackNakRepUlInactvTmr, 1);
1138 * @brief Handles processing of measurement gap timer expiry at the end of
1143 * Function : rgSCHMeasGapANRepTmrExpry
1145 * Invoking Module Processing:
1146 * - This API shall be invoked to process measurement gap timer expiry
1149 * - Set ue->isMeasuring = FALSE
1150 * - Re-initialize timer.
1153 * @param[in] RgSchUeCb *ue
1154 * @param[in] Check if some timer related parameter needs to be passed
1159 Void rgSCHMeasGapANRepTmrExpry(RgSchUeCb *ue)
1162 ue->measGapCb.isMeasuring = FALSE;
1163 cmInitTimers (&ue->measGapCb.measGapTmr, 1);
1169 * @brief Handles processing of ACK-NACK repetition timer expiry at the end of
1170 * ACK-NACK repetition.
1174 * Function : rgSchAckNakRepTmrExpry
1176 * Invoking Module Processing:
1177 * - This API shall be invoked to process ACK-NACK repetition timer expiry
1180 * - Set ue->isAckNakRep = FALSE
1181 * - Re-initialize timer.
1184 * @param[in] RgSchUeCb *ue
1185 * @param[in] Check if some timer related parameter needs to be passed
1190 Void rgSCHAckNakRepTmrExpry(RgSchUeCb *ue)
1193 ue->ackNakRepCb.isAckNakRep = FALSE;
1194 cmInitTimers (&ue->ackNakRepCb.ackNakRepTmr, 1);
1201 * @brief Adds ACK-NACK repeating UEs to the ackNakRepQ
1205 * Function : rgSchAckNakRepAddToQ
1207 * Invoking Module Processing:
1208 * - This API shall be invoked for adding list of UEs to the ACK-NACK
1209 * repeating queue at appropriate poistion. Invoking module shall invoke
1210 * with the list of ACK-NACK repeating UEs for a sub-frame and timing info
1211 * at which ACK NACK repetition shall start for the UEs.
1214 * - Determine the qOffset depending on the timing info as
1215 * - qOffset = (repStartTime->sfn *10 + repStartTime->subframe) % RG_MAX_NUM_DLSF
1216 * - Initialize the list at the qOffset.
1217 * - For each UE in the list,
1218 * - Add the UE to ackNakRepQ to the list at the determined qOffset.
1219 * - Set ue->qOffset = qOffset
1220 * - Initialize timers.
1223 * @param[in] RgSchCellCb *cell
1224 * @param[in] RgSchDlSf *crntDlSf
1225 * @param[in] CmLteTimingInfo repStartTime
1231 Void rgSCHAckNakRepAddToQ(RgSchCellCb *cell,RgSchDlSf *crntDlSf)
1236 RgSchDlHqProcCb *hqP;
1237 RgSchDlHqTbCb *tbCb;
1240 node = crntDlSf->ueLst.first;
1243 ue = (RgSchUeCb *)(node->node);
1245 hqNode = ue->dl.dlSfHqInfo[cell->cellId][crntDlSf->dlIdx].hqPLst.first;
1248 hqP = (RgSchDlHqProcCb *)hqNode->node;
1249 hqNode = hqNode->next;
1250 for (i = 0;(i<2) && (hqP->tbInfo[i].state == HQ_TB_WAITING);i++)
1252 tbCb = &hqP->tbInfo[i];
1253 /* Add UEs that have enabled ACK NACK repetition */
1254 if (ue->ackNakRepCb.isAckNackEnabled)
1256 tbCb->fbkRepCntr = ue->ackNakRepCb.cfgRepCnt;
1257 tbCb->fbkRecpRepCntr = ue->ackNakRepCb.cfgRepCnt;
1258 /* Removed init of timers as the init will be happening during
1259 * config or timer expiry*/
1270 * @brief Finds the number of subframes used for ACK-NACK cycle
1274 * Function : rgSCHAckNakRepFindUlDuration
1276 * This function finds the number of subframes required
1277 * for ACK-NACK repetition cycle based on UL subframes.
1279 * @param[in] RgSchCellCb *cell
1280 * @param[in] RgSchDlSf *dlSf
1281 * @param[in] CmLteTimingInfo repTime
1282 * @param[in] uint8_t repCnt
1288 static uint8_t rgSCHAckNakRepFindUlDuration(RgSchCellCb *cell,RgSchDlSf *dlSf,CmLteTimingInfo repTime,uint8_t repCnt)
1290 CmLteTimingInfo ulfrm;
1291 uint8_t noSubfrms = 0;
1292 uint16_t ulDlCfgIdx = cell->ulDlCfgIdx;
1297 rgSCHAckNakRepGetUlOffsetFrmDl(dlSf, repTime, &noSubfrms);
1298 RG_SCH_ADD_TO_CRNT_TIME(repTime, ulfrm, noSubfrms);
1300 idx = ulfrm.subframe;
1303 idx = (idx + 1) % RGSCH_NUM_SUB_FRAMES;
1304 if(rgSchTddUlDlSubfrmTbl[ulDlCfgIdx][idx] ==
1305 RG_SCH_TDD_UL_SUBFRAME)
1317 * @brief Finds the number of subframes used for ACK-NACK cycle
1321 * Function : rgSCHAckNakRepGetUlOffsetFrmDl
1323 * This function finds the number of subframes after
1324 * which UL subframes are present for the gicen DL
1327 * @param[in] RgSchDlSf *dlSf
1328 * @param[in] CmLteTimingInfo crntDlTime
1329 * @param[in] uint8_t *noSubfrms
1335 static Void rgSCHAckNakRepGetUlOffsetFrmDl(RgSchDlSf *dlSf,CmLteTimingInfo crntDlTime,uint8_t *noSubfrms )
1338 if(dlSf->dlFdbkInfo.sfnOffset != 0)
1340 *noSubfrms = (dlSf->dlFdbkInfo.sfnOffset - 1) * RGSCH_NUM_SUB_FRAMES;
1341 *noSubfrms = *noSubfrms + RGSCH_NUM_SUB_FRAMES - crntDlTime.subframe;
1342 *noSubfrms = *noSubfrms + dlSf->dlFdbkInfo.subframe;
1346 *noSubfrms = dlSf->dlFdbkInfo.subframe - crntDlTime.subframe;
1352 /**********************************************************************
1355 **********************************************************************/