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"
46 /* header/extern include files (.x) */
47 #include "tfu.x" /* RGU types */
48 #include "lrg.x" /* layer management typedefs for MAC */
49 #include "rgr.x" /* layer management typedefs for MAC */
50 #include "rg_sch_inf.x" /* typedefs for Scheduler */
51 #include "rg_sch.x" /* typedefs for Scheduler */
54 static S16 rgSCHMeasGapANRepUtlAddUe ARGS((
57 RgrUeMeasGapCfg *cfg));
59 static S16 rgSCHMeasGapANRepUtlRmvUe ARGS((
63 static S16 rgSchAckNackRepUtlRmvUe ARGS((
67 static Void rgSchAckNackRepUtlHdlTti ARGS((
69 CmLListCp *ackNackRepQ));
71 static Void rgSCHMeasGapANRepUtlHdlTti ARGS((
73 CmLListCp *measGapQ));
75 static uint8_t rgSCHAckNakRepFindUlDuration ARGS((
78 CmLteTimingInfo repTime,
80 static Void rgSCHAckNakRepGetUlOffsetFrmDl ARGS((
82 CmLteTimingInfo crntDlTime,
87 * @brief Handles Measurement gap and ack-nack repetition related
88 * configuration for a UE.
92 * Function : rgSCHMeasGapANRepUeCfg
94 * Invoking Module Processing:
95 * - This shall be invoked by SCH_GOM at UE configuration. It shall do the
96 * validations for the spec-defined values.
99 * - For UE-specific measurement gap related configuration,
100 * - If measurementGap is configured,
101 * - Update UE with the configured values.
102 * - Add Ue to cell->measGapCb->gapPrdQ depending on the gap period
103 * configuration at index = the configured gap offset.
104 * - measGapOffst = the configured gap offset
105 * - Initialize timers.
107 * - measGapOffst = RG_INVALID_MEASGAPQ_ID
108 * - For UE-specific ACK-NACK repetition related configuration,
109 * - Update the configured value. Set 'cfgRepCnt' variable value.
110 * - repCntr = cfgRepCnt.
111 * - qOffst = RG_INVALID_ACKNACKREPQ_ID
114 * @param[in] RgSchCellCb *cell
115 * @param[in] RgSchUeCb *ue
116 * @param[in] RgrUeCfg *ueCfg
122 S16 rgSCHMeasGapANRepUeCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeCfg *ueCfg)
125 ue->measGapCb.isMesGapEnabled = ueCfg->ueMesGapCfg.isMesGapEnabled;
127 if (ueCfg->ueMesGapCfg.isMesGapEnabled)
129 ue->measGapCb.gapPrd = ueCfg->ueMesGapCfg.gapPrd;
130 ue->measGapCb.gapOffst = ueCfg->ueMesGapCfg.gapOffst;
131 rgSCHMeasGapANRepUtlAddUe (cell, ue, &(ueCfg->ueMesGapCfg));
132 cmInitTimers (&ue->measGapCb.measGapTmr, 1);
133 cmInitTimers (&ue->measGapCb.measGapUlInactvTmr, 1);
134 cmInitTimers (&ue->measGapCb.measGapDlInactvTmr, 1);
137 /* ACK NACK repetition part */
138 if (ueCfg->ueAckNackCfg.isAckNackEnabled)
140 ue->ackNakRepCb.cfgRepCnt = ueCfg->ueAckNackCfg.ackNackRepFactor;
141 ue->ackNakRepCb.repCntr = ue->ackNakRepCb.cfgRepCnt;
142 ue->ackNakRepCb.isAckNackEnabled = TRUE;
143 ue->ackNakRepCb.pucchRes = ueCfg->ueAckNackCfg.pucchAckNackRep;
144 cmInitTimers (&ue->ackNakRepCb.ackNakRepUlInactvTmr, 1);
145 cmInitTimers (&ue->ackNakRepCb.ackNakRepDlInactvTmr, 1);
146 cmInitTimers (&ue->ackNakRepCb.ackNakRepTmr, 1);
152 * @brief Handles Measurement gap and ack-nack repetition related
153 * re-configuration for a UE.
157 * Function : rgSCHMeasGapANRepUeRecfg
159 * Invoking Module Processing:
160 * - This shall be invoked by SCH_GOM at UE re-configuration. It shall do the
161 * validations for the spec-defined values.
164 * - For measurement gap,
165 * - If measurement gap period or offset is re-configured, remove UE from
166 * the previous list, if any and add it to the new list.
167 * - Update configured values appropriately.
168 * - For ACK-NACK repetition,
169 * - Update the configured value. Set 'cfgRepCnt' variable value.
170 * - If (repCntr == 0)
171 * - repCntr = cfgRepCnt.
172 * - qOffst = RG_INVALID_ACKNACKREPQ_ID
174 * @param[in] RgSchCellCb *cell
175 * @param[in] RgSchUeCb *ue
176 * @param[in] RgrUeRecfg *ueRecfg
183 S16 rgSCHMeasGapANRepUeRecfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeRecfg *ueRecfg)
185 RgrUeMeasGapCfg *reCfg;
186 RgSchUeMeasGapCb *ueMeasCb;
187 RgrUeAckNackRepCfg *ackNackReCfg = &(ueRecfg->ueAckNackRecfg);
188 RgSchUeAckNakRepCb *ackNakRepCb = &(ue->ackNakRepCb);
190 reCfg = &(ueRecfg->ueMeasGapRecfg);
191 ueMeasCb = &(ue->measGapCb);
193 /* Removed extra comments
194 * Check this once again Check to see if anything changed or not */
195 if ((reCfg->isMesGapEnabled == TRUE) &&
196 (ueMeasCb->isMesGapEnabled == TRUE) &&
197 (reCfg->gapPrd == ueMeasCb->gapPrd) &&
198 (reCfg->gapOffst == ueMeasCb->gapOffst))
200 /* Nothing changed hence nothing to do */
204 if (reCfg->isMesGapEnabled)
206 if (ueMeasCb->isMesGapEnabled)
208 rgSCHMeasGapANRepUtlRmvUe (cell, ue);
212 cmInitTimers (&ueMeasCb->measGapTmr, 1);
213 cmInitTimers (&ueMeasCb->measGapUlInactvTmr, 1);
214 cmInitTimers (&ueMeasCb->measGapDlInactvTmr, 1);
217 /* Add to the correct Measurement gap queue */
218 rgSCHMeasGapANRepUtlAddUe (cell, ue, reCfg);
220 ueMeasCb->gapPrd = reCfg->gapPrd;
221 ueMeasCb->gapOffst = reCfg->gapOffst;
222 ueMeasCb->isMesGapEnabled = TRUE;
223 } /* if new config has Measurement gap enabled */
226 if (ueMeasCb->isMesGapEnabled)
228 /* check if return value needed or not */
229 rgSCHMeasGapANRepUtlRmvUe (cell, ue);
230 ueMeasCb->isMesGapEnabled = FALSE;
232 } /* if new config has Measurement gap disabled */
233 } /* For MeasGap configuration */
235 if (ackNackReCfg->isAckNackEnabled)
237 if (!ackNakRepCb->isAckNackEnabled)
239 ackNakRepCb->isAckNackEnabled = TRUE;
240 /* Timers need to be init immediately after config*/
241 cmInitTimers (&ue->ackNakRepCb.ackNakRepUlInactvTmr, 1);
242 cmInitTimers (&ue->ackNakRepCb.ackNakRepDlInactvTmr, 1);
243 cmInitTimers (&ue->ackNakRepCb.ackNakRepTmr, 1);
244 } /* repetition was disabled */
245 ackNakRepCb->pucchRes = ackNackReCfg->pucchAckNackRep;
246 ackNakRepCb->cfgRepCnt = ackNackReCfg->ackNackRepFactor;
247 if (ackNakRepCb->repCntr == 0)
249 ackNakRepCb->repCntr = ackNackReCfg->ackNackRepFactor;
251 } /* repetition enabled in re configuration */
254 ackNakRepCb->isAckNackEnabled = FALSE;
255 } /* repetition disabled in re configuration */
260 /** @brief This function is a utility to add the UE to the correct Measurement
261 * queue present in the cellCb.
275 static S16 rgSCHMeasGapANRepUtlAddUe(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeMeasGapCfg *cfg)
280 case RG_MEAS_GAPPRD_40:
281 /* Insert the UE into the linked list based on the gap Offset */
282 ue->measGapCb.measQLnk.node = (PTR)ue;
283 cmLListAdd2Tail (&(cell->measGapCb.gapPrd40Q[cfg->gapOffst]),
284 &(ue->measGapCb.measQLnk));
286 case RG_MEAS_GAPPRD_80:
287 ue->measGapCb.measQLnk.node = (PTR)ue;
288 cmLListAdd2Tail (&(cell->measGapCb.gapPrd80Q[cfg->gapOffst]),
289 &(ue->measGapCb.measQLnk));
292 DU_LOG("\nERROR --> SCH : rgSCHMeasGapANRepUeRecfg() Incorrect GAP Period"
293 "CRNTI:%d",ue->ueId);
297 } /* end of rgSCHMeasGapANRepUtlAddUe */
300 /** @brief This function is a utility function to remove the ue from the measQ
301 * preset in tthe cell Cb.
314 static S16 rgSCHMeasGapANRepUtlRmvUe(RgSchCellCb *cell,RgSchUeCb *ue)
317 switch (ue->measGapCb.gapPrd)
319 case RG_MEAS_GAPPRD_40:
320 /* Remove from the existing list */
321 cmLListDelFrm (&(cell->measGapCb.gapPrd40Q[ue->measGapCb.gapOffst]),
322 &(ue->measGapCb.measQLnk));
323 ue->measGapCb.measQLnk.node = NULLP;
325 case RG_MEAS_GAPPRD_80:
326 /* Remove from the existing list */
327 cmLListDelFrm (&(cell->measGapCb.gapPrd80Q[ue->measGapCb.gapOffst]),
328 &(ue->measGapCb.measQLnk));
329 ue->measGapCb.measQLnk.node = NULLP;
333 } /* end of rgSCHMeasGapANRepUtlRmvUe */
336 * @brief Frees Measurement gap and ack-nack repetition related data structures in UE
340 * Function : rgSCHMeasGapANRepUeDel
342 * Invoking Module Processing:
343 * - This shall be invoked by SCH_GOM at Ue deletion.
346 * - For measurement gap,
347 * - if (measGapOffst != RG_INVALID_MEASGAPQ_ID)
348 * - Remove from the measurement queue depending on the measGapPrd
350 * - Delete all timers
351 * - For ACK-NACK repetition,
352 * - if (qOffst != RG_INVALID_ACKNACKREPQ_ID)
353 * - Remove from the ackNakRepQ queue
354 * - Delete all timers
357 * @param[in] RgSchCellCb *cell
358 * @param[in] RgSchUeCb *ue
364 Void rgSCHMeasGapANRepUeDel(RgSchCellCb *cell,RgSchUeCb *ue,Bool isUeDel)
367 if (ue->measGapCb.isMesGapEnabled)
369 rgSCHMeasGapANRepUtlRmvUe (cell, ue);
370 /* Must stop the timer if its running */
371 if (ue->measGapCb.isMeasuring)
373 rgSCHTmrStopTmr (cell, RG_SCH_TMR_MEASGAP, ue);
376 ue->measGapCb.isMesGapEnabled = FALSE;
379 /* Stop timers if running */
380 if (ue->dl.dlInactvMask)
382 if (ue->dl.dlInactvMask & RG_MEASGAP_INACTIVE)
384 rgSCHTmrStopTmr (cell, RG_SCH_TMR_DL_MEASGAP, ue);
386 if (ue->dl.dlInactvMask & RG_ACKNAKREP_INACTIVE)
388 rgSCHTmrStopTmr (cell, RG_SCH_TMR_DL_ACKNACK, ue);
390 ue->dl.dlInactvLnk.node = NULLP;
392 if (ue->ul.ulInactvMask)
394 if (ue->ul.ulInactvMask & RG_MEASGAP_INACTIVE)
396 rgSCHTmrStopTmr (cell, RG_SCH_TMR_UL_MEASGAP, ue);
398 if (ue->ul.ulInactvMask & RG_ACKNAKREP_INACTIVE)
400 rgSCHTmrStopTmr (cell, RG_SCH_TMR_UL_ACKNACK, ue);
402 ue->ul.ulInactvLnk.node = NULLP;
405 /* ccpu00133470- Releasing ACKNACK Rep UE Deleted */
406 if (isUeDel & ue->ackNakRepCb.isAckNakRep)
408 rgSCHTmrStopTmr (cell, RG_SCH_TMR_ACKNACK_REP, ue);
409 rgSchAckNackRepUtlRmvUe (cell, ue);
414 /** @brief This function deletes the UEs information related to ACK NACK
422 * - Mainly we need to remove the UEs hqProcs from the ackNackQ(s)
423 * present in the subframes.
430 static S16 rgSchAckNackRepUtlRmvUe(RgSchCellCb *cell,RgSchUeCb *ue)
436 RgSchDlHqProcCb *hqP;
439 RgSchDlHqEnt *hqEnt = RG_SCH_CMN_GET_UE_HQE(ue, cell);
441 for (hqIdx = 0; hqIdx < hqEnt->numHqPrcs; hqIdx++)
443 hqP = &hqEnt->procs[hqIdx];
444 /* Starting from index 1 as index 0 isn't used */
445 for (repIdx = 1; repIdx < ue->ackNakRepCb.cfgRepCnt; repIdx++)
447 for (tbCnt = 0; tbCnt < 2; tbCnt++)
449 if ((hqP->tbInfo[tbCnt].crntSubfrm[repIdx] != NULLP) &&
450 (hqP->tbInfo[tbCnt].anRepLnk[repIdx].node != NULLP))
452 cmLListDelFrm(&((hqP->tbInfo[tbCnt].crntSubfrm[repIdx])->\
453 ackNakRepQ), &hqP->tbInfo[tbCnt].anRepLnk[repIdx]);
454 hqP->tbInfo[tbCnt].anRepLnk[repIdx].node = NULLP;
455 hqP->tbInfo[tbCnt].crntSubfrm[repIdx] = NULLP;
466 * @brief Per TTI processing for measurement gap and ack nack repetition
471 * Function : rgSCHMeasGapANRepTtiHndl
473 * Invoking Module Processing:
474 * - This shall be invoked by SCH_TOM on recieving TTI indication from PHY
475 * . SCH_TOM shall update the cell->crntTime before invoking this API.
478 * - Compute qOffset for 40ms queue as =
479 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe)%RG_MEAS_GAPPRD_40.
480 * - Mark all the UEs at computed offset for performing measurement. Set
481 * isMeasuring = TRUE.
482 * - Start measGapTmr for each UE:
483 * - length = RG_MEAS_GAP_LEN.
484 * - event = RG_MEASGAP_ON
485 * - handler = rgSCHMeasGapANRepTmrExpry
486 * - Reinitalize the list at the offset.
487 * - Compute qOffset for 80ms queue as =
488 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe)%RG_MEAS_GAPPRD_80.
489 * - Mark all the UEs at computed offset for performing measurement. Set
490 * isMeasuring = TRUE.
491 * - Start measGapTmr for each UE:
492 * - length = RG_MEAS_GAP_LEN.
493 * - event = RG_MEASGAP_ON
494 * - handler = rgSCHMeasGapANRepTmrExpry
495 * - Reinitalize the list at the offset.
496 * - Compute qOffset for ACK NACK repetition queue as =
497 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe)%RG_MAX_NUM_DLSF.
498 * - Mark all the UEs at computed offset for performing ack-nack repetition. Set
499 * isAckNakRep = TRUE.
500 * - Start ackNakRepTmr for each UE:
501 * - length = repCntr.
502 * - event = RG_ACKNAKREP_ON
503 * - handler = rgSchAckNakRepTmrExpry
504 * - Reinitalize the list at the offset.
505 * - 'isMeasuring' bool value shall be cheked
506 * - While sending dataRecpReq to PHY for non-adaptive uplink re-tx
507 * and if 'TRUE', no dataRecpReq shall be sent.
508 * - While sending NACK as feedback to UE and if 'TRUE' no PHICH shall
509 * be sent and shall mark the UE for adaptive re-tx.
510 * - While sending HqFbkRecpReq for a UE (applicable only if ACK NACK
511 * repetition coincides) and if 'TRUE',
512 * - The request shall not be sent.
513 * - Decrement repCntr
514 * - if (repCntr == 0)
515 * - Delete UE from the list.
516 * - Move the Ue to next subframe's list of ACK-NACK repeating UEs.
517 * - 'isAckNakRep' bool value shall be cheked
518 * - While sending dataRecpReq to PHY for non-adaptive uplink re-tx
519 * and if 'TRUE', no dataRecpReq shall be sent.
520 * - Check if any refresh for these cell-specific queues is needed
521 * anywhere else as well.
522 * - Check if TTI miss needs some trigger to the module.
525 * @param[in] RgSchCellCb *cell
531 S16 rgSCHMeasGapANRepTtiHndl(RgSchCellCb *cell)
536 CmLteTimingInfo repTime;
538 /* Measurement GAP Starts at offSet - however at MAC we are concerned at
539 * subframe + TFU_DELTA.
542 /* Introduced timing delta for DL control in FDD */
544 offset = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + TFU_DELTA) %
547 offset = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + TFU_DLCNTRL_DLDELTA) %
550 queue = &(cell->measGapCb.gapPrd40Q[offset]);
551 rgSCHMeasGapANRepUtlHdlTti (cell, queue);
553 /* Introduced timing delta for DL control in FDD */
555 offset = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + TFU_DELTA) %
558 offset = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + TFU_DLCNTRL_DLDELTA) %
561 queue = &(cell->measGapCb.gapPrd80Q[offset]);
562 rgSCHMeasGapANRepUtlHdlTti (cell, queue);
564 /* for ACK NACK repetition starts at offset - however at MAC we are
565 * concerned with subframe - TFU_DELTA */
566 /* offset = ((cell->crntTime.sfn * 10) + cell->crntTime.slot) %
567 * RG_MAX_NUM_DLSF; */
568 /* We wish to get the subframe whose HARQ Reception request would go out in
569 * this subframe. HARQ_RTT - TFU_DELTA
571 /* Introduced timing delta for reception req */
574 //RGSCHSUBFRMCRNTTIME(cell->crntTime, repTime, (4 - TFU_DELTA));
575 RGSCHDECRFRMCRNTTIME(cell->crntTime, repTime, (RG_SCH_CMN_HARQ_INTERVAL - TFU_RECPREQ_DLDELTA));
577 RGSCHDECRFRMCRNTTIME(cell->crntTime, repTime, (RG_SCH_CMN_HARQ_INTERVAL - TFU_RECPREQ_DLDELTA));
579 dlSf = rgSCHUtlSubFrmGet (cell, repTime);
580 queue = &(dlSf->ueLst);
581 rgSchAckNackRepUtlHdlTti (cell, queue);
586 /** @brief This function Marks the UE as ackNakRep so that Reception request
587 * isnt sent for any other thing than HARQ.
594 * - Loop through HARQ procs of the DlSf.
595 * - If the UE is a repeating one
596 * - Mark as ackNakRep = TRUE
599 * @param RgSchCellCb *cell
600 * @param CmLListCp *ackNakRepQ
603 static Void rgSchAckNackRepUtlHdlTti(RgSchCellCb *cell,CmLListCp *ackNackRepQ)
608 node = ackNackRepQ->first;
611 ue = (RgSchUeCb *)(node->node);
612 if ((NULLP != ue) && (ue->ackNakRepCb.isAckNackEnabled))
614 ue->ackNakRepCb.isAckNakRep = TRUE;
615 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_ACKNACK_REP,
616 ue->ackNakRepCb.repCntr);
624 /** @brief This function
638 static Void rgSCHMeasGapANRepUtlHdlTti(RgSchCellCb *cell,CmLListCp *measGapQ)
643 node = measGapQ->first;
646 ue = (RgSchUeCb*)node->node;
647 ue->measGapCb.isMeasuring = TRUE;
648 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_MEASGAP, RG_SCH_MEAS_GAP_LEN);
656 * @brief Determines the list of UEs inactive for DL scheduling due to
657 * measurement gap and ack nack repetitions
661 * Function : rgSCHMeasGapANRepGetDlInactvUe
663 * Invoking Module Processing:
664 * - This API shall be invoked to get list of inactive UEs for downlink
665 * scheduling due to measurement gaps and ACK NACK repetitions.
668 * - Compute qOffset for 40ms or 80ms queue as =
669 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe + DL_DELTA +
670 * RG_SCH_CMN_HARQ_INTERVAL)
671 * % RG_MEAS_GAPPRD_40 or RG_MEAS_GAPPRD_80.
672 * - Add all the UEs at computed offset to dlInactvUeLst since the
673 * DL transmission or feedback transmission from UE for DL
674 * transmissions shall collide with measurement gap.
675 * - Mark each UE. Set dlInactvMask |= RG_MEASGAP_INACTIVE
676 * - Start measGapDlInactvTmr timer for each UE,
677 * - length = RG_MEAS_GAP_LEN + RG_SCH_CMN_HARQ_INTERVAL
678 * - event = RG_MEASGAP_DLINACTV
679 * - handler = rgSCHMeasGapANRepDlInactvTmrExpry
680 * - Compute qOffset for ACK NACK repetition queue as =
681 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe + DL_DELTA +
682 * RG_SCH_CMN_HARQ_INTERVAL -1)
684 * - Add all the UEs at computed offset to dlInactvUeLst since the
685 * feedback transmission from UE for DL transmissions shall
686 * collide with ACK NACK repetition of the UE.
687 * - Mark each UE. Set dlInactvMask |= RG_ACKNAKREP_INACTIVE
688 * - Start ackNakRepDlInactvTmr timer for each UE,
689 * - length = repCntr - 1
690 * - event = RG_ACKNAKREP_DLINACTV
691 * - handler = rgSCHMeasGapANRepDlInactvTmrExpry
692 * - Verify the above computations before coding
696 * @param[in] RgSchCellCb *cell
697 * @param[out] CmLListCp *dlInactvUeLst
701 S16 rgSCHMeasGapANRepGetDlInactvUe(RgSchCellCb *cell,CmLListCp *dlInactvUeLst)
709 CmLteTimingInfo ackNakTime;
711 uint8_t harqFdbkOffset;
715 RgSchDlHqProcCb *hqP;
719 schedTime = cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + RG_DL_DELTA;
722 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, RG_DL_DELTA);
723 if(rgSchTddUlDlSubfrmTbl[cell->ulDlCfgIdx][ackNakTime.subframe] !=
724 RG_SCH_TDD_DL_SUBFRAME)
729 dlSf = rgSCHUtlSubFrmGet (cell, ackNakTime);
730 if(dlSf->dlFdbkInfo.sfnOffset > 0)
733 (dlSf->dlFdbkInfo.sfnOffset - 1) * RGSCH_NUM_SUB_FRAMES+ \
734 RGSCH_NUM_SUB_FRAMES - ackNakTime.subframe + \
735 dlSf->dlFdbkInfo.subframe;
739 harqFdbkOffset = dlSf->dlFdbkInfo.subframe - ackNakTime.subframe;
742 harqFdbkOffset = RG_SCH_CMN_HARQ_INTERVAL;
744 /* Calc offset for Measurement gap 40 */
745 offset = (schedTime + harqFdbkOffset) % RG_MEAS_GAPPRD_40;
746 queue = &(cell->measGapCb.gapPrd40Q[offset]);
751 ue = (RgSchUeCb*)node->node;
752 ue->dl.dlInactvMask |= RG_MEASGAP_INACTIVE;
753 /* Add to the inactv list */
754 ue->dl.dlInactvLnk.node = (PTR)ue;
755 cmLListAdd2Tail (dlInactvUeLst, &(ue->dl.dlInactvLnk));
757 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_DL_MEASGAP,
758 (RG_SCH_MEAS_GAP_LEN + harqFdbkOffset));
762 /* Calc offset for Measurement gap 80 */
763 offset = (schedTime + harqFdbkOffset) % RG_MEAS_GAPPRD_80;
764 queue = &(cell->measGapCb.gapPrd80Q[offset]);
769 ue = (RgSchUeCb*)node->node;
770 ue->dl.dlInactvMask |= RG_MEASGAP_INACTIVE;
771 /* Add to the inactv list */
772 ue->dl.dlInactvLnk.node = (PTR)ue;
773 cmLListAdd2Tail (dlInactvUeLst, &(ue->dl.dlInactvLnk));
775 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_DL_MEASGAP,
776 (RG_SCH_MEAS_GAP_LEN + harqFdbkOffset));
780 /* Calc offset for ACK NACK repetition */
781 /*offset = (cell->crntTime.sfn * 10 +
782 cell->crntTime.slot + RG_DL_DELTA + RG_SCH_CMN_HARQ_INTERVAL - 1)
784 /* The ackNakRepQ resides in each dlSf corresponding to the repStart */
785 /* Must pick up the subframe that was scheduled in the last TTI */
787 if(cell->ulDlCfgIdx == 5)
791 rgSCHUtlGetPrevDlSfInfo(cell, ackNakTime, &ackNakTime, &repCntr);
792 dlSf = rgSCHUtlSubFrmGet (cell, ackNakTime);
793 /* crnt DL subframe */
794 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, RG_DL_DELTA);
798 /* Go to the subframe being scheduled */
799 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, RG_DL_DELTA);
800 /* Go to the previous subframe */
801 RGSCHDECRFRMCRNTTIME(ackNakTime, ackNakTime, 1);
805 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime,
808 dlSf = rgSCHUtlSubFrmGet (cell, ackNakTime);
810 queue = &(dlSf->ueLst);
815 ue = (RgSchUeCb *)(node->node);
817 hqNode = ue->dl.dlSfHqInfo[cell->cellId][dlSf->dlIdx].hqPLst.first;
820 hqP = (RgSchDlHqProcCb *)hqNode->node;
821 hqNode = hqNode->next;
822 for (i = 0;(i<2) && (hqP->tbInfo[i].state == HQ_TB_WAITING);i++)
824 tbCb = &hqP->tbInfo[i];
825 if (tbCb->fbkRepCntr > 0)
827 ue->dl.dlInactvMask |= RG_ACKNAKREP_INACTIVE;
828 /* Check if already added to the list */
829 if (!(ue->dl.dlInactvMask & RG_MEASGAP_INACTIVE))
831 /* Add to the inactv list */
832 ue->dl.dlInactvLnk.node = (PTR)ue;
833 cmLListAdd2Tail (dlInactvUeLst, &(ue->dl.dlInactvLnk));
837 repCntr = rgSCHAckNakRepFindUlDuration(cell, dlSf, ackNakTime,
838 (uint8_t)(ue->ackNakRepCb.repCntr - 1));
839 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_DL_ACKNACK, repCntr);
841 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_DL_ACKNACK,
842 (ue->ackNakRepCb.repCntr - 1));
852 * @brief Determines the list of UEs inactive for UL scheduling due to
853 * measurement gap and ack nack repetitions
857 * Function : rgSCHMeasGapANRepGetUlInactvUe
859 * Invoking Module Processing:
860 * - This API shall be invoked to get list of inactive UEs for uplink
861 * scheduling due to measurement gaps and ACK NACK repetitions.
864 * - Compute qOffset for 40ms or 80ms queue as =
865 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe + TFU_DELTA +
866 * RG_SCH_CMN_HARQ_INTERVAL)
867 * % RG_MEAS_GAPPRD_40 or RG_MEAS_GAPPRD_80.
868 * - Add all the UEs at computed offset to ulInactvUeLst since the UL
869 * transmissions shall collide with measurement gap.
870 * - Mark each UE. Set ulInactvMask |= RG_MEASGAP_INACTIVE
871 * - Start measGapUlInactvTmr timer for each UE
872 * - length = RG_MEAS_GAP_LEN
873 * - event = RG_MEASGAP_ULINACTV
874 * - handler = rgSCHMeasGapANRepUlInactvTmrExpry
875 * - Compute qOffset for ACK NACK repetition queue as =
876 * ((cell->crntTime->sfn * 10)+cell->crntTime->subframe + TFU_DELTA +
877 * RG_SCH_CMN_HARQ_INTERVAL)
879 * - Add all the UEs at computed offset to ulInactvUeLst since the
880 * feedback transmission from UE for DL transmissions shall
881 * collide with repeating ACK ACK-NACKs.
882 * - Mark each UE. Set ulInactvMask |= RG_ACKNAKREP_INACTIVE
883 * - Start ackNakRepUlInactv timer for each UE
885 * - event = RG_ACKNAKREP_ULINACTV
886 * - handler = rgSCHMeasGapANRepUlInactvTmrExpry
887 * - Verify the above computations before coding
890 * @param[in] RgSchCellCb *cell
891 * @param[out] CmLListCp *ulInactvUeLst
896 S16 rgSCHMeasGapANRepGetUlInactvUe(RgSchCellCb *cell,CmLListCp *ulInactvUeLst)
904 CmLteTimingInfo ackNakTime;
907 uint8_t pdcchToPuschGap;
912 RgSchDlHqProcCb *hqP;
916 /*ccpu00139481- Meas Gap should be monitored in UL with TFU_ULCNTRL_DLDELTA*/
917 schedTime = cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot + \
920 pdcchToPuschGap = RGSCH_PDCCH_PUSCH_DELTA;
922 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, TFU_ULCNTRL_DLDELTA);
923 pdcchToPuschGap = rgSchTddPuschTxKTbl[cell->ulDlCfgIdx][ackNakTime.subframe];
924 for(idx=0; pdcchToPuschGap && (idx< (pdcchToPuschGap+RG_SCH_MEAS_GAP_LEN)) ; idx++)
927 /* Calc offset for Measurement gap 40 */
928 offset = (schedTime + pdcchToPuschGap -idx + RG_MEAS_GAPPRD_40) % RG_MEAS_GAPPRD_40;
929 queue = &(cell->measGapCb.gapPrd40Q[offset]);
933 ue = (RgSchUeCb*)node->node;
934 if(!(ue->ul.ulInactvMask & RG_MEASGAP_INACTIVE))
936 ue->ul.ulInactvMask |= RG_MEASGAP_INACTIVE;
937 /* Add to the inactv list */
938 ue->ul.ulInactvLnk.node = (PTR)ue;
939 cmLListAdd2Tail (ulInactvUeLst, &(ue->ul.ulInactvLnk));
940 /* Start timer Note the timer is started for a value GAP_LEN +
941 * RG_SCH_CMN_HARQ_INTERVAL. The "4"
942 * is added because for UE to transmit, the PDCCH must be sent 4 subframes
943 * ahead - UE cant read PDCCH format0 if it is in measurement gap. */
944 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_UL_MEASGAP,
945 (RG_SCH_MEAS_GAP_LEN + pdcchToPuschGap - idx));
946 //DU_LOG("\nINFO --> SCH : Starting Meas Gap 40 @ DL TTI- (%d:%d) K-%d offset-%d Len %d \n", ackNakTime.sfn,\
947 ackNakTime.subframe, harqFdbkOffset, offset, RG_SCH_MEAS_GAP_LEN + harqFdbkOffset-idx);
952 /* Calc offset for Measurement gap 80 */
953 offset = (schedTime + pdcchToPuschGap - idx + RG_MEAS_GAPPRD_80) % RG_MEAS_GAPPRD_80;
954 queue = &(cell->measGapCb.gapPrd80Q[offset]);
959 ue = (RgSchUeCb*)node->node;
960 if(!(ue->ul.ulInactvMask & RG_MEASGAP_INACTIVE))
962 ue->ul.ulInactvMask |= RG_MEASGAP_INACTIVE;
963 /* Add to the inactv list */
964 ue->ul.ulInactvLnk.node = (PTR)ue;
965 cmLListAdd2Tail (ulInactvUeLst, &(ue->ul.ulInactvLnk));
967 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_UL_MEASGAP,
968 (RG_SCH_MEAS_GAP_LEN + pdcchToPuschGap - idx));
969 //DU_LOG("\nINFO --> SCH : Starting Meas Gap 80 @ DL TTI- (%d:%d) K-%d offset-%d Len %d \n", ackNakTime.sfn,\
970 ackNakTime.subframe, harqFdbkOffset, offset, RG_SCH_MEAS_GAP_LEN + harqFdbkOffset-idx);
975 /* Calc offset for ACK NACK repetition */
976 /*offset = (cell->crntTime.sfn * 10 +
977 cell->crntTime.slot + RG_UL_SCHED_DELTA +
978 RG_SCH_CMN_HARQ_INTERVAL ) % RG_MAX_NUM_DLSF;*/
980 /* Must get the DLSF that is scheduled at TFU_DELTA Away */
982 if(cell->ulDlCfgIdx == 5)
986 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, TFU_DELTA);
987 if(rgSchTddUlDlSubfrmTbl[cell->ulDlCfgIdx][ackNakTime.subframe] !=
988 RG_SCH_TDD_DL_SUBFRAME)
993 /* Introduced timing delta for DL control in FDD */
994 RG_SCH_ADD_TO_CRNT_TIME(cell->crntTime, ackNakTime, TFU_DLCNTRL_DLDELTA);
996 dlSf = rgSCHUtlSubFrmGet (cell, ackNakTime);
997 queue = &(dlSf->ueLst);
1002 ue = (RgSchUeCb *)(node->node);
1004 hqNode = ue->dl.dlSfHqInfo[cell->cellId][dlSf->dlIdx].hqPLst.first;
1007 hqP = (RgSchDlHqProcCb *)hqNode->node;
1008 hqNode = hqNode->next;
1009 for (i = 0;(i<2) && (hqP->tbInfo[i].state == HQ_TB_WAITING);i++)
1011 tbCb = &hqP->tbInfo[i];
1012 if (tbCb->fbkRepCntr > 0)
1014 ue->ul.ulInactvMask |= RG_ACKNAKREP_INACTIVE;
1015 /* Check if already added to the list */
1016 if (!(ue->ul.ulInactvMask & RG_MEASGAP_INACTIVE))
1018 /* Add to the inactv list */
1019 ue->ul.ulInactvLnk.node = (PTR)ue;
1020 cmLListAdd2Tail (ulInactvUeLst, &(ue->ul.ulInactvLnk));
1024 repCntr = rgSCHAckNakRepFindUlDuration(cell, dlSf, ackNakTime,
1025 ue->ackNakRepCb.repCntr);
1026 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_UL_ACKNACK, repCntr);
1028 rgSCHTmrStartTmr (cell, ue, RG_SCH_TMR_UL_ACKNACK,
1029 (ue->ackNakRepCb.repCntr));
1039 * @brief Handles processing of DL Inactive timer expiry at the end of
1040 * measurement gap or ack nack repetition for a UE
1044 * Function : rgSCHMeasGapANRepDlInactvTmrExpry
1046 * Invoking Module Processing:
1047 * - This API shall be invoked to process DL inactive timer expiry
1050 * - If timer event is RG_MEASGAP_DLINACTV,
1051 * - dlInactvMask &= ~RG_MEASGAP_INACTIVE
1052 * - If timer event is RG_ACKNAKREP_DLINACTV,
1053 * - dlInactvMask &= ~RG_ACKNAKREP_INACTIVE
1054 * - if (!dlInactvMask)
1055 * - Invoke DL scheduler to put the UE back into the scheduling queues.
1056 * - Re-initialize timer.
1059 * @param[in] RgSchUeCb *ue
1060 * @param[in] Check if some timer related parameter needs to be passed
1065 Void rgSCHMeasGapANRepDlInactvTmrExpry(RgSchUeCb *ue,uint8_t tmrEvnt)
1068 RgSchCellCb *cell = ue->cell;
1072 case RG_SCH_TMR_DL_MEASGAP:
1073 RG_SCH_CMN_DL_UPDT_INACTV_MASK ( cell, ue, RG_MEASGAP_INACTIVE);
1075 case RG_SCH_TMR_DL_ACKNACK:
1076 RG_SCH_CMN_DL_UPDT_INACTV_MASK ( cell, ue, RG_ACKNAKREP_INACTIVE);
1079 if (!ue->dl.dlInactvMask)
1081 cmInitTimers (&ue->measGapCb.measGapDlInactvTmr, 1);
1082 cmInitTimers (&ue->ackNakRepCb.ackNakRepDlInactvTmr, 1);
1088 * @brief Handles processing of UL Inactive timer expiry at the end of
1089 * measurement gap or ack nack repetition for a UE
1093 * Function : rgSCHMeasGapANRepUlInactvTmrExpry
1095 * Invoking Module Processing:
1096 * - This API shall be invoked to process UL inactive timer expiry
1099 * - If timer event is RG_MEASGAP_ULINACTV,
1100 * - ulInactvMask &= ~RG_MEASGAP_INACTIVE
1101 * - If timer event is RG_ACKNAKREP_ULINACTV,
1102 * - ulInactvMask &= ~RG_ACKNAKREP_INACTIVE
1103 * - if (!ulInactvMask)
1104 * - Invoke UL scheduler to put the UE back into the scheduling queues.
1105 * - Re-initialize timer.
1108 * @param[in] RgSchUeCb *ue
1109 * @param[in] Check if some timer related parameter needs to be passed
1114 Void rgSCHMeasGapANRepUlInactvTmrExpry(RgSchUeCb *ue,uint8_t tmrEvnt)
1116 RgSchCellCb *cell = ue->cell;
1120 case RG_SCH_TMR_UL_MEASGAP:
1121 RG_SCH_CMN_UL_UPDT_INACTV_MASK ( cell, ue, RG_MEASGAP_INACTIVE);
1123 case RG_SCH_TMR_UL_ACKNACK:
1124 RG_SCH_CMN_UL_UPDT_INACTV_MASK ( cell, ue, RG_ACKNAKREP_INACTIVE);
1127 if (!ue->ul.ulInactvMask)
1129 cmInitTimers (&ue->measGapCb.measGapUlInactvTmr, 1);
1130 cmInitTimers (&ue->ackNakRepCb.ackNakRepUlInactvTmr, 1);
1136 * @brief Handles processing of measurement gap timer expiry at the end of
1141 * Function : rgSCHMeasGapANRepTmrExpry
1143 * Invoking Module Processing:
1144 * - This API shall be invoked to process measurement gap timer expiry
1147 * - Set ue->isMeasuring = FALSE
1148 * - Re-initialize timer.
1151 * @param[in] RgSchUeCb *ue
1152 * @param[in] Check if some timer related parameter needs to be passed
1157 Void rgSCHMeasGapANRepTmrExpry(RgSchUeCb *ue)
1160 ue->measGapCb.isMeasuring = FALSE;
1161 cmInitTimers (&ue->measGapCb.measGapTmr, 1);
1167 * @brief Handles processing of ACK-NACK repetition timer expiry at the end of
1168 * ACK-NACK repetition.
1172 * Function : rgSchAckNakRepTmrExpry
1174 * Invoking Module Processing:
1175 * - This API shall be invoked to process ACK-NACK repetition timer expiry
1178 * - Set ue->isAckNakRep = FALSE
1179 * - Re-initialize timer.
1182 * @param[in] RgSchUeCb *ue
1183 * @param[in] Check if some timer related parameter needs to be passed
1188 Void rgSCHAckNakRepTmrExpry(RgSchUeCb *ue)
1191 ue->ackNakRepCb.isAckNakRep = FALSE;
1192 cmInitTimers (&ue->ackNakRepCb.ackNakRepTmr, 1);
1199 * @brief Adds ACK-NACK repeating UEs to the ackNakRepQ
1203 * Function : rgSchAckNakRepAddToQ
1205 * Invoking Module Processing:
1206 * - This API shall be invoked for adding list of UEs to the ACK-NACK
1207 * repeating queue at appropriate poistion. Invoking module shall invoke
1208 * with the list of ACK-NACK repeating UEs for a sub-frame and timing info
1209 * at which ACK NACK repetition shall start for the UEs.
1212 * - Determine the qOffset depending on the timing info as
1213 * - qOffset = (repStartTime->sfn *10 + repStartTime->subframe) % RG_MAX_NUM_DLSF
1214 * - Initialize the list at the qOffset.
1215 * - For each UE in the list,
1216 * - Add the UE to ackNakRepQ to the list at the determined qOffset.
1217 * - Set ue->qOffset = qOffset
1218 * - Initialize timers.
1221 * @param[in] RgSchCellCb *cell
1222 * @param[in] RgSchDlSf *crntDlSf
1223 * @param[in] CmLteTimingInfo repStartTime
1229 Void rgSCHAckNakRepAddToQ(RgSchCellCb *cell,RgSchDlSf *crntDlSf)
1234 RgSchDlHqProcCb *hqP;
1235 RgSchDlHqTbCb *tbCb;
1238 node = crntDlSf->ueLst.first;
1241 ue = (RgSchUeCb *)(node->node);
1243 hqNode = ue->dl.dlSfHqInfo[cell->cellId][crntDlSf->dlIdx].hqPLst.first;
1246 hqP = (RgSchDlHqProcCb *)hqNode->node;
1247 hqNode = hqNode->next;
1248 for (i = 0;(i<2) && (hqP->tbInfo[i].state == HQ_TB_WAITING);i++)
1250 tbCb = &hqP->tbInfo[i];
1251 /* Add UEs that have enabled ACK NACK repetition */
1252 if (ue->ackNakRepCb.isAckNackEnabled)
1254 tbCb->fbkRepCntr = ue->ackNakRepCb.cfgRepCnt;
1255 tbCb->fbkRecpRepCntr = ue->ackNakRepCb.cfgRepCnt;
1256 /* Removed init of timers as the init will be happening during
1257 * config or timer expiry*/
1268 * @brief Finds the number of subframes used for ACK-NACK cycle
1272 * Function : rgSCHAckNakRepFindUlDuration
1274 * This function finds the number of subframes required
1275 * for ACK-NACK repetition cycle based on UL subframes.
1277 * @param[in] RgSchCellCb *cell
1278 * @param[in] RgSchDlSf *dlSf
1279 * @param[in] CmLteTimingInfo repTime
1280 * @param[in] uint8_t repCnt
1286 static uint8_t rgSCHAckNakRepFindUlDuration(RgSchCellCb *cell,RgSchDlSf *dlSf,CmLteTimingInfo repTime,uint8_t repCnt)
1288 CmLteTimingInfo ulfrm;
1289 uint8_t noSubfrms = 0;
1290 uint16_t ulDlCfgIdx = cell->ulDlCfgIdx;
1295 rgSCHAckNakRepGetUlOffsetFrmDl(dlSf, repTime, &noSubfrms);
1296 RG_SCH_ADD_TO_CRNT_TIME(repTime, ulfrm, noSubfrms);
1298 idx = ulfrm.subframe;
1301 idx = (idx + 1) % RGSCH_NUM_SUB_FRAMES;
1302 if(rgSchTddUlDlSubfrmTbl[ulDlCfgIdx][idx] ==
1303 RG_SCH_TDD_UL_SUBFRAME)
1315 * @brief Finds the number of subframes used for ACK-NACK cycle
1319 * Function : rgSCHAckNakRepGetUlOffsetFrmDl
1321 * This function finds the number of subframes after
1322 * which UL subframes are present for the gicen DL
1325 * @param[in] RgSchDlSf *dlSf
1326 * @param[in] CmLteTimingInfo crntDlTime
1327 * @param[in] uint8_t *noSubfrms
1333 static Void rgSCHAckNakRepGetUlOffsetFrmDl(RgSchDlSf *dlSf,CmLteTimingInfo crntDlTime,uint8_t *noSubfrms )
1336 if(dlSf->dlFdbkInfo.sfnOffset != 0)
1338 *noSubfrms = (dlSf->dlFdbkInfo.sfnOffset - 1) * RGSCH_NUM_SUB_FRAMES;
1339 *noSubfrms = *noSubfrms + RGSCH_NUM_SUB_FRAMES - crntDlTime.subframe;
1340 *noSubfrms = *noSubfrms + dlSf->dlFdbkInfo.subframe;
1344 *noSubfrms = dlSf->dlFdbkInfo.subframe - crntDlTime.subframe;
1350 /**********************************************************************
1353 **********************************************************************/