--- /dev/null
+/*******************************************************************************
+################################################################################
+# Copyright (c) [2017-2019] [Radisys] #
+# #
+# Licensed under the Apache License, Version 2.0 (the "License"); #
+# you may not use this file except in compliance with the License. #
+# You may obtain a copy of the License at #
+# #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+# #
+# Unless required by applicable law or agreed to in writing, software #
+# distributed under the License is distributed on an "AS IS" BASIS, #
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+################################################################################
+*******************************************************************************/
+
+/************************************************************************
+
+ Name: LTE-MAC layer
+
+ Type: C source file
+
+ Desc: C source code for Entry point fucntions
+
+ File: rg_sch_dhm.c
+
+**********************************************************************/
+
+/** @file rg_sch_dhm.c
+@brief APIs related to Downlink HARQ for the scheduler.
+*/
+
+static const char* RLOG_MODULE_NAME="MAC";
+static int RLOG_FILE_ID=242;
+static int RLOG_MODULE_ID=4096;
+
+/* header include files -- defines (.h) */
+#include "envopt.h" /* environment options */
+#include "envdep.h" /* environment dependent */
+#include "envind.h" /* environment independent */
+#include "gen.h" /* general layer */
+#include "ssi.h" /* system service interface */
+#include "cm5.h" /* common timers */
+#include "cm_hash.h" /* common hash list */
+#include "cm_mblk.h" /* common memory link list library */
+#include "cm_llist.h" /* common linked list library */
+#include "cm_err.h" /* common error */
+#include "cm_lte.h" /* common LTE */
+#include "lrg.h"
+#include "rgr.h"
+#include "rgm.h"
+#include "tfu.h"
+#include "rg_env.h"
+#include "rg_sch_err.h"
+#include "rg_sch_inf.h" /* typedefs for Scheduler */
+#include "rg_sch.h"
+#include "rg_sch_cmn.h"
+#include "rl_interface.h"
+#include "rl_common.h"
+
+/* header/extern include files (.x) */
+#include "gen.x" /* general layer */
+#include "ssi.x" /* system service interface */
+#include "cm5.x" /* common timers */
+#include "cm_lib.x" /* common library */
+#include "cm_hash.x" /* common hash list */
+#include "cm_llist.x" /* common linked list library */
+#include "cm_mblk.x" /* memory management */
+#include "cm_tkns.x" /* common tokens */
+#include "cm_lte.x" /* common LTE */
+#include "lrg.x"
+#include "rgr.x"
+#include "rgm.x"
+#include "tfu.x"
+#include "rg_sch_inf.x" /* typedefs for Scheduler */
+#include "rg_sch.x"
+#include "rg_sch_cmn.x"
+
+#ifdef RGSCH_SPS_STATS
+extern U32 rgNumSPSSchedDropMaxRetx;
+extern U32 rgNumActDtx;
+#endif
+PUBLIC U32 nackSf[10];
+
+
+
+#ifdef MAC_SCH_STATS
+PUBLIC RgSchNackAckStats hqFailStats;
+PUBLIC RgSchHqRetxStats hqRetxStats;
+#endif /* MAC_SCH_STATS */
+//Chandan Stats Collection
+#ifdef DLHQ_STATS
+U32 statsCnt;
+RgSchDlHqStats dlHqStats[10000] = {{0,0,0}};
+#endif
+
+#ifdef TFU_TDD
+/* For special bundling case: convert numOfAcks to ACK/NACK
+ * The below table derives the HARQ aknowledgement as ACK or NACK using the
+ * number of transmission done and the feedback value received
+ * The below table is based on Table 7.3-X from 36.213 and
+ * table 79 from FAPIv1.1 doc
+ */
+U8 rgSchNumOfAcksToAckNack[RG_SCH_MAX_NUM_EXPECTED_ACKS][RG_SCH_NUM_FDBK_VALUE] = {
+{TFU_HQFDB_ACK, TFU_HQFDB_NACK, TFU_HQFDB_NACK},
+{TFU_HQFDB_NACK, TFU_HQFDB_ACK, TFU_HQFDB_NACK},
+{TFU_HQFDB_NACK, TFU_HQFDB_NACK, TFU_HQFDB_ACK},
+{TFU_HQFDB_ACK, TFU_HQFDB_NACK, TFU_HQFDB_NACK},
+{TFU_HQFDB_NACK, TFU_HQFDB_ACK, TFU_HQFDB_NACK},
+{TFU_HQFDB_NACK, TFU_HQFDB_NACK, TFU_HQFDB_ACK},
+{TFU_HQFDB_ACK, TFU_HQFDB_NACK, TFU_HQFDB_NACK},
+{TFU_HQFDB_NACK, TFU_HQFDB_ACK, TFU_HQFDB_NACK},
+{TFU_HQFDB_NACK, TFU_HQFDB_NACK, TFU_HQFDB_ACK}
+};
+#endif
+
+/* local typedefs */
+
+/* local externs */
+
+PRIVATE Void rgSCHDhmFdbkIndHndlTa ARGS((RgSchDlHqProcCb *hqP, U8 tbIdx, U8 fdbk,
+ Bool maxHqRetxReached));
+PUBLIC void rgEmtcsetNullSubFrm ARGS((RgSchDlHqProcCb *hqP));
+#ifndef LTE_TDD
+PRIVATE S16 rgSCHDhmProcHqFdbkAckNackRep ARGS((
+RgSchDlHqProcCb *hqP,
+RgSchDlSf *sf,
+U8 tbCnt,
+U8 *isAck
+));
+#endif
+#ifdef DL_LA
+PRIVATE S16 rgSCHDhmUpdateAckNackHistory ARGS((
+ RgSchCellCb *cell,
+ RgSchUeCb *ueCb,
+ U8 hqfdbk,
+ U8 tbCnt
+ ));
+#endif
+#ifdef LTE_TDD
+PRIVATE Void rgSCHDhmPrcSplBundlFdbk ARGS((
+ RgSchCellCb *cell,
+ TfuHqInfo *fdbk,
+ U8 hqCnt
+ ));
+#ifdef LTE_ADV
+PRIVATE Void rgSchGetHqFdbkPosForM1 ARGS((
+ RgSchUeCb *ue,
+ RgSchDlHqProcCb *hqP,
+ U8 *isAck,
+ RgTfuHqInfo *fdbk,
+ U8 tbIdx,
+ RgSchTddANInfo *anInfo
+ ));
+PRIVATE Void rgSchGetHqFdbkPosForM234 ARGS((
+ RgSchUeCb *ue,
+ RgSchDlHqProcCb *hqP,
+ U8 *isAck,
+ RgTfuHqInfo *fdbk,
+ U8 tbIdx,
+ RgSchTddANInfo *anInfo,
+ U8 M,
+ CmLteTimingInfo timeInfo
+ ));
+#endif/*LTE_ADV*/
+#endif/*LTE_TDD*/
+
+/* Freeing up the HARQ proc blocked for
+ * indefinite time in case of Retx */
+PUBLIC S16 rgSCHDhmDlRetxAllocFail ARGS((
+RgSchUeCb *ue,
+RgSchDlHqProcCb *proc
+));
+
+#ifdef EMTC_ENABLE
+EXTERN S16 rgSCHDhmEmtcRgrCellCfg ARGS((
+RgSchCellCb *cell
+));
+#endif
+
+#ifdef CA_DBG
+extern U32 gPCellTb1AckCount,gPCellTb2AckCount,gPCellTb1NackCount,gPCellTb2NackCount;
+extern U32 gSCellSchedCount,gPrimarySchedCount;
+extern U32 gSCellTb1AckCount,gSCellTb2AckCount,gSCellTb1NackCount,gSCellTb2NackCount;
+extern U32 gPCellTb1DtxCount, gPCellTb2DtxCount, gSCellTb1DtxCount, gSCellTb2DtxCount;
+extern U32 gHqFdbkCount;
+
+#endif
+#ifdef EMTC_ENABLE
+EXTERN Void rgSCHEmtcUtlDlHqPTbRmvFrmTx
+(
+RgSchEmtcDlSf *subFrm,
+RgSchDlHqProcCb *hqP,
+U8 tbIdx,
+Bool isRepeting
+);
+EXTERN RgSchEmtcDlSf* rgSCHEmtcUtlSubFrmGet
+(
+RgSchCellCb *cell,
+CmLteTimingInfo frm
+);
+EXTERN Void rgSCHEmtcHqInfoAlloc ARGS((RgSchCellCb *cell, RgSchDlHqProcCb *hqP));
+#endif
+/* forward references */
+
+/**
+ * @brief This function initializes the DL HARQ Entity of UE.
+ *
+ * @details
+ *
+ * Function: rgSCHDhmHqEntInit
+ * Purpose: This function initializes the DL HARQ entity of
+ * UE control block. This is performed at the time
+ * of creating UE control block.
+ *
+ * Invoked by: configuration module
+ *
+ * @param[in] RgSchCellCb* cell
+ * @return RgSchDlHqEnt *
+ *
+ **/
+/*MS_WORKAROUND for ccpu00122893*/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmHqEntReset
+(
+ RgSchDlHqEnt *hqE
+)
+#else
+PUBLIC Void rgSCHDhmHqEntReset(hqE)
+ RgSchDlHqEnt *hqE;
+#endif
+{
+ RgSchDlHqProcCb *hqP;
+ U8 i;
+ TRC2(rgSCHDhmHqEntReset)
+ cmLListInit(&hqE->inUse);
+ cmLListInit(&hqE->free);
+ for (i=0; i < hqE->numHqPrcs; i++)
+ {
+ hqP = &hqE->procs[i];
+ hqP->hqE = hqE;
+ hqP->procId = i;
+ /* Fix - reset numLch */
+ hqP->tbInfo[0].numLch = 0;
+ hqP->tbInfo[1].numLch = 0;
+ hqP->tbInfo[0].txCntr = 0;
+ hqP->tbInfo[0].ndi = 0; /* Initialize the NDI to Zero */
+ hqP->tbInfo[1].txCntr = 0;
+ hqP->tbInfo[1].ndi = 0; /* Initialize the NDI to Zero */
+ hqP->tbInfo[0].tbIdx = 0;
+ hqP->tbInfo[1].tbIdx = 1;
+ hqP->tbInfo[0].hqP = hqP;
+ hqP->tbInfo[1].hqP = hqP;
+ hqP->tbInfo[0].state = HQ_TB_ACKED;
+ hqP->tbInfo[1].state = HQ_TB_ACKED;
+ hqP->tbInfo[0].contResCe = NOTPRSNT;
+ hqP->tbInfo[1].contResCe = NOTPRSNT;
+ hqP->lnk.node = (PTR)hqP;
+ //cmLListAdd2Tail(&hqE->free, &hqP->lnk);
+ hqP->hqPLst = NULLP;
+ rgSCHDhmHqPAdd2FreeLst(hqP);
+ hqP->tbInfo[0].lchSchdData = hqP->tbInfo[0].lchSchdDataArr;
+ hqP->tbInfo[1].lchSchdData = hqP->tbInfo[1].lchSchdDataArr;
+ hqP->drxCb.rttIndx = DRX_INVALID;
+ hqP->drxCb.reTxIndx = DRX_INVALID;
+ hqP->tbInfo[0].cntrRetxAllocFail = 0;
+ hqP->tbInfo[1].cntrRetxAllocFail = 0;
+ hqP->hasDcch = FALSE;
+ hqP->cwSwpEnabled = FALSE;
+ hqP->pdcch = NULLP;
+ hqP->subFrm = NULLP;
+
+#ifdef LTE_ADV
+ rgSCHLaaResetDlHqProcCb(hqP);
+#endif
+ }
+ RETVOID;
+} /* rgSCHDhmHqEntReset */
+
+/**
+ * @brief This function assigns dlHqEnt of raCb to ueCb.
+ *
+ * @details
+ *
+ * Function: rgSCHDhmAssgnUeHqEntFrmRaCb
+ * Purpose: This function assigns dlHqEnt of raCb to ueCb.
+ *
+ * Invoked by: configuration module
+ *
+ * @param[in] RgSchUeCb *ue
+ * @param[in] RgSchRaCb *raCb
+ * @return Void
+ *
+ **/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmAssgnUeHqEntFrmRaCb
+(
+RgSchUeCb *ue,
+RgSchRaCb *raCb
+)
+#else
+PUBLIC Void rgSCHDhmAssgnUeHqEntFrmRaCb(ue, raCb)
+RgSchUeCb *ue;
+RgSchRaCb *raCb;
+#endif
+{
+ TRC2(rgSCHDhmAssgnUeHqEntFrmRaCb)
+
+ ue->cellInfo[0]->hqEnt = raCb->dlHqE;
+ ue->cellInfo[0]->hqEnt->ue = ue;
+ /* Update the DL Harq related information */
+ ue->cellInfo[0]->hqEnt->maxHqTx = ue->cell->dlHqCfg.maxDlHqTx;
+ raCb->dlHqE = NULLP;
+ /* Fix : set UE active in DL as UE initialization completed */
+ ue->dl.dlInactvMask &= ~(RG_HQENT_INACTIVE);
+ ue->ul.ulInactvMask &= ~(RG_HQENT_INACTIVE);
+ rgSCHCmnDlInitHqEnt(ue->cell, ue->cellInfo[0]->hqEnt);
+
+ RETVOID;
+}
+
+/**
+ * @brief This function deletes the dlHqEnt.
+ *
+ * @details
+ *
+ * Function: rgSCHDhmDelHqEnt
+ * Purpose: This function deletes the dlHqEnt.
+ *
+ * Invoked by: configuration module
+ *
+ * @param[in] RgSchCellCb *cell
+ * @param[in] RgSchDlHqEnt **hqE
+ * @return Void
+ *
+ **/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmDelHqEnt
+(
+RgSchCellCb *cell,
+RgSchDlHqEnt **hqE
+)
+#else
+PUBLIC Void rgSCHDhmDelHqEnt(cell, hqE)
+RgSchCellCb *cell;
+RgSchDlHqEnt **hqE;
+#endif
+{
+ TRC2(rgSCHDhmDelHqEnt)
+
+ if (!(*hqE))
+ {
+ RETVOID;
+ }
+
+ rgSCHCmnDlDeInitHqEnt(cell, *hqE);
+
+ rgSCHUtlFreeSBuf(cell->instIdx, (Data **)hqE,
+ sizeof(RgSchDlHqEnt));
+
+ RETVOID;
+}
+
+#ifdef ANSI
+PUBLIC RgSchDlHqEnt *rgSCHDhmHqEntInit
+(
+RgSchCellCb *cell
+)
+#else
+PUBLIC RgSchDlHqEnt *rgSCHDhmHqEntInit(cell)
+RgSchCellCb *cell;
+#endif
+{
+ RgSchDlHqEnt *hqE;
+ Inst inst = cell->instIdx;
+
+ TRC2(rgSCHDhmHqEntInit)
+
+ /* Init the HARQ data structure */
+ if (rgSCHUtlAllocSBuf(inst, (Data **)&hqE, sizeof(RgSchDlHqEnt)) != ROK)
+ {
+ RLOG_ARG0(L_DEBUG,DBG_CELLID,cell->cellId,
+ "rgSCHDhmHqEntInit hqE alloc fail");
+ RETVALUE(NULLP);
+ }
+#ifdef LTE_TDD
+ /* Init the HARQ processes */
+ hqE->numHqPrcs = rgSchTddDlNumHarqProcTbl[cell->ulDlCfgIdx];
+ if (rgSCHUtlAllocSBuf(inst, (Data **)&hqE->procs,
+ hqE->numHqPrcs * sizeof(RgSchDlHqProcCb)) != ROK)
+ {
+ RLOG_ARG0(L_DEBUG,DBG_CELLID,cell->cellId,
+ "rgSCHDhmHqEntInit hqP alloc fail in hqE");
+ RETVALUE(NULLP);
+ }
+#else
+ hqE->numHqPrcs = RGSCH_NUM_DL_HQ_PROC;
+#endif
+
+#ifdef LTE_ADV
+ rgSCHLaaInitDlHqProcCb (cell, hqE);
+#endif
+
+ /* Initialize maximum tranmission counter */
+ hqE->maxHqTx = cell->dlHqCfg.maxDlHqTx;
+
+
+ /* MW_WORKAROUND for ccpu00122893 */
+ rgSCHDhmHqEntReset(hqE);
+ /* CA Dev Start*/
+ hqE->cell = cell;
+ /* CA Dev End*/
+
+ RETVALUE(hqE);
+} /* rgSCHDhmHqEntInit */
+
+/**
+ * @brief This function gets an available HARQ process.
+ *
+ * @details
+ *
+ * Function: rgSCHDhmGetAvlHqProc
+ * Purpose: This function returns an available HARQ process in
+ * the DL direction. All HARQ processes are maintained
+ * in queues of free and inuse.
+ *
+ * 1. Check if the free queue is empty. If yes, return
+ * RFAILED
+ * 2. If not empty, update the proc variable with the
+ * first process in the queue. Return ROK.
+ *
+ * Invoked by: scheduler
+ *
+ * @param[in] RgSchUeCb *ue
+ * @param[in] CmLteTimingInfo timingInfo
+ * @param[out] RgSchDlHqProc **hqP
+ * @return S16
+ * -#ROK if successful
+ * -#RFAILED otherwise
+ *
+ **/
+#ifdef ANSI
+PUBLIC S16 rgSCHDhmGetAvlHqProc
+(
+RgSchCellCb *cell,
+RgSchUeCb *ue,
+CmLteTimingInfo timingInfo,
+RgSchDlHqProcCb **hqP
+)
+#else
+PUBLIC S16 rgSCHDhmGetAvlHqProc (cell, ue, timingInfo, hqP)
+RgSchCellCb *cell;
+RgSchUeCb *ue;
+CmLteTimingInfo timingInfo;
+RgSchDlHqProcCb **hqP;
+#endif
+{
+ RgSchDlHqEnt *hqE = NULLP;
+ RgSchDlHqProcCb *tmpHqProc;
+ CmLList *tmp;
+ TRC2(rgSCHDhmGetAvlHqProc);
+
+ hqE = RG_SCH_CMN_GET_UE_HQE(ue, cell);
+
+ if (hqE == NULLP)
+ {
+ RLOG_ARG1(L_ERROR,DBG_CELLID,cell->cellId, "rgSCHDhmGetAvlHqProc hqE NULL ue %d"
+ , ue->ueId);
+ RETVALUE(RFAILED);
+ }
+
+
+ CM_LLIST_FIRST_NODE(&(hqE->free), tmp);
+
+ if (NULLP == tmp)
+ {
+ RLOG_ARG3(L_ERROR,DBG_CELLID,cell->cellId,
+ "rgSCHDhmGetAvlHqProc free %ld inUse %ld ue %d"
+ , hqE->free.count, hqE->inUse.count, ue->ueId);
+ /* No Harq Process available in the free queue. */
+ RETVALUE(RFAILED);
+ }
+
+ tmpHqProc = (RgSchDlHqProcCb *)(tmp->node);
+
+#ifdef LTEMAC_SPS
+ /* If SPS HARQ procs are in use, do not use SPS harq procs for non-SPS
+ * transmissions */
+ if (ue->dl.isSpsHqPInUse)
+ {
+ while (tmpHqProc->procId < ue->dl.dlSpsCfg.numSpsHqProc)
+ {
+ CM_LLIST_NEXT_NODE(&(hqE->free), tmp);
+ if (!tmp)
+ {
+ break;
+ }
+ tmpHqProc = (RgSchDlHqProcCb *)(tmp->node);
+ }
+ if (!tmp)
+ {
+ /* No Harq Process available in the free queue. */
+ RETVALUE(RFAILED);
+ }
+ }
+#endif
+
+
+ tmpHqProc->tbInfo[0].timingInfo = timingInfo;
+ tmpHqProc->tbInfo[1].timingInfo = timingInfo;
+ tmpHqProc->hasDcch = FALSE;
+ tmpHqProc->cwSwpEnabled = FALSE;
+
+ /* Remove the element from the free Queue */
+ //cmLListDelFrm(&hqE->free, tmp);
+ rgSCHDhmHqPDelFrmFreeLst(tmpHqProc);
+
+ /* Add the element into the inUse Queue as well */
+ //cmLListAdd2Tail(&hqE->inUse, &tmpHqProc->lnk);
+ rgSCHDhmHqPAdd2InUseLst(tmpHqProc);
+
+ *hqP = tmpHqProc;
+
+#ifdef LTE_ADV
+ rgSCHLaaResetDlHqProcCb(tmpHqProc);
+#endif
+
+ /* LAA DBG Only */
+ tmpHqProc->tbSizeAtEstimate[0] = 0;
+ tmpHqProc->tbSizeAtEstimate[1] = 0;
+ tmpHqProc->tbSizeAtFnlz[0] = 0;
+ tmpHqProc->tbSizeAtFnlz[1] = 0;
+ tmpHqProc->tbSizeOfMvdTb[0] = 0;
+ tmpHqProc->tbSizeOfMvdTb[1] = 0;
+ tmpHqProc->itbsAtEstimate[0] = 0;
+ tmpHqProc->itbsAtEstimate[1] = 0;
+ tmpHqProc->prbAtEstimate = 0;
+
+ RETVALUE(ROK);
+} /* rgSCHDhmGetAvlHqProc */
+
+
+/**
+ * @brief This function adds HARQ process for a given TB in to
+ * the inuse queue upon retx.
+ *
+ * @details
+ *
+ * Function: rgSCHDhmHqTbRetx
+ * Purpose: This function handles when a HARQ process is scheduled
+ * for retransmission. It adds the HARQ procss to inuse
+ * queue.
+ * 1. Check if this HqP is already added to the inUse
+ * queue as part of this function call for other
+ * TB's retransmission.
+ * 2. If already present in inUse Q then do not add.
+ *
+ * Invoked by: scheduler
+ *
+ * @param[in] RgSchDlHqEnt *hqE
+ * @param[in] CmLteTimingInfo timingInfo
+ * @param[out] RgDlHqProc *hqP
+ * @param[in] U8 tbIdx
+ * @return Void
+ *
+ **/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmHqTbRetx
+(
+RgSchDlHqEnt *hqE,
+CmLteTimingInfo timingInfo,
+RgSchDlHqProcCb *hqP,
+U8 tbIdx
+)
+#else
+PUBLIC Void rgSCHDhmHqTbRetx(hqE, timingInfo, hqP, tbIdx)
+RgSchDlHqEnt *hqE;
+CmLteTimingInfo timingInfo;
+RgSchDlHqProcCb *hqP;
+U8 tbIdx;
+#endif
+{
+ U8 othrTbIdx = tbIdx ^ 1;
+ TRC2(rgSCHDhmHqTbRetx)
+
+ hqP->tbInfo[tbIdx].timingInfo = timingInfo;
+
+ if (hqE->msg4Proc == hqP)
+ {
+ RETVOID;
+ }
+ /* fix for ccpu00118633 No Hq proc Avl end*/
+
+ /* Extra:check if Harq process is already linked to in-use
+ Queue by means of other TB handling. */
+ if (hqP->tbInfo[othrTbIdx].state != HQ_TB_WAITING)
+ {
+ /*Fix FIXME */
+ if (hqE->msg4Proc != hqP)
+ {
+ //cmLListAdd2Tail(&hqE->inUse, &hqP->lnk);
+ rgSCHDhmHqPAdd2InUseLst(hqP);
+ }
+ }
+
+ hqP->tbInfo[tbIdx].cntrRetxAllocFail = 0;
+
+ RETVOID;
+} /* rgSCHDhmHqTbRetx */
+
+/**
+ * @brief This function returns last scheduled HARQ process for
+ * a UE's HARQ entity.
+ *
+ * @details
+ *
+ * Function: rgSCHDhmLastSchedHqProc
+ * Purpose: This function returns the last (most recent)
+ * process in the inUse list, which corresponds
+ * to the last scheduled process. Returns NULLP
+ * if list is empty.
+ * The reason for introducing this is to have
+ * an ability to check if UE was scheduled
+ * in the current subframe (scheduling would
+ * have caused a proc to be added to the end
+ * of the list, and checking time (only subframe
+ * number probably works) would confirm this.
+ *
+ * Invoked by: scheduler
+ *
+ * @param[in] RgSchDlHqEnt *hqE
+ * @return RgSchDlHqProcCb *
+ *
+ **/
+#ifdef ANSI
+PUBLIC RgSchDlHqProcCb * rgSCHDhmLastSchedHqProc
+(
+RgSchDlHqEnt *hqE
+)
+#else
+PUBLIC RgSchDlHqProcCb * rgSCHDhmLastSchedHqProc(hqE)
+RgSchDlHqEnt *hqE;
+#endif
+{
+ TRC2(rgSCHDhmLastSchedHqProc);
+ /* GRPPWR_CNTRL Fix: UE context will not hold a valid hqE,
+ * until RACH procedure is completed */
+ if ((hqE == NULLP) || (hqE->inUse.last == NULLP))
+ {
+ RETVALUE(NULLP);
+ }
+ RETVALUE((RgSchDlHqProcCb *)hqE->inUse.last->node);
+} /* rgSCHDhmLastSchedHqProc */
+
+#ifdef RGR_V1
+/**
+ * @brief This function gets an available HARQ process for MSG 4.
+ *
+ * @details
+ *
+ * Function: rgSCHDhmGetCcchSduHqProc
+ * Purpose: This function returns an available HARQ process in
+ * the DL direction. All HARQ processes are maintained
+ * in queues of free and inuse.
+ *
+ * 1. Check if the free queue is empty. If yes, return
+ * RFAILED.
+ * 2. If not empty, update the proc variable with the
+ * first process in the queue. Return ROK.
+ *
+ * Invoked by: scheduler
+ *
+ * @param[in] RgSchRaCb *raCb
+ * @param[in] CmLteTimingInfo timingInfo
+ * @param[out] RgSchDlHqProcCb **hqP
+ * @return S16
+ * -#ROK if successful
+ * -#RFAILED otherwise
+ *
+ **/
+#ifdef ANSI
+PUBLIC S16 rgSCHDhmGetCcchSduHqProc
+(
+RgSchUeCb *ueCb,
+CmLteTimingInfo timingInfo,
+RgSchDlHqProcCb **hqP
+)
+#else
+PUBLIC S16 rgSCHDhmGetCcchSduHqProc (ueCb, timingInfo, hqP)
+RgSchUeCb *ueCb;
+CmLteTimingInfo timingInfo;
+RgSchDlHqProcCb **hqP;
+#endif
+{
+ RgSchDlHqProcCb *tmpHqProc;
+ CmLList *tmp;
+ RgSchDlHqEnt *hqE;
+
+ TRC2(rgSCHDhmGetCcchSduHqProc)
+
+ hqE = ueCb->cellInfo[0]->hqEnt;
+ CM_LLIST_FIRST_NODE(&(hqE->free), tmp);
+ if (NULLP == tmp)
+ {
+ /* No Harq Process available in the free queue. */
+ RETVALUE(RFAILED);
+ }
+
+ /* Remove the element from the free Queue and */
+ /* set the MSG 4 HARQ proc pointer */
+ //cmLListDelFrm(&hqE->free, tmp);
+
+ tmpHqProc = (RgSchDlHqProcCb *)(tmp->node);
+
+ rgSCHDhmHqPDelFrmFreeLst(tmpHqProc);
+
+ tmpHqProc->tbInfo[0].timingInfo = timingInfo;
+ /* Fix : syed minor code reorg */
+ *hqP = tmpHqProc;
+ /*Updating ccchSduProc to identify feedback for CCCH SDU sent without
+ * Cont Res CE*/
+ hqE->ccchSduProc = tmpHqProc;
+ //cmLListAdd2Tail(&hqE->inUse, &tmpHqProc->lnk);
+ rgSCHDhmHqPAdd2InUseLst(tmpHqProc);
+
+ RETVALUE(ROK);
+} /* rgSCHDhmGetCcchSduHqProc */
+#endif
+
+/**
+ * @brief This function gets an available HARQ process for MSG 4.
+ *
+ * @details
+ *
+ * Function: rgSCHDhmGetMsg4HqProc
+ * Purpose: This function returns an available HARQ process in
+ * the DL direction. All HARQ processes are maintained
+ * in queues of free and inuse.
+ *
+ * 1. Check if the free queue is empty. If yes, return
+ * RFAILED.
+ * 2. If not empty, update the proc variable with the
+ * first process in the queue. Return ROK.
+ *
+ * Invoked by: scheduler
+ *
+ * @param[in] RgSchRaCb *raCb
+ * @param[in] CmLteTimingInfo timingInfo
+ * @param[out] RgDlHqProc **hqP
+ * @return S16
+ * -#ROK if successful
+ * -#RFAILED otherwise
+ *
+ **/
+#ifdef ANSI
+PUBLIC S16 rgSCHDhmGetMsg4HqProc
+(
+RgSchRaCb *raCb,
+CmLteTimingInfo timingInfo
+)
+#else
+PUBLIC S16 rgSCHDhmGetMsg4HqProc (raCb, timingInfo)
+RgSchRaCb *raCb;
+CmLteTimingInfo timingInfo;
+#endif
+{
+ RgSchDlHqProcCb *tmpHqProc;
+ CmLList *tmp;
+ RgSchDlHqEnt *hqE;
+
+ TRC2(rgSCHDhmGetMsg4HqProc)
+
+ hqE = raCb->dlHqE;
+ CM_LLIST_FIRST_NODE(&(hqE->free), tmp);
+ if (NULLP == tmp)
+ {
+ /* No Harq Process available in the free queue. */
+ RETVALUE(RFAILED);
+ }
+
+ /* Remove the element from the free Queue and */
+ /* set the MSG 4 HARQ proc pointer */
+ //cmLListDelFrm(&hqE->free, tmp);
+ tmpHqProc = (RgSchDlHqProcCb *)(tmp->node);
+ rgSCHDhmHqPDelFrmFreeLst(tmpHqProc);
+ tmpHqProc->tbInfo[0].timingInfo = timingInfo;
+ hqE->msg4Proc = tmpHqProc;
+
+ RETVALUE(ROK);
+} /* rgSCHDhmGetMsg4HqProc */
+
+/**
+ * @brief This function releases a HARQ process.
+ *
+ * @details
+ *
+ * Function: rgSCHDhmRlsHqpTb
+ * Purpose: This function resets the TB specific fields
+ * Based on the other TBs state, this HqProcess
+ * is returned to the HqEnt.
+ *
+ * 1. Add the HARQ process to the free queue.
+ * Invoked by: scheduler and HARQ processing
+ *
+ * @param[in] RgDlHqProc *hqP
+ * @param[in] U8 tbIdx
+ * @param[in] Bool togNdi
+ * @return Void
+ *
+ **/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmRlsHqpTb
+(
+RgSchDlHqProcCb *hqP,
+U8 tbIdx,
+Bool togNdi
+)
+#else
+PUBLIC Void rgSCHDhmRlsHqpTb(hqP, tbIdx, togNdi)
+RgSchDlHqProcCb *hqP;
+U8 tbIdx;
+Bool togNdi;
+#endif
+{
+ RgSchDlHqEnt *hqE;
+ U8 othrTbIdx = tbIdx ^ 1;
+#ifdef LTEMAC_SPS
+ RgSchCmnDlHqProc *cmnHqDl;
+#endif
+ /* L2_COUNTERS */
+#ifdef LTE_L2_MEAS
+ RgSchDlLcCb* lcCb = NULLP;
+ U8 numLch = 0;
+#endif
+
+ TRC2(rgSCHDhmRlsHqpTb)
+
+ /* Reset all tbInfo values */
+
+ hqE = hqP->hqE;
+
+#ifdef MAC_SCH_STATS
+ if (hqP->hqE->ue != NULLP)
+ {
+ RgSchUeCb *ueCb = hqP->hqE->ue;
+ RgSchCmnUe *cmnUe = (RgSchCmnUe*)ueCb->sch;
+ RgSchCmnDlUe *dlUe = RG_SCH_CMN_GET_DL_UE(ueCb,hqE->cell);/*CA dev*/
+ U8 cqi = dlUe->mimoInfo.cwInfo[0].cqi;
+ /* to get retransmission, decreasing transmission counter */
+ U16 numDlRetx = hqP->tbInfo[0].txCntr-1;
+ U8 tbs = dlUe->mimoInfo.cwInfo[0].iTbs[0];
+ static U32 retxCnt1 = 0;
+
+ RG_SCH_CMN_DL_TBS_TO_MCS(tbs, \
+ hqRetxStats.dlCqiStat[(cqi - 1)].mcs);
+
+ switch (numDlRetx)
+ {
+ case 1:
+ hqRetxStats.dlCqiStat[(cqi - 1)].numOfHQ_1++;
+ break;
+ case 2:
+ hqRetxStats.dlCqiStat[(cqi - 1)].numOfHQ_2++;
+ break;
+ case 3:
+ hqRetxStats.dlCqiStat[(cqi - 1)].numOfHQ_3++;
+ break;
+ case 4:
+ hqRetxStats.dlCqiStat[(cqi - 1)].numOfHQ_4++;
+ break;
+ }
+ hqRetxStats.dlCqiStat[(cqi - 1)].totalTx = \
+ hqRetxStats.dlCqiStat[(cqi - 1)].numOfHQ_1 + \
+ (hqRetxStats.dlCqiStat[(cqi - 1)].numOfHQ_2 * 2) + \
+ (hqRetxStats.dlCqiStat[(cqi - 1)].numOfHQ_3 * 3) + \
+ (hqRetxStats.dlCqiStat[(cqi - 1)].numOfHQ_4 * 4);
+
+ retxCnt1 += numDlRetx;
+ }
+#endif /* MAC_SCH_STATS */
+ RGSCH_ARRAY_BOUND_CHECK(0, hqP->tbInfo, tbIdx);
+ /* Toggle ndi */
+ if(togNdi == TRUE)
+ {
+ hqP->tbInfo[tbIdx].ndi ^= 1;
+ }
+
+ /* L2_COUNTERS */
+#ifdef LTE_L2_MEAS
+ for (numLch =0; numLch < hqP->tbInfo[tbIdx].numLch; numLch++)
+ {
+ if (NULLP != (lcCb = rgSCHDbmGetDlDedLcCb( hqP->hqE->ue,
+ hqP->tbInfo[tbIdx].lchSchdDataArr[numLch].lcId)))
+ {
+ if (lcCb->lcType == CM_LTE_LCH_DTCH)
+ {
+ if (hqP->hqE->ue->qciActiveLCs[lcCb->qciCb->qci])
+ {
+ hqP->hqE->ue->qciActiveLCs[lcCb->qciCb->qci]--;
+ }
+
+ if (!(hqP->hqE->ue->qciActiveLCs[lcCb->qciCb->qci]))
+ {
+ lcCb->qciCb->dlUeCount--;
+ }
+ }
+ }
+ }
+#endif
+
+ /* Initialization */
+ hqP->tbInfo[tbIdx].tbSz = 0;
+ hqP->tbInfo[tbIdx].numLch = 0;
+ hqP->tbInfo[tbIdx].txCntr = 0;
+ /* FOR ACK NACK REP */
+ hqP->tbInfo[tbIdx].fbkRepCntr = 0;
+ hqP->tbInfo[tbIdx].fbkRecpRepCntr = 0;
+ hqP->tbInfo[tbIdx].ackCount = 0;
+ /* pdcch is moved from TbCb to HqCb.
+ This pdcch will be set to NULL when
+ HqCb will be pushed to free list*/
+ hqP->tbInfo[tbIdx].state = HQ_TB_ACKED;
+ hqP->tbInfo[tbIdx].isAckNackDtx = 0;
+ hqP->tbInfo[tbIdx].nackCount = 0;
+ hqP->tbInfo[tbIdx].dtxCount = 0;
+ hqP->tbInfo[tbIdx].schdTa.pres = NOTPRSNT;
+ hqP->tbInfo[tbIdx].contResCe = NOTPRSNT;
+#ifdef LTE_ADV
+ hqP->tbInfo[tbIdx].schdSCellActCe.pres = NOTPRSNT;
+#endif
+ hqP->tbInfo[tbIdx].minRlcReordrTmr = 0;
+ /* Handling msg4 hqProc */
+ if (hqE->msg4Proc == hqP)
+ {
+ hqE->msg4Proc = NULLP;
+ hqP->pdcch = NULLP;
+ hqP->subFrm = NULLP;
+ /* Add the proc to the free list */
+ //cmLListAdd2Tail(&hqE->free, &hqP->lnk);
+ rgSCHDhmHqPAdd2FreeLst(hqP);
+ RETVOID;
+ }
+#ifdef RGR_V1
+ /* MS_WORKAROUND : syed The check (hqE->ccchSduProc != NULLP)
+ * is dangerous and it expects ccchSduProc is the first
+ * DL allocation for a UE, and considering a scenario
+ * of multiple UEs contending and 1 UE per TTI, this
+ * assumption can be wronged, leading to inUse list
+ * corruption. Hence altering this check.
+ * A better approach would be do avoid having this
+ * special handling for ccchSduProc, streamline
+ * it with the usual approach. */
+ if (hqE->ccchSduProc == hqP)
+ {
+ hqE->ccchSduProc = NULLP;
+ /* ccpu00137582- If hqP is in reTxLst then it will be no more available
+ * in inUse list, Hence need not to delete from inUse list*/
+ if(NULLP == hqP->tbInfo[tbIdx].ccchSchdInfo.retxLnk.node)
+ {
+ //cmLListDelFrm(&hqE->inUse, &hqP->lnk);
+ rgSCHDhmHqPDelFrmInUseLst(hqP);
+ }
+ else
+ {
+ hqP->tbInfo[tbIdx].ccchSchdInfo.retxLnk.node = NULLP;
+ }
+ hqP->pdcch = NULLP;
+ hqP->subFrm = NULLP;
+ /* Add the proc to the free list */
+ //cmLListAdd2Tail(&hqE->free, &hqP->lnk);
+ rgSCHDhmHqPAdd2FreeLst(hqP);
+ RETVOID;
+ }
+#endif
+
+ /* extra:check if other TB is also free for allocation then
+ * add it to FREE List */
+ switch(hqP->tbInfo[othrTbIdx].state)
+ {
+ case HQ_TB_ACKED:
+ /* Remove the element from the inUse Queue */
+ /* Freeing up the HARQ proc blocked for
+ * indefinite time in case of Retx */
+ if (hqP->tbInfo[tbIdx].cntrRetxAllocFail != RG_SCH_MAX_RETX_ALLOC_FAIL)
+ {
+ //cmLListDelFrm(&hqE->inUse, &hqP->lnk);
+ rgSCHDhmHqPDelFrmInUseLst(hqP);
+ }
+ hqP->pdcch = NULLP;
+ hqP->subFrm = NULLP;
+#ifdef EMTC_ENABLE
+rgEmtcsetNullSubFrm(hqP);
+#endif
+ /* Add the proc to the free list */
+ //cmLListAdd2Tail(&hqE->free, &hqP->lnk);
+ rgSCHDhmHqPAdd2FreeLst(hqP);
+#ifdef LAA_DBG
+ if (hqE->free.count > 8)
+ {
+ int *p = NULL;
+ printf("Crashing invalid hq count after free \n");
+ printf("Crashing %d \n", *p);
+ *p = 10;
+ }
+#endif
+#ifdef LTEMAC_SPS
+ cmnHqDl = RG_SCH_CMN_GET_DL_HQP(hqP);
+ if (cmnHqDl)
+ {
+ cmnHqDl->spsAction = 0;
+ cmnHqDl->isSpsActv = FALSE;
+ cmnHqDl->isSpsSvcSchd = FALSE;
+ }
+#endif
+ break;
+ case HQ_TB_NACKED:
+ /* Remove the element from the inUse Queue */
+ /* Freeing up the HARQ proc blocked for
+ * indefinite time in case of Retx */
+ if (hqP->tbInfo[othrTbIdx].cntrRetxAllocFail == 0)
+ {
+ //cmLListDelFrm(&hqE->inUse, &hqP->lnk);
+ rgSCHDhmHqPDelFrmInUseLst(hqP);
+ }
+ break;
+ case HQ_TB_WAITING:
+ /* Do nothing */
+ break;
+ }
+
+ hqP->tbInfo[tbIdx].cntrRetxAllocFail = 0;
+
+ RETVOID;
+} /* rgSCHDhmRlsHqpTb */
+
+/**
+ * @brief This function releases a HARQ process.
+ *
+ * @details
+ *
+ * Function: rgSCHDhmRlsHqProc
+ * Purpose: This function returns a HARQ process to HARQ Entity
+ * in the DL direction.
+ *
+ * 1. Add the HARQ process to the free queue.
+ * Invoked by: scheduler and HARQ processing
+ *
+ * @param[in] RgDlHqProc *hqP
+ * @return Void
+ *
+ **/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmRlsHqProc
+(
+RgSchDlHqProcCb *hqP
+)
+#else
+PUBLIC Void rgSCHDhmRlsHqProc(hqP)
+RgSchDlHqProcCb *hqP;
+#endif
+{
+
+ TRC2(rgSCHDhmRlsHqProc)
+
+
+#ifdef MAC_SCH_STATS
+ /* THIS FUNCTION IS NOT CALLED */
+ if (hqP->hqE->ue != NULLP)
+ {
+ RgSchUeCb *ueCb = hqP->hqE->ue;
+ RgSchCmnUe *cmnUe = (RgSchCmnUe*)ueCb->sch;
+ RgSchCmnDlUe *dlUe = RG_SCH_CMN_GET_DL_UE(ueCb,hqE->cell);/*CA dev*/
+ U8 cqi = dlUe->mimoInfo.cwInfo[0].cqi;
+ /* to get retransmission, decreasing transmission counter */
+ U16 numDlRetx = hqP->tbInfo[0].txCntr-1;
+ U8 tbs = dlUe->mimoInfo.cwInfo[0].iTbs[0];
+
+ RG_SCH_CMN_DL_TBS_TO_MCS(tbs, hqRetxStats.dlCqiStat[(cqi - 1)].mcs);
+
+ switch (numDlRetx)
+ {
+ case 1:
+ hqRetxStats.dlCqiStat[(cqi - 1)].numOfHQ_1++;
+ break;
+ case 2:
+ hqRetxStats.dlCqiStat[(cqi - 1)].numOfHQ_2++;
+ break;
+ case 3:
+ hqRetxStats.dlCqiStat[(cqi - 1)].numOfHQ_3++;
+ break;
+ case 4:
+ hqRetxStats.dlCqiStat[(cqi - 1)].numOfHQ_4++;
+ break;
+ }
+ hqRetxStats.dlCqiStat[(cqi - 1)].totalTx = \
+ hqRetxStats.dlCqiStat[(cqi - 1)].numOfHQ_1 + \
+ (hqRetxStats.dlCqiStat[(cqi - 1)].numOfHQ_2 * 2) + \
+ (hqRetxStats.dlCqiStat[(cqi - 1)].numOfHQ_3 * 3) + \
+ (hqRetxStats.dlCqiStat[(cqi - 1)].numOfHQ_4 * 4);
+ }
+#endif /* MAC_SCH_STATS */
+ hqP->pdcch = NULLP;
+ hqP->subFrm = NULLP;
+#ifdef EMTC_ENABLE
+rgEmtcsetNullSubFrm(hqP);
+#endif
+ rgSCHDhmHqPDelFrmInUseLst(hqP);
+ rgSCHDhmHqPAdd2FreeLst(hqP);
+#ifdef TFU_UPGRADE
+ hqP->tbCnt = 0;
+#endif
+
+ RETVOID;
+} /* rgSCHDhmRlsHqProc */
+
+#ifdef LTEMAC_SPS
+/**
+ * @brief This function gets HARQ process with the given ID.
+ *
+ * @details
+ *
+ * Function: rgSCHDhmGetHqProcFrmId
+ * Purpose: This function returns the HARQ process with the given ID.
+ * Invoked by: ROM
+ *
+ * @param[in] RgSchUeCb *ue
+ * @param[in] U8 idx
+ * @param[in] RgDlHqProc **hqP
+ * @return S16
+ * -# ROK if successful
+ * -# RFAILED otherwise
+ *
+ **/
+#ifdef ANSI
+PUBLIC S16 rgSCHDhmGetHqProcFrmId
+(
+RgSchCellCb *cell,
+RgSchUeCb *ue,
+U8 idx,
+RgSchDlHqProcCb **hqP
+)
+#else
+PUBLIC S16 rgSCHDhmGetHqProcFrmId(cell, ue, idx, hqP)
+RgSchCellCb *cell;
+RgSchUeCb *ue;
+U8 idx;
+RgSchDlHqProcCb **hqP;
+#endif
+{
+ RgSchDlHqEnt *hqE;
+ TRC2(rgSCHDhmGetHqProcFrmId)
+
+ hqE = RG_SCH_CMN_GET_UE_HQE(ue, cell);
+ /* Pick the proc based on the index provided */
+ *hqP = &(hqE->procs[idx]);
+
+ RETVALUE(ROK);
+} /* rgSCHDhmGetHqProcFrmId */
+
+/**
+ * @brief This function gets SPS HARQ process from the given time
+ *
+ * @details
+ *
+ * Function: rgSCHDhmSpsDlGetHqProc
+ * Purpose: This function returns the SPS HARQ process for the given time
+ *
+ * @param[in] RgSchUeCb *ue
+ * @param[in] CmLteTimingInfo timingInfo
+ * @return RgSchDlHqProcCb control block
+ *
+ **/
+#ifdef ANSI
+PUBLIC RgSchDlHqProcCb* rgSCHDhmSpsDlGetHqProc
+(
+RgSchCellCb *cell,
+RgSchUeCb *ue,
+CmLteTimingInfo timingInfo
+)
+#else
+PUBLIC RgSchDlHqProcCb* rgSCHDhmSpsDlGetHqProc(cell, ue, timingInfo)
+RgSchCellCb *cell,
+RgSchUeCb *ue;
+CmLteTimingInfo timingInfo;
+#endif
+{
+ RgSchDlHqEnt *hqE;
+ U8 idx;
+ RgSchDlHqProcCb *hqProc = NULLP;
+ CmLList *tmp = NULLP;
+
+ TRC2(rgSCHDhmSpsDlGetHqProc);
+
+ hqE = RG_SCH_CMN_GET_UE_HQE(ue, cell);
+
+ CM_LLIST_FIRST_NODE(&(hqE->free), tmp);
+
+ if (NULLP == tmp)
+ {
+ /* No Harq Process available in the free queue. */
+ RETVALUE(NULLP);
+ }
+
+ idx = ((timingInfo.sfn * RGSCH_NUM_SUB_FRAMES_5G + timingInfo.subframe)/
+ ue->dl.dlSpsCfg.dlSpsPrdctyEnum) % ue->dl.dlSpsCfg.numSpsHqProc;
+
+
+ hqProc = (RgSchDlHqProcCb *)(tmp->node);
+
+ /* If the HARQ process is in the free list, retrieve the process */
+ while (hqProc->procId != idx)
+ {
+ CM_LLIST_NEXT_NODE(&(hqE->free), tmp);
+ if (!tmp)
+ {
+ break;
+ }
+ hqProc = (RgSchDlHqProcCb *)(tmp->node);
+ }
+
+ if (!tmp)
+ {
+ /* No Harq Process available in the free queue. */
+ RETVALUE(NULLP);
+ }
+
+ hqProc->tbInfo[0].timingInfo = timingInfo;
+ hqProc->tbInfo[1].timingInfo = timingInfo;
+
+ /* Remove the element from the free Queue */
+ //cmLListDelFrm(&hqE->free, tmp);
+ rgSCHDhmHqPDelFrmFreeLst(hqProc);
+
+ /* Add the element into the inUse Queue as well */
+ //cmLListAdd2Tail(&hqE->inUse, &hqProc->lnk);
+ rgSCHDhmHqPAdd2InUseLst(hqProc);
+
+#ifdef LTE_ADV
+ rgSCHLaaResetDlHqProcCb(hqProc);
+#endif
+
+ RETVALUE(hqProc);
+} /* rgSCHDhmSpsDlGetHqProc */
+#endif /* LTEMAC_SPS */
+
+
+/** * @brief Handler for handling TA.
+ *
+ * @details
+ *
+ * Function : rgSCHDhmFdbkIndHndlTa
+ *
+ * This function handles the TA state and values based on the
+ * feedback indication received.
+ *
+ * @param[in] RgSchDlHqProcCb *hqP
+ * @param[in] U8 tbIdx
+ * @param[in] U8 fdbk
+ * @return Void
+ * -# None.
+ **/
+#ifdef ANSI
+PRIVATE Void rgSCHDhmFdbkIndHndlTa
+(
+RgSchDlHqProcCb *hqP,
+U8 tbIdx,
+U8 fdbk,
+Bool maxHqRetxReached
+)
+#else
+PRIVATE Void rgSCHDhmFdbkIndHndlTa(hqP, tbIdx, fdbk,maxHqRetxReached)
+RgSchDlHqProcCb *hqP;
+U8 tbIdx;
+U8 fdbk;
+Bool maxHqRetxReached;
+#endif
+{
+ RgSchUeCb *ueCb;
+ RgSchCellCb *cell;
+
+ TRC2(rgSCHDhmFdbkIndHndlTa)
+
+ ueCb = hqP->hqE->ue;
+ cell = ueCb->cell;
+ switch(fdbk)
+ {
+ case TRUE:
+ /*ccpu00130018 -ADD - To prevent duplicate insert into the TA list*/
+ hqP->tbInfo[tbIdx].taSnt = FALSE;
+ /* To prevent duplicate inserts of ueCb into TA list */
+ if (ueCb->taLnk.node == NULLP)
+ {
+ ueCb->taLnk.node = (PTR)ueCb;
+ cmLListAdd2Tail(&cell->taUeLst, &ueCb->taLnk);
+ }
+ else
+ {
+#ifdef DEBUGP
+ RLOG_ARG1(L_ERROR,DBG_CELLID,cell->cellId, "Trying to add CRNTI:%d into TA"
+ "ACK List twice", ueCb->ueId);
+#endif
+ }
+ break;
+
+ case FALSE:
+ /* If Ta was sent and its the final NACK, then reset only the
+ * taState to IDLE and not the value */
+ /* Changed handling in case maxhqretx is reached for TA */
+ if(TRUE == maxHqRetxReached)
+ {
+ hqP->tbInfo[tbIdx].taSnt = FALSE;
+ hqP->hqE->ue->dl.taCb.state = RGSCH_TA_IDLE;
+
+ rgSCHUtlReTxTa(cell, ueCb);
+ RLOG_ARG0(L_DEBUG,DBG_CELLID,cell->cellId,
+ "Nack Rcvd for TA. Max Tries Attempted");
+ }
+ break;
+ case TFU_HQFDB_DTX:
+ /* If Ta was sent and its the final NACK, then reset only the
+ * taState to IDLE and not the value */
+ if(TRUE == maxHqRetxReached)
+ {
+ hqP->tbInfo[tbIdx].taSnt = FALSE;
+ hqP->hqE->ue->dl.taCb.state = RGSCH_TA_IDLE;
+
+ /*ccpu00131191 and ccpu00131317 - Fix for RRC Reconfig failure
+ * issue for VoLTE call */
+ rgSCHUtlDlTARpt(cell, ueCb);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ RETVOID;
+} /* rgSCHDhmFdbkIndHndlTa */
+
+/* 3.1 MIMO: TA cmd details at TB level rather than Hq Level */
+/** * @brief Handler for scheduling TA.
+ *
+ * @details
+ *
+ * Function : rgSCHDhmShcdTa
+ *
+ * This function is called by scheduler when resource allocation
+ * for TA transmission is done.
+ *
+ * @param[in] RgSchUeCb *ue
+ * @param[out] RgSchDlHqTbCb *tbInfo
+ * @return Void
+ * -# None.
+ **/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmSchdTa
+(
+RgSchUeCb *ueCb,
+RgSchDlHqTbCb *tbInfo
+)
+#else
+PUBLIC Void rgSCHDhmSchdTa(ueCb, tbInfo)
+RgSchUeCb *ueCb;
+RgSchDlHqTbCb *tbInfo;
+#endif
+{
+
+ TRC2(rgSCHDhmSchdTa)
+
+ ueCb->dl.taCb.state = RGSCH_TA_SCHEDULED;
+ ueCb->dl.taCb.numRemSf = 2;
+ tbInfo->schdTa.pres = PRSNT_NODEF;
+ tbInfo->schdTa.val = ueCb->dl.taCb.ta;
+
+ RETVOID;
+} /* rgSCHDhmSchdTa */
+
+#ifdef LTE_TDD
+/** * @brief Handler for fetching Harq Proc given the feeback information.
+ *
+ * @details
+ *
+ * Function : rgSCHDhmHqProcByFdbkTime
+ *
+ * This function shall fetch all the harq proc having the feedback
+ * timing information.
+ *
+ * @param[in] RgSchDlHqEnt *hqE
+ * @param[in] CmLteTimingInfo timeInfo
+ * @param[in] Bool *isMsg4
+ * @param[out] RgSchDlHqProcCb **hqPrcs
+ * @param[out] U8 *numTbs
+ * @param[out] S8 *tbStrtIdx
+ * @param[out] U8 *cntHqPrcs
+ * @return S16
+ **/
+#ifdef ANSI
+PRIVATE S16 rgSCHDhmHqProcByFdbkTime
+(
+RgSchDlHqEnt *hqE,
+CmLteTimingInfo timeInfo,
+Bool *isMsg4,
+RgSchDlHqProcCb **hqPrcs,
+U8 *numTbs,
+S8 *tbStrtIdx,
+U8 *cntHqPrcs,
+RgSchCellCb *cell
+)
+#else
+PRIVATE S16 rgSCHDhmHqProcByFdbkTime(hqE, timeInfo, isMsg4, hqPrcs,
+ numTbs, tbStrtIdx, cntHqPrcs)
+RgSchDlHqEnt *hqE;
+CmLteTimingInfo timeInfo;
+Bool *isMsg4;
+RgSchDlHqProcCb **hqPrcs;
+U8 *numTbs;
+S8 *tbStrtIdx;
+U8 *cntHqPrcs;
+RgSchCellCb *cell;
+#endif
+{
+ RgSchDlHqTbCb *tbCb;
+ RgSchDlHqProcCb *hqP;
+ CmLteTimingInfo schdSfTime;
+ RgSchTddDlAscSetIdxK ascIdx;
+ U8 noFdbks;
+ U8 i;
+ U8 idx;
+ U8 dlIdx;
+ CmLListCp *lnk;
+ CmLList *node;
+
+ *cntHqPrcs = 0;
+ if (hqE->msg4Proc)
+ {
+ if (RGSCH_TIMEINFO_SAME(hqE->msg4Proc->tbInfo[0].fdbkTime, timeInfo))
+ {
+ *isMsg4 = TRUE;
+ hqPrcs[*cntHqPrcs] = hqE->msg4Proc;
+ tbStrtIdx[*cntHqPrcs] = 0;
+ numTbs[*cntHqPrcs] = 1;
+ (*cntHqPrcs)++;
+ RETVALUE(ROK);
+ }
+ }
+ ascIdx = rgSchTddDlAscSetIdxKTbl[cell->ulDlCfgIdx][timeInfo.subframe];
+ noFdbks = ascIdx.numFdbkSubfrms;
+
+ for(idx=0; idx<noFdbks; idx++)
+ {
+ /* ccpu00133109: Removed RGSCHSUBFRMCRNTTIME as it is not giving proper output
+ * if diff is more than 10. Instead using RGSCHDECRFRMCRNTTIME() as it is
+ * serving the purpose */
+ RGSCHDECRFRMCRNTTIME(timeInfo,schdSfTime,ascIdx.subfrmNum[idx]);
+ dlIdx = rgSCHUtlGetDlSfIdx(cell, &schdSfTime);
+ lnk = &hqE->ue->dl.dlSfHqInfo[dlIdx].hqPLst;
+ node = lnk->first;
+ while (node)
+ {
+ hqP = (RgSchDlHqProcCb*)node->node;
+ node = node->next;
+
+ numTbs[*cntHqPrcs] = 0;
+ tbStrtIdx[*cntHqPrcs] = -1;
+ for (i = 0; i < 2; i++)
+ {
+ /* Extra:check which TB is waiting for feedback */
+ if (hqP->tbInfo[i].state == HQ_TB_WAITING)
+ {
+ if (tbStrtIdx[*cntHqPrcs] == -1)
+ {
+ tbStrtIdx[*cntHqPrcs] = i;
+ }
+ numTbs[*cntHqPrcs]++;
+ }
+ }
+ if (numTbs[*cntHqPrcs] > 0)
+ {
+ hqPrcs[*cntHqPrcs] = hqP;
+ (*cntHqPrcs)++;
+ }
+ }
+
+ /* AN REP Hq Procs */
+ node = cell->subFrms[dlIdx]->ackNakRepQ.first;
+ while(node)
+ {
+ tbCb = (RgSchDlHqTbCb *)(node->node);
+ hqP = tbCb->hqP;
+
+ numTbs[*cntHqPrcs] = 0;
+ tbStrtIdx[*cntHqPrcs] = -1;
+ for (i = 0; i < 2; i++)
+ {
+ /* Extra:check which TB is waiting for feedback */
+ if (hqP->tbInfo[i].state == HQ_TB_WAITING)
+ {
+ if (tbStrtIdx[*cntHqPrcs] == -1)
+ {
+ tbStrtIdx[*cntHqPrcs] = i;
+ }
+ numTbs[*cntHqPrcs]++;
+ }
+ }
+ if (numTbs[*cntHqPrcs] == 2)
+ {
+ node = node->next;
+ }
+ if (numTbs[*cntHqPrcs] > 0)
+ {
+ hqPrcs[*cntHqPrcs] = hqP;
+ (*cntHqPrcs)++;
+ }
+
+ node = node->next;
+ }
+ }
+
+
+ RETVALUE(ROK);
+}
+#else /* LTE_TDD */
+/** * @brief Handler for fetching Harq Proc given the timming information.
+ *
+ * @details
+ *
+ * Function : rgSCHDhmHqProcByTime
+ *
+ * This function shall fetch the harq proc using the timing information.
+ *
+ * @param[in] RgSchDlHqEnt *hqE
+ * @param[in] CmLteTimingInfo timeInfo
+ * @param[in] Bool *isMsg4
+ * @param[out] U8 *numTbs
+ * @param[out] S8 *tbStrtIdx
+ * @return RgSchDlHqProcCb*
+ * -# RgSchDlHqProcCb*
+ * -# NULLP
+ **/
+#ifdef ANSI
+PUBLIC RgSchDlHqProcCb *rgSCHDhmHqProcByTime
+(
+RgSchDlHqEnt *hqE,
+CmLteTimingInfo timeInfo,
+Bool *isMsg4,
+RgSchDlSf *sf
+)
+#else
+PUBLIC RgSchDlHqProcCb *rgSCHDhmHqProcByTime(hqE, timeInfo,
+ isMsg4,sf)
+RgSchDlHqEnt *hqE;
+CmLteTimingInfo timeInfo;
+Bool *isMsg4;
+RgSchDlSf *sf;
+#endif
+{
+ if (hqE->msg4Proc)
+ {
+ if (RGSCH_TIMEINFO_SAME(hqE->msg4Proc->tbInfo[0].timingInfo, timeInfo))
+ {
+ *isMsg4 = TRUE;
+ RETVALUE(hqE->msg4Proc);
+ }
+ }
+
+ RETVALUE(NULLP);
+}
+#endif
+
+/** * @brief Handler for handling the harq transaction failure.
+ *
+ * @details
+ *
+ * Function : rgSCHDhmHqTbTrnsFail
+ *
+ * This function handled the harq TB transaction failure :
+ * - If retries have not reached maximum, add to the reTx Q.
+ * - else do error recovery.
+ *
+ * @param[in] RgSchCellCb *cell
+ * @param[in] RgSchDlHqProcCb *hqP
+ * @param[in] U8 tbCnt
+ * @param[out] Bool *isMaxRetx
+ * @return Void
+ * -#None.
+ *
+ **/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmHqTbTrnsFail
+(
+RgSchCellCb *cell,
+RgSchDlHqProcCb *hqP,
+U8 tbCnt,
+Bool *isMaxRetx
+)
+#else
+PUBLIC Void rgSCHDhmHqTbTrnsFail(cell, hqP, tbCnt, isMaxRetx)
+RgSchCellCb *cell;
+RgSchDlHqProcCb *hqP;
+U8 tbCnt;
+Bool *isMaxRetx;
+#endif
+{
+ RgSchDlHqEnt *hqE;
+ U8 maxHqTx;
+
+ TRC2(rgSCHDhmHqTbTrnsFail)
+
+ hqE = hqP->hqE;
+
+ /* Fetch the maximum number of harq transmissions */
+ if (hqE->msg4Proc == hqP)
+ {
+#ifdef RGR_V1
+ if(hqP->hqE->raCb->expiryTime.sfn == RGSCH_CONTRES_EXP)
+ {
+ RLOG_ARG1(L_DEBUG,DBG_CELLID,cell->cellId,
+ "rgSCHDhmHqTbTrnsFail contRes exp(): tmpCRNTI = %u",
+ hqP->hqE->raCb->tmpCrnti);
+ rgSCHRamMsg4Done(cell, (RgSchRaCb *)hqP->hqE->raCb);
+ RETVOID;
+ }
+#endif
+ maxHqTx = cell->dlHqCfg.maxMsg4HqTx;
+ }
+ else
+ {
+ maxHqTx = hqE->maxHqTx;
+ }
+
+#ifdef MAC_SCH_STATS
+ if (hqE->ue != NULLP)
+ {
+ RgSchUeCb *ueCb = hqE->ue;
+ RgSchCmnUe *cmnUe = (RgSchCmnUe*)ueCb->sch;
+ RgSchCmnDlUe *dlUe = RG_SCH_CMN_GET_DL_UE(ueCb,hqE->cell);/*CA dev*/
+ U8 tbs = dlUe->mimoInfo.cwInfo[0].iTbs[0];
+ static U32 retxCnt = 0;
+
+ {
+ ++retxCnt;
+ hqFailStats.dlCqiStat[(dlUe->mimoInfo.cwInfo[0].cqi - 1)].numOfNacks++;
+ }
+ RG_SCH_CMN_DL_TBS_TO_MCS(tbs,
+ (hqFailStats.dlCqiStat[(dlUe->mimoInfo.cwInfo[0].cqi - 1)].mcs));
+ }
+#endif /* MAC_SCH_STATS */
+
+ RGSCH_ARRAY_BOUND_CHECK(cell->instIdx, hqP->tbInfo, tbCnt);
+ /* Reset the PDCCH reference */
+ hqP->pdcch = NULL;
+ if (hqP->tbInfo[tbCnt].txCntr < maxHqTx)
+ {
+ hqP->tbInfo[tbCnt].state = HQ_TB_NACKED;
+
+ if((hqE->ue != NULLP) && (hqE->ue->isDrxEnabled == TRUE))
+ {
+
+ /*If DRX is enabled for the UE, we need to start the HARQ RTT timer
+ * for the UE. Addtion to the retransmission queue will be done on
+ * HARQ RTT timer expiry.--*/
+ switch(hqP->tbInfo[tbCnt ^ 1].state)
+ {
+ case HQ_TB_ACKED:
+ /*As the first TB is ACKED we have not started HARQ RTT for the
+ * HqP, so start it here.*/
+ //cmLListDelFrm(&hqE->inUse, &hqP->lnk);
+ rgSCHDhmHqPDelFrmInUseLst(hqP);
+ /* CA Dev Start */
+ rgSCHDrxStartHarqRTTTmr(hqP->hqE->ue->cell, hqP, tbCnt);
+ /* CA Dev End*/
+#ifdef LTEMAC_SPS
+ /* Integration fix */
+ /* Setting cntrRetxAllocFail to MAX value here */
+ /* Since the hqP entry is already deleted from inUse list of HqEntity
+ setting the value here will ensure the entry is not deleted
+ again during release harq proc */
+ if ( (hqP->sch != (RgSchCmnDlHqProc *)NULLP) &&
+ (RG_SCH_CMN_SPS_DL_IS_SPS_HQP(hqP)))
+ {
+ hqP->tbInfo[0].cntrRetxAllocFail = RG_SCH_MAX_RETX_ALLOC_FAIL;
+ if (hqP->tbInfo[1].txCntr)
+ {
+ hqP->tbInfo[1].cntrRetxAllocFail = RG_SCH_MAX_RETX_ALLOC_FAIL;
+ }
+ }
+#endif
+ break;
+ case HQ_TB_NACKED:
+ /*As the first TB is NACKED we have already started HARQ RTT for the
+ * HqP, so dont start it here, just delete from in use queue.*/
+ //cmLListDelFrm(&hqE->inUse, &hqP->lnk);
+ rgSCHDhmHqPDelFrmInUseLst(hqP);
+ break;
+ case HQ_TB_WAITING:
+ /*As this is the first TB to be fed back and is NACKED start
+ * the HARQ RTT here.*/
+ /* CA Dev Start */
+ rgSCHDrxStartHarqRTTTmr(hqP->hqE->ue->cell, hqP,tbCnt);
+ /* CA Dev End*/
+ break;
+ }
+ RETVOID;
+ }
+ /* extra:check if already removed as part of other TB processing
+ * then donot remove from InUse Q */
+ /* Check if other TB is not waiting for feedback.
+ * Makinf sure hqP is present in inUse Queue until
+ * it is fedback for all its TBs */
+ switch(hqP->tbInfo[tbCnt ^ 1].state)
+ {
+ case HQ_TB_ACKED:
+ /*Fix for ccpu00113296 - Do not delete for Msg4 Harq Entities*/
+ if(hqE->msg4Proc != hqP)
+ {
+ //cmLListDelFrm(&hqE->inUse, &hqP->lnk);
+ rgSCHDhmHqPDelFrmInUseLst(hqP);
+ }
+ /* Retransmission needs to be done. Add to the scheduler Q */
+ rgSCHUtlDlProcAddToRetx(hqP->hqE->cell, hqP);
+ break;
+ case HQ_TB_NACKED:
+ /*Fix for ccpu00113296 - Do not delete for Msg4 Harq Entities*/
+ if(hqE->msg4Proc != hqP)
+ {
+ //cmLListDelFrm(&hqE->inUse, &hqP->lnk);
+ rgSCHDhmHqPDelFrmInUseLst(hqP);
+ }
+ break;
+ case HQ_TB_WAITING:
+ /* Retransmission needs to be done. Add to the scheduler Q */
+ /* CA Dev Start*/
+ rgSCHUtlDlProcAddToRetx(hqP->hqE->cell, hqP);
+ /* CA Dev End*/
+ break;
+ }
+ *isMaxRetx = FALSE;
+ }
+ else
+ {
+ /* Failure Notification */
+ if (hqE->msg4Proc == hqP)
+ {
+ /* SR_RACH_STATS : MSG4 Max Retx Fail*/
+ rgNumMsg4FailMaxRetx++;
+#ifdef TENB_STATS
+ hqE->cell->tenbStats->sch.msg4Fail ++;
+#endif
+
+ /* Perform RAM MSG4 done processing */
+ RLOG_ARG1(L_DEBUG,DBG_CELLID,cell->cellId,
+ "rgSCHDhmHqTbTrnsFail(): hq max retx fail: tmpCRNTI = %u",
+ hqP->hqE->raCb->tmpCrnti);
+ rgSCHRamMsg4Done(cell, (RgSchRaCb *)hqP->hqE->raCb);
+ }
+ else
+ {
+ /* Release the Harq Proc */
+ rgSCHDhmRlsHqpTb(hqP, tbCnt, TRUE);
+ }
+ *isMaxRetx = TRUE;
+ }
+
+ RETVOID;
+} /* rgSCHDhmHqTbTrnsFail */
+
+PUBLIC U32 rgHqRvStats[2][4][2] = {{{0, 0}, {0, 0}, {0, 0}, {0, 0}},
+ {{0, 0}, {0, 0}, {0, 0}, {0, 0}}};
+#ifdef LTE_TDD
+#ifdef LTE_ADV
+/** * @brief Function to decode the position of HarqFb for M=1.
+ *
+ * @details
+ *
+ * Function : rgSchGetHqFdbkPosForM1
+ *
+ * @param[in] RgSchUeCb *ue,
+ * @param[in] RgSchDlHqProcCb *hqP,
+ * @param[in] U8 *isAck,
+ * @param[in] RgTfuHqInfo *fdbk,
+ * @param[in] U8 tbIdx,
+ * @param[in] RgSchTddANInfo *anInfo;
+ * @return RETVOID
+ **/
+#ifdef ANSI
+PRIVATE Void rgSchGetHqFdbkPosForM1
+(
+ RgSchUeCb *ue,
+ RgSchDlHqProcCb *hqP,
+ U8 *isAck,
+ RgTfuHqInfo *fdbk,
+ U8 tbIdx,
+ RgSchTddANInfo *anInfo
+ )
+#else
+PRIVATE Void rgSchGetHqFdbkPosForM1(ue,hqP,isAck,fdbk,tbIdx,anInfo)
+ RgSchUeCb *ue;
+ RgSchDlHqProcCb *hqP;
+ U8 *isAck;
+ RgTfuHqInfo *fdbk;
+ U8 tbIdx;
+ RgSchTddANInfo *anInfo;
+#endif
+{
+ if((ue != NULLP))
+ {
+ /* handle pusch and pucch cases */
+ /* PUSCH:: Fdbks are in the increasing order
+ * of servCellIdx as per 36.212 section 5.2.26*/
+ switch(ue->f1bCsAVal)
+ {
+ case RG_SCH_A_VAL_2:
+ {
+ if(RG_SCH_IS_CELL_SEC(ue,hqP->hqE->cell))
+ {
+ *isAck = fdbk->isAck[1];/*SCell*/
+ }
+ else
+ {
+ *isAck = fdbk->isAck[0];/*PCell*/
+ }
+ break;
+ }
+ case RG_SCH_A_VAL_3:
+ {
+ if(RG_SCH_IS_CELL_SEC(ue,hqP->hqE->cell))
+ {
+ U8 cellIdx = rgSchUtlGetServCellIdx(hqP->hqE->cell->instIdx,
+ hqP->hqE->cell->cellId,
+ hqP->hqE->ue);
+
+ if(rgSCHUtlGetMaxTbSupp(ue->cellInfo[cellIdx]->txMode.txModeEnum) > 1)
+ {/*SCell - mimo mode*/
+ if(TRUE == fdbk->isPusch)
+ {
+ *isAck = fdbk->isAck[tbIdx + 1];
+ }
+ else
+ {
+ *isAck = fdbk->isAck[tbIdx];
+ }
+ }
+ else
+ {/*SCell - siso mode*/
+ *isAck = fdbk->isAck[2];
+ }
+ }else
+ {
+ if(rgSCHUtlGetMaxTbSupp(ue->mimoInfo.txMode) > 1)
+ {/*Primary Cell - mimo mode*/
+ *isAck = fdbk->isAck[tbIdx];
+ }
+ else
+ {/*Primary Cell - siso mode*/
+ if((TRUE == fdbk->isPusch) && (FALSE == anInfo->isSpsOccasion))
+ {
+ /* If fdbk is on PUSCH but its not an SPS occasion*/
+ *isAck = fdbk->isAck[0];
+ }
+ else
+ {
+ /* If fdbk is on PUCCH or its an SPS occasion*/
+ *isAck = fdbk->isAck[2];
+ }
+ }
+ }
+ break;
+ }
+ case RG_SCH_A_VAL_4:
+ {
+ if(RG_SCH_IS_CELL_SEC(ue,hqP->hqE->cell))
+ {
+ *isAck = fdbk->isAck[tbIdx + 2];
+ }
+ else
+ {
+ *isAck = fdbk->isAck[tbIdx];
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ RETVOID;
+}/* End of rgSchGetHqFdbkPosForM1 */
+
+/** * @brief Function to decode the position of HarqFb for M>=2 cases.
+ *
+ * @details
+ *
+ * Function : rgSchGetHqFdbkPosForM234
+ *
+ * @param[in] RgSchUeCb *ue,
+ * @param[in] RgSchDlHqProcCb *hqP,
+ * @param[in] U8 *isAck,
+ * @param[in] RgTfuHqInfo *fdbk,
+ * @param[in] U8 tbIdx,
+ * @param[in] RgSchTddANInfo *anInfo;
+ * @param[in] CmLteTimingInfo timeInfo;
+ * @return RETVOID
+ **/
+#ifdef ANSI
+PRIVATE Void rgSchGetHqFdbkPosForM234
+(
+ RgSchUeCb *ue,
+ RgSchDlHqProcCb *hqP,
+ U8 *isAck,
+ RgTfuHqInfo *fdbk,
+ U8 tbIdx,
+ RgSchTddANInfo *anInfo,
+ U8 M,
+ CmLteTimingInfo timeInfo
+ )
+#else
+PRIVATE Void rgSchGetHqFdbkPosForM234(ue,hqP,isAck,fdbk,tbIdx,anInfo,M,timeInfo)
+ RgSchUeCb *ue;
+ RgSchDlHqProcCb *hqP;
+ U8 *isAck;
+ RgTfuHqInfo *fdbk;
+ U8 tbIdx;
+ RgSchTddANInfo *anInfo;
+ U8 M;
+ CmLteTimingInfo timeInfo;
+#endif
+{
+ U8 fdbkIdx;
+ Bool isSCell;
+ RgSchTddANInfo *pCellAnInfo;
+ U8 incr = 0;
+
+ if(NULLP != ue)
+ {
+ isSCell = RG_SCH_IS_CELL_SEC(ue,hqP->hqE->cell);
+ pCellAnInfo = rgSCHUtlGetUeANFdbkInfo(ue, &timeInfo, RGSCH_PCELL_INDEX);
+
+ if(TRUE == fdbk->isPusch)
+ {
+ if(TRUE == isSCell)
+ {/*SCell*/
+ if (anInfo->wUlDai == 3)
+ {
+ incr = anInfo->wUlDai;
+ }
+ else
+ {
+ incr = M;
+ }
+ if(1 == anInfo->ulDai)
+ {
+ fdbkIdx = (hqP->tbInfo[tbIdx].dai - 1) +
+ hqP->tbInfo[tbIdx].tbIdx + incr;
+ }
+ else
+ {
+ fdbkIdx = (hqP->tbInfo[tbIdx].dai - 1) + incr;
+ }
+ }
+ else
+ {/*PCell*/
+ if(1 == anInfo->ulDai)
+ {
+ if(rgSCHUtlGetMaxTbSupp(ue->mimoInfo.txMode) > 1)
+ {
+ fdbkIdx = (hqP->tbInfo[tbIdx].dai - 1) + (hqP->tbInfo[tbIdx].tbIdx);
+ }
+ else
+ {
+ fdbkIdx = (hqP->tbInfo[tbIdx].dai) - 1;
+ }
+ }
+ else
+ {
+ fdbkIdx = (hqP->tbInfo[tbIdx].dai) - 1;
+ }
+ }
+ }
+ else
+ {/*PUCCH*/
+ if(TRUE == isSCell)
+ {
+ /* pucchFdbkIdx is set to DAI hence -1 to get index */
+ fdbkIdx = ((hqP->tbInfo[tbIdx].pucchFdbkIdx) + M -1);
+ }
+ else
+ {
+ if(M > 2)
+ {
+ /* SPS occasion feedback in case of M > 2 will
+ * be always present in the index 0*/
+#ifdef LTEMAC_SPS
+ if(hqP->spsN1PucchRes.pres == TRUE)
+ {/* SPS occasion hq proc */
+ fdbkIdx = 0;
+ }else
+#endif
+ if((NULLP != pCellAnInfo) &&
+ (pCellAnInfo->dlDai != pCellAnInfo->ulDai))
+ {
+ fdbkIdx = hqP->tbInfo[tbIdx].pucchFdbkIdx;
+ }else
+ {/* NO SPS occasion was present in the bundle*/
+ fdbkIdx = hqP->tbInfo[tbIdx].pucchFdbkIdx - 1;
+ }
+ }
+ else
+ {
+ fdbkIdx = hqP->tbInfo[tbIdx].pucchFdbkIdx - 1;
+ }
+ }
+ }
+ *isAck = fdbk->isAck[fdbkIdx];
+#ifdef DLHQ_STATS
+ static RgSchDlHqProcCb *temp = NULLP;
+ if (temp != hqP->tbInfo[tbIdx].hqP)
+ {
+ statsCnt = statsCnt % 10000;
+ dlHqStats[statsCnt].cellId = hqP->hqE->cell->cellId;
+ dlHqStats[statsCnt].sfn = hqP->tbInfo[tbIdx].timingInfo.sfn;
+ dlHqStats[statsCnt].sf = hqP->tbInfo[tbIdx].timingInfo.subframe;
+ dlHqStats[statsCnt].ack = *isAck;
+ dlHqStats[statsCnt].fdbkIdx = fdbkIdx;
+ dlHqStats[statsCnt].ue = hqP->hqE->ue->ueId;;
+ if (anInfo)
+ dlHqStats[statsCnt].ulDai = incr;
+ if(TRUE == fdbk->isPusch)
+ {
+ dlHqStats[statsCnt].dlDai = hqP->tbInfo[tbIdx].dai;
+ }
+ else
+ {
+ dlHqStats[statsCnt].dlDai = hqP->tbInfo[tbIdx].pucchFdbkIdx;
+ }
+ if (*isAck != 1)
+ {
+ dlHqStats[statsCnt].ack0 = fdbk->isAck[0];
+ dlHqStats[statsCnt].ack1 = fdbk->isAck[1];
+ dlHqStats[statsCnt].ack2 = fdbk->isAck[2];
+ dlHqStats[statsCnt].ack3 = fdbk->isAck[3];
+ dlHqStats[statsCnt].ack4 = fdbk->isAck[4];
+ dlHqStats[statsCnt].ack5 = fdbk->isAck[5];
+ dlHqStats[statsCnt].ack6 = fdbk->isAck[6];
+ dlHqStats[statsCnt].ack7 = fdbk->isAck[7];
+ }
+ statsCnt++;
+ temp = hqP->tbInfo[tbIdx].hqP;
+ }
+#endif
+ }/*ue*/
+ RETVOID;
+}/*rgSchGetHqFdbkPosForM234*/
+#endif/*LTE_ADV*/
+
+/*
+ * @brief Handler for HARQ feedback received for DL transmission.
+ *
+ * @details
+ *
+ * Function : rgSCHDhmHqFdbkInd
+ *
+ * This function shall act on the feedback received from TOM for DL
+ * transmission. If the feedback for msg4 is final (after max transmissions
+ * or ACK) inform RAM that Msg4 transmission is done.
+ *
+ *
+ * @param[in] Void *cb
+ * @param[in] U8 cbType
+ * @param[in] RgSchCellCb cellCb
+ * @param[in] CmLteTimingInfo timeInfo
+ * @param[in] TfuHqInfo *fdbk
+ * @param[in] RgInfRlsHqInfo *rlsHqBufs
+ * @param[in] RgSchErrInfo *err
+ * @return S16
+ * -# ROK
+ * -# RFAILED
+ **/
+#ifdef ANSI
+PUBLIC S16 rgSCHDhmHqFdbkInd
+(
+Void *cb,
+U8 cbType,
+RgSchCellCb *cellCb,
+CmLteTimingInfo timeInfo,
+TfuHqInfo *fdbk,
+RgInfRlsHqInfo *rlsHqBufs,
+RgSchErrInfo *err
+)
+#else
+PUBLIC S16 rgSCHDhmHqFdbkInd(cb, cbType, cellCb, timeInfo, fdbk, rlsHqBufs, err)
+Void *cb;
+U8 cbType;
+RgSchCellCb *cellCb;
+CmLteTimingInfo timeInfo;
+TfuHqInfo *fdbk;
+RgInfRlsHqInfo *rlsHqBufs;
+RgSchErrInfo *err;
+#endif
+{
+ RgSchCellCb *sCell = NULLP;
+ RgSchDlHqEnt *hqE;
+ /*ccpu00127339 - MOD - change to avoid the crash*/
+ RgSchUeCb *ue = NULLP;
+ RgSchDlSf *sf;
+ Bool isMsg4 = FALSE;
+ RgSchRaCb *raCb = NULLP;
+ U16 rnti=0;
+ /* Maximum possible HARQ processes in UL-DL configuration 5 that is
+ * given feedback at a time */
+ RgSchDlHqProcCb *hqPrcs[(RGSCH_NUM_SUB_FRAMES-1)*5]; /*MAX 5 Cells*/
+ U8 numTb[(RGSCH_NUM_SUB_FRAMES-1)*5];
+ S8 tbStrtIdx[(RGSCH_NUM_SUB_FRAMES-1)*5];
+ U8 hqCnt;
+ U8 idx;
+ RgSchTddANInfo *anInfo = NULLP;
+ U8 isAck = 0;
+ U8 tbCnt;
+ RgrTddAckNackMode ackNackMode;
+ Bool hqRls = FALSE;
+ RgSchDlSf *nxtDlsf = NULLP;
+ /* U8 rcvCnt = 0; */
+ CmLteTimingInfo nxtfrm = {0,0};
+ Bool anUpd = FALSE;
+ Bool maxHqRetxReached;
+#ifdef LTEMAC_SPS
+ Bool hasRelPdcch = FALSE;
+#endif
+
+#if ((defined LTEMAC_SPS_AN_MUX) || (defined LTE_ADV))
+ RgSchTddDlAscSetIdxK ascIdx;
+ U8 noFdbks;
+#endif
+
+#ifdef LTEMAC_SPS_AN_MUX
+ Bool isPusch = FALSE;
+ U8 tmpIdx;
+ U8 hIdx;
+ /* Subframes in which transmissions are scheduled and whose feedback can come
+ * in this subframe. Used only for Multiplexing mode */
+ CmLteTimingInfo schdSfTime[RGSCH_TDD_MAX_FDBK];
+#ifdef RGSCH_SPS_STATS
+ RgSchCmnDlHqProc *cmnHqDl;
+#endif
+#endif
+#ifdef LTE_ADV
+ U8 sCellActCePres = 0;
+#endif
+/* LTEMAC_SPS_AN_MUX*/
+ RgrSchFrmt1b3TypEnum uciFrmtTyp = RG_SCH_UCI_FORMAT1A_1B;
+ TRC2(rgSCHDhmHqFdbkInd)
+
+ if (cbType == RGSCH_HQ_FDB_IND_CB_TYPE_RA_CB)
+ {
+ raCb = (RgSchRaCb *)(cb);
+ ackNackMode = RGR_TDD_ACKNACK_MODE_BUNDL;
+ hqE = raCb->dlHqE;
+ /* ccpu00139061 Fix */
+ rnti = raCb->tmpCrnti;
+ }
+ else
+ {
+ ue = (RgSchUeCb *)(cb);
+ ackNackMode = ue->dl.ackNackMode;
+ hqE = RG_SCH_CMN_GET_UE_HQE(ue, cellCb);
+ rnti = ue->ueId;
+#ifdef LTEMAC_SPS_AN_MUX
+ isPusch = fdbk->isPusch;
+#endif
+
+#ifdef LTEMAC_SPS
+ if (RGSCH_TIMEINFO_SAME(timeInfo, ue->relPdcchFbkTiming))
+ {
+ hasRelPdcch = TRUE;
+ }
+#endif
+ }
+
+#if ((defined LTEMAC_SPS_AN_MUX) || (defined LTE_ADV))
+ ascIdx = rgSchTddDlAscSetIdxKTbl[cellCb->ulDlCfgIdx][timeInfo.subframe];
+ noFdbks = ascIdx.numFdbkSubfrms;
+#endif
+#ifdef LTEMAC_SPS_AN_MUX
+ /* Calculate the subframe time at which transmissions should have happened to
+ * receive feedback in this subframe */
+ if (ackNackMode == RGR_TDD_ACKNACK_MODE_MULT)
+ {
+ for(idx=0; idx<noFdbks; idx++)
+ {
+ /* ccpu00133109: Removed RGSCHSUBFRMCRNTTIME as it is not giving proper output
+ * if diff is more than 10. Instead using RGSCHDECRFRMCRNTTIME() as it is
+ * serving the purpose */
+ RGSCHDECRFRMCRNTTIME(timeInfo,schdSfTime[idx],ascIdx.subfrmNum[idx]);
+ }
+ }
+#endif
+
+ rgSCHDhmHqProcByFdbkTime(hqE, timeInfo, &isMsg4, hqPrcs, numTb, \
+ tbStrtIdx, &hqCnt,hqE->cell);
+ /* Fetch the harqProc from the inUse list */
+#ifdef LTEMAC_SPS
+ if ((FALSE == hasRelPdcch) && (hqCnt == 0))
+#endif
+ if(hqCnt == 0)
+ {
+ err->errType = RGSCHERR_DHM_FDBK_IND;
+ err->errCause = RGSCHERR_DHM_FDBK_IND_INVALID_CB;
+ RETVALUE(RFAILED);
+ }
+
+ /* ccpu00147469 : This code is moved below as here this code always try to
+ * get the primary cell aninfo. it is due to hqE->cell->cellId as it is
+ * cellId of PCEll
+ */
+
+ if(fdbk->hqFdbkMode == TFU_ACK_NACK_SPECIAL_BUNDLING)
+ {
+ rgSCHDhmPrcSplBundlFdbk(cellCb, fdbk, hqCnt);
+ }
+
+#ifdef TFU_TDD
+#endif
+
+#ifdef LTEMAC_SPS_AN_MUX
+ /* Check if feedback came on configured UL SPS grant in Muxing mode */
+ if((ackNackMode == RGR_TDD_ACKNACK_MODE_MULT) &&
+ (isPusch == TRUE) )
+ {
+ hIdx = 0;
+ /* Pick the valid feedbacks out of M feedbacks */
+ for(idx=0; idx<noFdbks; idx++)
+ {
+ /* Skip the feedback if hqProc[idx] did not transmit in schdSf[idx]
+ * and no release pdcch is sent in prevTime */
+ /* TODO: SPS_TDD: Check this while testing */
+ if ((hqPrcs[hIdx] && !RGSCH_TIMEINFO_SAME(hqPrcs[hIdx]->\
+ tbInfo[(S16)(tbStrtIdx[hIdx])].timingInfo,\
+ schdSfTime[idx])) &&
+ !RGSCH_TIMEINFO_SAME(ue->relPdcchTxTime, schdSfTime[idx]))
+ {
+ /* Discard the feedback which is corresponding to a subframe in
+ * which no DL transmission took place */
+ tmpIdx = idx+1;
+ while(tmpIdx < noFdbks)
+ {
+ fdbk->isAck[tmpIdx-1] = fdbk->isAck[tmpIdx];
+ fdbk->isAck[tmpIdx-1] = fdbk->isAck[tmpIdx];
+ tmpIdx++;
+ }
+ rcvCnt--;
+ ++hIdx;
+ }
+ } /* end of for loop */
+ } /* end of configured UL SPS grant check */
+#endif
+#ifdef CA_DBG
+ {
+ if(ue)
+ {
+ gHqFdbkCount++;
+ }
+ }
+
+#endif
+
+ for(idx=0;idx < hqCnt; idx++)
+ {
+ /* Fix for CR ccpu00147469: Get the anInfo for each harq proc */
+ if(ue)
+ {
+#ifdef LTE_ADV
+ U8 servCellIdx = rgSchUtlGetServCellIdx(hqPrcs[idx]->hqE->cell->instIdx,
+ hqPrcs[idx]->hqE->cell->cellId,ue);
+
+ if(ue->cellInfo[servCellIdx]->sCellState != RG_SCH_SCELL_ACTIVE)
+ {
+ continue;
+ }
+ anInfo = rgSCHUtlGetUeANFdbkInfo(ue, &timeInfo,servCellIdx);
+#else
+ anInfo = rgSCHUtlGetUeANFdbkInfo(ue, &timeInfo,RGSCH_PCELL_INDEX);
+#endif
+ if(anInfo == NULLP)
+ {
+ RGSCHDBGINFO(cellCb->instIdx,(rgSchPBuf(cellCb->instIdx),
+ "Ack Rcvd. No Ack/Nack feedback available \n"));
+ RETVALUE(RFAILED);
+ }
+ }
+
+ sCell = hqPrcs[idx]->hqE->cell;
+ rlsHqBufs = &(sCell->rlsHqArr[sCell->crntHqIdx]);
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs = 0;
+ for (tbCnt = tbStrtIdx[idx]; (tbCnt-tbStrtIdx[idx]) < numTb[idx]; tbCnt++)
+ {
+ /* Fix : syed MultiUe per TTI crash in TA List. */
+ hqRls = FALSE;
+ maxHqRetxReached = FALSE;
+ /* Remove the harq process from the subframe */
+ sf = rgSCHUtlSubFrmGet(cellCb, hqPrcs[idx]->tbInfo[tbCnt].timingInfo);
+
+ if(NULLP != ue)
+ {
+ uciFrmtTyp = ue->dl.dlSfHqInfo[cellCb->cellId][sf->dlIdx].uciFrmtTyp;
+ }
+
+ if(uciFrmtTyp != RG_SCH_UCI_FORMAT1B_CS)
+ {
+ if((fdbk->hqFdbkMode != TFU_ACK_NACK_SPECIAL_BUNDLING)&&
+ (RGR_TDD_ACKNACK_MODE_MULT == ackNackMode))
+ {
+ isAck = fdbk->isAck[hqPrcs[idx]->tbInfo[tbCnt].m];
+ }
+ else
+ {
+ /* TODO: review for TM4 and CA interaction */
+ if((TRUE == hqPrcs[idx]->cwSwpEnabled) && (1 < numTb[idx]))
+ {
+ isAck = fdbk->isAck[!tbCnt];
+ }
+ else
+ {
+ isAck = fdbk->isAck[tbCnt];
+ }
+ }
+ }
+#ifdef LTE_ADV
+ else
+ {
+ if(1 == noFdbks)
+ {/* M == 1 case */
+ rgSchGetHqFdbkPosForM1(ue, hqPrcs[idx], &isAck, fdbk, tbCnt, anInfo);
+ }
+ else
+ {
+ rgSchGetHqFdbkPosForM234(ue, hqPrcs[idx], &isAck, fdbk, tbCnt, anInfo, noFdbks, timeInfo);
+ }
+ }
+#endif
+
+#ifdef BRDCM
+ /* revanth tweakin AN PUSCH to ACK always */
+ if (hqPrcs[idx]->isPuschFdbk)
+ {
+ isAck = 1;
+ }
+#endif
+
+ hqPrcs[idx]->tbInfo[tbCnt].isAckNackDtx = isAck;
+ if(cellCb->ulDlCfgIdx != 5)
+ {
+ rgSCHUtlGetNxtDlSfInfo(hqPrcs[idx]->tbInfo[tbCnt].timingInfo,\
+ cellCb, sf, &nxtDlsf, &nxtfrm);
+ }
+ /* Keep a tab on how many ACKs or NACKs we have received */
+ if (isAck == TFU_HQFDB_ACK)
+ {
+ hqPrcs[idx]->tbInfo[tbCnt].ackCount += 1; /* Ack counter */
+ rgHqRvStats[tbCnt][hqPrcs[idx]->tbInfo[tbCnt].dlGrnt.rv][0]++;
+#ifdef TENB_STATS
+ sCell->tenbStats->sch.dlAckNack[tbCnt]\
+ [hqPrcs[idx]->tbInfo[tbCnt].dlGrnt.rv]++;
+#endif
+ /* Do not update the Ul Trans Time in case of raCb */
+ if (ue)
+ {
+ rgSCHUtlHdlUlTransInd(cellCb, ue, timeInfo);
+#ifdef TENB_STATS
+ ue->tenbStats->stats.nonPersistent.sch[RG_SCH_CELLINDEX(sCell)].dlAckNackCnt[tbCnt] ++;
+#endif
+ }
+ }
+ else if (isAck == TFU_HQFDB_NACK)
+ {
+ hqPrcs[idx]->tbInfo[tbCnt].nackCount += 1; /* Nack Counter */
+ rgHqRvStats[tbCnt][hqPrcs[idx]->tbInfo[tbCnt].dlGrnt.rv][1]++;
+#ifdef TENB_STATS
+ sCell->tenbStats->sch.dlNack[tbCnt]\
+ [hqPrcs[idx]->tbInfo[tbCnt].dlGrnt.rv]++;
+ sCell->tenbStats->sch.dlAckNack[tbCnt]\
+ [hqPrcs[idx]->tbInfo[tbCnt].dlGrnt.rv]++;
+#endif
+ /* Do not update the Ul Trans Time in case of raCb */
+ if (ue)
+ {
+ rgSCHUtlHdlUlTransInd(cellCb, ue, timeInfo);
+#ifdef TENB_STATS
+ ue->tenbStats->stats.nonPersistent.sch[RG_SCH_CELLINDEX(sCell)].dlNackCnt[tbCnt] ++;
+ ue->tenbStats->stats.nonPersistent.sch[RG_SCH_CELLINDEX(sCell)].dlAckNackCnt[tbCnt] ++;
+#endif
+ }
+#ifdef LTE_L2_MEAS
+ if(hqPrcs[idx]->tbInfo[tbCnt].txCntr == 1)
+ {
+ cellCb->dlUlTbCnt.tbTransDlFaulty++;
+ }
+#endif
+ }
+ else
+ {
+ hqPrcs[idx]->tbInfo[tbCnt].dtxCount += 1; /* DTX Counter*/
+#ifdef TENB_STATS
+ sCell->tenbStats->sch.dlDtx[tbCnt]\
+ [hqPrcs[idx]->tbInfo[tbCnt].dlGrnt.rv]++;
+ if (ue)
+ {
+ ue->tenbStats->stats.nonPersistent.sch[RG_SCH_CELLINDEX(sCell)].dlDtxCnt[tbCnt] ++;
+ }
+#endif
+#ifdef LTE_L2_MEAS
+ if(hqPrcs[idx]->tbInfo[tbCnt].txCntr == 1)
+ {
+ cellCb->dlUlTbCnt.tbTransDlFaulty++;
+ }
+#endif
+ }
+#ifdef CA_DBG
+ if(ue && RG_SCH_IS_CELL_SEC(ue,hqPrcs[idx]->hqE->cell))
+ {
+ if(isAck == TFU_HQFDB_ACK)
+ {
+ gSCellTb1AckCount++;
+ gSCellTb2AckCount++;
+ }else if(isAck == TFU_HQFDB_NACK)
+ {
+ gSCellTb1NackCount++;
+ gSCellTb2NackCount++;
+ }else
+ {
+ gSCellTb1DtxCount++;
+ gSCellTb2DtxCount++;
+ }
+ }
+ else
+ {
+ if(isAck == TFU_HQFDB_ACK)
+ {
+ gPCellTb1AckCount++;
+ gPCellTb2AckCount++;
+ }else if(isAck == TFU_HQFDB_NACK)
+ {
+ gPCellTb1NackCount++;
+ gPCellTb2NackCount++;
+ }else
+ {
+ gPCellTb1DtxCount++;
+ gPCellTb2DtxCount++;
+ }
+ }
+#endif
+ /* Check if this is repeating UE */
+ if (hqPrcs[idx]->tbInfo[tbCnt].fbkRepCntr != 0)
+ {
+ rgSCHUtlDlHqPTbRmvFrmTx(sf, hqPrcs[idx], tbCnt, TRUE);
+ /* Check if last repetition */
+ if (--hqPrcs[idx]->tbInfo[tbCnt].fbkRepCntr)
+ {
+ RGSCH_NULL_CHECK(cellCb->instIdx, nxtDlsf);
+ /* Update feedback time for this hqP TB so that
+ * next subframe its picked up */
+ RGSCH_UPD_HQAN_FDBKTIME(&hqPrcs[idx]->tbInfo[tbCnt],\
+ nxtDlsf, nxtfrm);
+ RGSCH_NULL_CHECK(cellCb->instIdx, anInfo);
+ RGSCH_UPD_ANINFO_WITH_HQ(anInfo, &hqPrcs[idx]->tbInfo[tbCnt]);
+ anUpd = TRUE;
+ continue;
+ }
+ /* For a repeating UE take the decision here */
+ /* For a repeating UE take the decision here */
+ if (((hqPrcs[idx]->tbInfo[tbCnt].ackCount) > (hqPrcs[idx]->tbInfo[tbCnt].nackCount)) &&
+ ((hqPrcs[idx]->tbInfo[tbCnt].ackCount) > (hqPrcs[idx]->tbInfo[tbCnt].dtxCount)))
+ {
+ isAck = TFU_HQFDB_ACK;
+ }
+ else if (((hqPrcs[idx]->tbInfo[tbCnt].dtxCount) > (hqPrcs[idx]->tbInfo[tbCnt].nackCount)) &&
+ ((hqPrcs[idx]->tbInfo[tbCnt].dtxCount) > (hqPrcs[idx]->tbInfo[tbCnt].ackCount)))
+ {
+ isAck = TFU_HQFDB_DTX;
+ }
+ else
+ {
+ isAck = TFU_HQFDB_NACK;
+ }
+ hqPrcs[idx]->tbInfo[tbCnt].isAckNackDtx = isAck;
+ }
+ else
+ {
+ rgSCHUtlDlHqPTbRmvFrmTx(sf, hqPrcs[idx], tbCnt, FALSE);
+ }
+#ifdef LTEMAC_SPS
+ if (((isAck == TFU_HQ_NACK) || (isAck == TFU_HQ_ACK)) &&
+ ((hqPrcs[idx]->sch != (RgSchCmnDlHqProc *)NULLP) &&
+ (RG_SCH_CMN_SPS_DL_IS_SPS_TX_HQP(hqPrcs[idx])))
+ )
+ {
+ /* ACK or NACK received for SPS ACTV PDCCH
+ * Hence consider SPS ACTVN PDCCH received successfully */
+ rgSCHUtlDlProcAck(cellCb, hqPrcs[idx]);
+ }
+#endif
+ if(TFU_HQFDB_ACK == isAck)
+ {
+ /* SPS_REVIEW */
+ if (isMsg4 == TRUE)
+ {
+ if (raCb == NULLP)
+ {
+ raCb = rgSCHDbmGetRaCb(cellCb, rnti);
+ }
+ /* Inform Random Access Module regarding the ack received */
+ if (raCb != NULLP)
+ {
+ /*RRC Connection Setup failure issue where RRC connection
+ * setup was not reaching UE due to message 4 HARQ failure */
+#ifdef XEON_SPECIFIC_CHANGES
+ CM_LOG_DEBUG(CM_LOG_ID_SCH, "Msg4 Harq SUCCESS for UE(%d)\n", rnti);
+#endif
+ rgSCHRamMsg4Done(cellCb, raCb);
+ }
+ }
+ else /*ccpu00114124- HARQ Release for Msg4 */
+ {
+#ifdef DL_LA
+ /*Update feedback history for every Tx/Retx */
+ rgSCHDhmUpdateAckNackHistory(sCell, ue, isAck, tbCnt);
+#endif
+ RGSCH_NULL_CHECK(cellCb->instIdx, ue);
+ RG_UPD_ACQI_TRIG_WT(ue, sCell, isAck);
+#ifdef LTE_ADV
+ /* Store activation CE presence as it is required later to start
+ *activation delay timer */
+ sCellActCePres = hqPrcs[idx]->tbInfo[tbCnt].schdSCellActCe.pres;
+#endif
+ rgSCHDhmRlsHqpTb(hqPrcs[idx], tbCnt, TRUE);
+ }
+ hqRls = TRUE;
+ }
+ else
+ {
+ /* If this Msg4 DTX, there will be
+ * no DlHqProc as it has its own HarqProc */
+ /* SPS_REVIEW */
+ {
+ rgSCHDhmHqTbTrnsFail(cellCb, hqPrcs[idx], tbCnt, &hqRls);
+ maxHqRetxReached = hqRls;
+#ifdef DL_LA
+ if ((isMsg4 == FALSE))
+ {
+ /*Update feedback history for every Tx/Retx */
+ rgSCHDhmUpdateAckNackHistory(sCell, ue, isAck, tbCnt);
+ }
+#endif
+ if (isMsg4 == FALSE)
+ {
+ RGSCH_NULL_CHECK(cellCb->instIdx, ue);
+ RG_UPD_ACQI_TRIG_WT(ue, sCell, isAck);
+ }
+ }
+ }
+
+ if(TRUE == hqRls)
+ {
+ /* MS_WORKAROUND: to increase Harq Fail Counter .
+ The status field is required for tracking the number of harq faliures at MAC*/
+ if (isAck)
+ {
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].status[\
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs] = TRUE;
+ }
+ else
+ {
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].status[\
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs] = FALSE;
+ }
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].tbId[\
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs] = tbCnt + 1;
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs++;
+ }
+
+ /* Handle the TA */
+ if (hqPrcs[idx]->tbInfo[tbCnt].taSnt == TRUE)
+ {
+ rgSCHDhmFdbkIndHndlTa(hqPrcs[idx], tbCnt, isAck, maxHqRetxReached);
+ }
+#ifdef LTE_ADV
+ /* Handle Scell activation */
+ if (TRUE == sCellActCePres)
+ {
+ /* Primary Cellcb needs to be retrived
+ * if the feedback is coming on pusch of
+ * sec cell. THis needs to be considered
+ * while UL_CA*/
+ rgSCHSCellHndlFdbkInd(hqPrcs[idx], tbCnt, isAck, maxHqRetxReached);
+ }
+#endif
+ }
+ if (hqRls == FALSE)
+ {
+ hqPrcs[idx]->cwSwpEnabled = FALSE;
+ }
+ if(rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs)
+ {
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].rnti = rnti;
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].hqProcId =
+ hqPrcs[idx]->procId;
+ rlsHqBufs->numUes++;
+ }
+#ifdef BRDCM
+ hqPrcs[idx]->isPuschFdbk = 0;
+#endif
+ }
+
+#ifdef LTEMAC_SPS
+ /*it is possible for some TDD configurations (like TDD cfg 5)
+ * to have multiple feedback for 13 subframes before. It is
+ * possible in such a case to have a release sent after data
+ * thus running into a situation where we are receiving feedback
+ * for both data and relese pdcch
+ */
+/*
+ if ( (hqCnt == 0) ||
+ (hasRelPdcch && rcvCnt > hqCnt)
+ )
+ */
+ if (ue && hasRelPdcch)
+ {
+ /* Bool found = FALSE; */
+
+ sf = rgSCHUtlSubFrmGet(cellCb, ue->relPdcchTxTime);
+
+ /*
+ if ( !sf->relPdcch)
+ {
+ found = FALSE;
+ }
+ */
+
+
+#if ((defined LTEMAC_SPS_AN_MUX) || (defined LTE_ADV))
+ if(ackNackMode == RGR_TDD_ACKNACK_MODE_MULT)
+ {
+ CmLteTimingInfo txTime;
+ U8 ulDlCfgIdx = 0;
+ U8 maxFdbks = 0;
+ U8 itr = 0;
+
+ ulDlCfgIdx = cellCb->ulDlCfgIdx;
+
+ maxFdbks = rgSchTddDlAscSetIdxKTbl[ulDlCfgIdx]
+ [timeInfo.subframe].
+ numFdbkSubfrms;
+
+ for(itr=0; itr< maxFdbks; itr++)
+ {
+#ifdef LTE_ADV
+ /* Handling the case of only SPS release pdcch
+ * and no other scheduling in both the serving cells
+ * */
+ if(ue->uciFrmtTyp == RG_SCH_UCI_FORMAT1B_CS)
+ {/* Using the sorted K table */
+ RGSCHDECRFRMCRNTTIME (timeInfo, txTime,
+ rgSchTddDlHqPucchResCalTbl[ulDlCfgIdx][timeInfo.subframe].subfrmNum[itr]);
+ }else
+#endif
+ {
+ RGSCHDECRFRMCRNTTIME (timeInfo, txTime,
+ rgSchTddDlAscSetIdxKTbl[ulDlCfgIdx][timeInfo.subframe].subfrmNum[itr]);
+ }
+
+ if (RGSCH_TIMEINFO_SAME (txTime, ue->relPdcchTxTime))
+ {
+#ifdef LTE_ADV
+ if((ue->uciFrmtTyp == RG_SCH_UCI_FORMAT1B_CS)&&
+ (maxFdbks == 1))
+ {/* M == 1 case */
+ if(rgSCHUtlGetMaxTbSupp(ue->mimoInfo.txMode) > 1)
+ {
+ isAck = fdbk->isAck[0];
+ }else
+ {
+ isAck = fdbk->isAck[2];
+ }
+ }
+ else
+ /* M > 1 same below logic apply.
+ If SPS occasion and rel pdcch is present
+ SPS occasion after SPS release cannot
+ happen in a bundle
+ */
+#endif
+ {
+ isAck = fdbk->isAck[itr];
+ }
+
+ rgSCHUtlDlRelPdcchFbk(cellCb, ue, isAck);
+
+ RGSCH_NULL_CHECK(cellCb->instIdx, sf->relPdcch);
+ /* Remove release PDCCH from the subframe */
+ rgSCHUtlPdcchPut(cellCb, &sf->pdcchInfo, sf->relPdcch);
+ sf->relPdcch = NULLP;
+ /* found = TRUE; */
+ break;
+ }
+
+ }
+ }
+ else
+#endif
+ {
+ RGSCH_NULL_CHECK(cellCb->instIdx, sf->relPdcch);
+ /* Remove release PDCCH from the subframe */
+ rgSCHUtlPdcchPut(cellCb, &sf->pdcchInfo, sf->relPdcch);
+ sf->relPdcch = NULLP;
+ /* found = TRUE; */
+ rgSCHUtlDlRelPdcchFbk(cellCb, ue, fdbk->isAck[0]);
+ }
+ /*
+ if ( found == FALSE )
+ {
+ RGSCH_NULL_CHECK(cellCb->instIdx, ue);
+ RLOG_ARG3(L_ERROR,DBG_CELLID,cellCb->cellId,"CRNTI:%d"
+ " NO HARQ proc available for feedback:timeInfo:snf %d,subframe %d",
+ ue->ueId,timeInfo.sfn, timeInfo.subframe);
+ err->errType = RGSCHERR_DHM_FDBK_IND;
+ err->errCause = RGSCHERR_DHM_FDBK_IND_INVALID_CB;
+ RETVALUE(RFAILED);
+ }
+ */
+ }/*if(hqCnt==0)*/
+#endif /* LTEMAC_SPS */
+ /* Initialise the Ack/Nack feedback */
+ /* [ccpu00127651] - MOD For Msg4 Harq Proc, anInfo will not be filled while
+ scheduling. So added a condition !isMsg4 to avoid calling the function
+ rgSCHUtlInitUeANFdbkInfo*/
+ if((ue) && (!anUpd) && (!isMsg4))
+ {
+#ifdef LTE_ADV
+ /* TODO:: Initi the anInfo all the serving cells */
+ for(idx = 0; idx <= RG_SCH_MAX_SCELL; idx++)
+ {
+ if(ue->cellInfo[idx])
+ {
+ anInfo = rgSCHUtlGetUeANFdbkInfo(ue, &timeInfo,idx);
+ /* Fix for CR ccpu00147693: If anInfo is there then initialize it
+ * else don't do anything. basically continue for next serving
+ * cell*/
+ if(anInfo)
+ {
+ rgSCHUtlInitUeANFdbkInfo(anInfo);
+ }
+ }
+ }
+#else
+ rgSCHUtlInitUeANFdbkInfo(anInfo);
+#endif
+ }
+
+ RETVALUE(ROK);
+}
+//#endif /* LTEMAC_SPS */
+
+#else /* LTE_TDD */
+/** * @brief Handler for HARQ feedback received for DL transmission.
+ *
+ * @details
+ *
+ * Function : rgSCHDhmPrcFdbkForTb
+ *
+ * Process Hq Prc Fdbk for a TB
+ *
+ * @param[in] RgSchCellCb *cell
+ * @param[in] RgTfuHarqAckIndInfo *fdbk
+ * @param[in] RgSchErrInfo *err
+ * @return S16
+ * -# ROK
+ * -# RFAILED
+ **/
+#ifdef ANSI
+PUBLIC S16 rgSCHDhmPrcFdbkForTb
+(
+RgSchCellCb *cell,
+RgSchUeCb *ue,
+RgSchDlHqProcCb *hqP,
+RgSchDlSf *sf,
+Bool isMsg4,
+U16 rnti,
+U8 tbCnt,
+CmLteTimingInfo timingInfo,
+U8 isAck,
+RgInfRlsHqInfo *rlsHqBufs,
+RgSchErrInfo *err
+)
+#else
+PUBLIC S16 rgSCHDhmPrcFdbkForTb(cell, ue, hqP, sf, isMsg4, rnti, tbCnt, timingInfo, isAck, rlsHqBufs, err)
+RgSchCellCb *cell;
+RgSchUeCb *ue;
+RgSchDlHqProcCb *hqP;
+RgSchDlSf *sf;
+Bool isMsg4;
+U16 rnti;
+U8 tbCnt;
+CmLteTimingInfo timingInfo;
+U8 isAck;
+RgInfRlsHqInfo *rlsHqBufs;
+RgSchErrInfo *err;
+#endif
+{
+#ifdef DEBUGP
+ Inst inst = cell->instIdx;
+#endif
+#ifdef RGSCH_SPS_STATS
+ RgSchCmnDlHqProc *cmnHqDl;
+#endif
+ S16 ret = ROK;
+ RgSchRaCb *raCb = NULLP;
+ Bool hqRls=FALSE;
+ Bool hqFreed =FALSE;
+ Bool maxHqRetxReached = FALSE;
+ RgSchCmnDlUe *ueDl = NULLP;
+ RgSchCellCb *sCell = hqP->hqE->cell;
+#ifdef EMTC_ENABLE
+ RgSchEmtcDlSf *emtcSf;
+ CmLteTimingInfo frm = timingInfo;
+#endif
+
+ TRC2(rgSCHDhmPrcFdbkForTb)
+ if (ue)
+ {
+ ueDl = RG_SCH_CMN_GET_DL_UE(ue,cell);
+ }
+ hqRls = FALSE;
+ /* Fix : syed MultiUe per TTI crash in TA List. */
+ maxHqRetxReached = FALSE;
+
+ /* Fix : syed Consider CW to TB mapping for Hq Feedback.
+ * TODO: Need to enhance this in case of TM4 testing,
+ * when cwSwap flag is considered. */
+
+ RGSCHDBGINFO(inst, (rgSchPBuf(inst), "rgSCHDhmHqFdbkInd():\
+ tbCnt=%d , isAck=%d",tbCnt,isAck));
+ if (isAck == TFU_HQFDB_ACK)
+ {
+ hqP->tbInfo[tbCnt].ackCount += 1; /* Ack counter */
+ /*sanjay*/
+ rgHqRvStats[tbCnt][hqP->tbInfo[tbCnt].dlGrnt.rv][0]++;
+ /* Do not update the Ul Trans Time in case of raCb */
+ if (ue)
+ {
+ rgSCHUtlHdlUlTransInd(cell, ue, timingInfo);
+#ifdef TENB_STATS
+ ue->tenbStats->stats.nonPersistent.sch[RG_SCH_CELLINDEX(sCell)].dlAckNackCnt[tbCnt]++;
+#endif
+
+ }
+
+#ifdef TENB_STATS
+ sCell->tenbStats->sch.dlAckNack[tbCnt]\
+ [hqP->tbInfo[tbCnt].dlGrnt.rv]++;
+
+#endif
+
+ }
+ else if (isAck == TFU_HQFDB_NACK)
+ {
+ hqP->tbInfo[tbCnt].nackCount += 1; /* Nack Counter */
+ RGSCHDBGINFONEW(inst, (rgSchPBuf(inst), "<HARQ> HqP[%d:%d] NACKED "
+ "ue(%d)\n", hqP->procId, tbCnt, hqP->hqE->ue->ueId));
+ rgHqRvStats[tbCnt][hqP->tbInfo[tbCnt].dlGrnt.rv][1]++;
+ /* Do not update the Ul Trans Time in case of raCb */
+
+#ifdef TENB_STATS
+ sCell->tenbStats->sch.dlAckNack[tbCnt]\
+ [hqP->tbInfo[tbCnt].dlGrnt.rv]++;
+
+ sCell->tenbStats->sch.dlNack[tbCnt]\
+ [hqP->tbInfo[tbCnt].dlGrnt.rv]++;
+
+
+#endif
+
+ if (ue)
+ {
+ rgSCHUtlHdlUlTransInd(cell, ue, timingInfo);
+#ifdef TENB_STATS
+ ue->tenbStats->stats.nonPersistent.sch[RG_SCH_CELLINDEX(sCell)].dlAckNackCnt[tbCnt]++;
+ ue->tenbStats->stats.nonPersistent.sch[RG_SCH_CELLINDEX(sCell)].dlNackCnt[tbCnt] ++;
+#endif
+ }
+ /* Added Dl TB count for NACKED data*/
+#ifdef LTE_L2_MEAS
+ if(hqP->tbInfo[tbCnt].txCntr == 1)
+ {
+ cell->dlUlTbCnt.tbTransDlFaulty++;
+ }
+#endif
+ }
+ else
+ {
+ RGSCHDBGINFONEW(inst,(rgSchPBuf(inst),"<HARQ> HqP[%d:%d] DTXED UE(%d)\n",
+ hqP->procId, tbCnt,hqP->hqE->ue->ueId));
+ hqP->tbInfo[tbCnt].dtxCount += 1; /* DTX Counter*/
+
+#ifdef TENB_STATS
+ sCell->tenbStats->sch.dlDtx[tbCnt]\
+ [hqP->tbInfo[tbCnt].dlGrnt.rv]++;
+ if (ue)
+ {
+ ue->tenbStats->stats.nonPersistent.sch[RG_SCH_CELLINDEX(sCell)].dlDtxCnt[tbCnt]++;
+ }
+#endif
+
+
+ /* Added Dl TB count for DTXED data*/
+#ifdef LTE_L2_MEAS
+ if(hqP->tbInfo[tbCnt].txCntr == 1)
+ {
+ cell->dlUlTbCnt.tbTransDlFaulty++;
+ }
+#endif
+ }
+
+ /* Check if this is repeating UE */
+ if (hqP->tbInfo[tbCnt].fbkRepCntr != 0)
+ {
+ if((rgSCHDhmProcHqFdbkAckNackRep(hqP,sf,tbCnt,&isAck)) != ROK)
+ {
+ RETVALUE(ret);
+ }
+ }
+ else
+ {
+ /* For a Normal UE take the decision here */
+ hqP->tbInfo[tbCnt].isAckNackDtx = isAck;
+ {
+ rgSCHUtlDlHqPTbRmvFrmTx(sf, hqP, tbCnt, FALSE);
+ }
+ }
+ /* Process either the ACK received or max retries have occurred */
+ /* Assuming for Repetition that 2 ACKs and 2 NACKs make an NACK */
+ if (TFU_HQFDB_ACK == isAck)
+ {
+ if (isMsg4 == TRUE)
+ {
+ /* SR_RACH_STATS : MSG4 ACK*/
+ rgNumMsg4Ack++;
+
+ if (raCb == NULLP)
+ {
+ raCb = rgSCHDbmGetRaCb(cell, rnti);
+ }
+ RGSCHDBGINFO(cell->instIdx,
+ (rgSchPBuf(cell->instIdx), "Ack Rcvd. FdbkInd for Msg4Done\n"));
+ /* Inform Random Access Module regarding the ack received */
+ if (raCb != NULLP)
+ {
+ /*RRC Connection Setup failure issue where RRC connection
+ * setup was not reaching UE due to message 4 HARQ failure */
+ printf("\nMSG4 Ack ,calling rgSCHRamMsg4Done\n");
+ ret = rgSCHRamMsg4Done(cell, raCb);
+ hqFreed = TRUE;
+ }
+ else
+ {
+ printf("\nraCb is NULLP\n");
+ }
+ }
+ else /*ccpu00114124- HARQ Release for Msg4 */
+ {
+ RGSCH_NULL_CHECK(cell->instIdx, ueDl);
+ /* Push this harq process back to the free queue */
+ ueDl->mimoInfo.cwInfo[tbCnt].ackCnt++;
+#ifdef DL_LA
+ if(hqP->tbInfo[tbCnt].txCntr == 1)
+ {
+ rgSCHDhmUpdateAckNackHistory(sCell, ue, isAck, tbCnt);
+ }
+#endif
+ RGSCH_NULL_CHECK(cell->instIdx, ue);
+ RG_UPD_ACQI_TRIG_WT(ue, sCell,isAck);
+ rgSCHDhmRlsHqpTb(hqP, tbCnt, TRUE);
+ }
+ hqRls = TRUE;
+ }
+ else
+ {
+ {
+ if(!isMsg4)
+ {
+ RGSCH_NULL_CHECK(cell->instIdx, ueDl);
+ ueDl->mimoInfo.cwInfo[tbCnt].nackCnt++;
+#ifdef DL_LA
+ if(hqP->tbInfo[tbCnt].txCntr == 1)
+ {
+ rgSCHDhmUpdateAckNackHistory(sCell, ue, isAck, tbCnt);
+ }
+#endif
+ RGSCH_NULL_CHECK(cell->instIdx, ue);
+ RG_UPD_ACQI_TRIG_WT(ue, sCell, isAck);
+ }
+ else
+ {
+#ifdef XEON_SPECIFIC_CHANGES
+ CM_LOG_DEBUG(CM_LOG_ID_SCH,"Msg4 Harq FAILURE for UE(%d)\n", rnti);
+#endif
+ rgNumMsg4Nack++;
+ }
+ rgSCHDhmHqTbTrnsFail(cell, hqP, tbCnt, &hqRls);
+ maxHqRetxReached = hqRls;
+ }
+ }
+
+ if(hqRls == TRUE)
+ {
+ /* MS_WORKAROUND: to increase Harq Fail Counter .
+ The status field is required for tracking the number of harq faliures at MAC*/
+ if (isAck)
+ {
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].status[\
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs] = TRUE;
+ }
+#ifdef LTE_L2_MEAS
+ else if(maxHqRetxReached)
+ {
+ /* this is to differentiat the NACK with data loss used for UU loss L2 meas */
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].status[\
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs] = 0xFF; /* RGU_NACK_LOSS; */
+ }
+#endif
+ else
+ {
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].status[\
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs] = FALSE;
+ }
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].tbId[\
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs] = tbCnt + 1;
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs++;
+ }
+
+ /* Handle the TA */
+ if (hqFreed == FALSE && hqP->tbInfo[tbCnt].taSnt == TRUE)
+ {
+ rgSCHDhmFdbkIndHndlTa(hqP, tbCnt, isAck, maxHqRetxReached);
+ }
+ RETVALUE(ret);
+} /* rgSCHDhmPrcFdbkForTb */
+/** * @brief Function to decode the position of HarqFb for eachCell.
+ *
+ * @details
+ *
+ * Function : rgSchGetHqFdbkPos
+ *
+ * @param[in] RgSchCellCb *cell,
+ * @param[in] RgSchUeCb *ue,
+ * @param[in] RgSchDlHqProcCb *hqP,
+ * @param[in] RgrSchFrmt1b3TypEnum uciFrmtTyp,
+ * @param[in] Bool *isAck,
+ * @param[in] RgTfuHqInfo *fdbk,
+ * @return RETVOID
+ **/
+#ifdef ANSI
+PUBLIC Void rgSchGetHqFdbkPos
+(
+ RgSchCellCb *cell,
+ RgSchUeCb *ue,
+ RgSchDlHqProcCb *hqP,
+ RgrSchFrmt1b3TypEnum uciFrmtTyp,
+ U8 *isAck,
+ RgTfuHqInfo *fdbk
+ )
+#else
+PUBLIC Void rgSchGetHqFdbkPos(cell,ue,hqP,uciFrmtTyp,isAck,fdbk)
+ RgSchCellCb *cell;
+ RgSchUeCb *ue;
+ RgSchDlHqProcCb *hqP;
+ RgrSchFrmt1b3TypEnum uciFrmtTyp;
+ U8 *isAck;
+ RgTfuHqInfo *fdbk;
+#endif
+{
+ if(uciFrmtTyp != RG_SCH_UCI_FORMAT1B_CS)
+ {
+ isAck[0] = fdbk->isAck[0];
+ isAck[1] = fdbk->isAck[1];
+ RETVOID;
+ }
+#ifdef LTE_ADV
+ /* LAA Making all ack for LAA CELL */
+ //if (hqP->hqE && rgSCHLaaSCellEnabled(hqP->hqE->cell))
+ if (0)
+ {
+ isAck[0] = TRUE;
+ isAck[1] = TRUE;
+ RETVOID;
+ }
+
+ if((ue != NULLP))
+ {
+ /* PUSCH:: Fdbks are in the increasing order
+ * of servCellIdx as per 36.212 section 5.2.26*/
+ switch(ue->f1bCsAVal)
+ {/* A Value */
+ case RG_SCH_A_VAL_2:
+ {
+ if(RG_SCH_IS_CELL_SEC(ue,hqP->hqE->cell))
+ {
+ isAck[0] = fdbk->isAck[1];/*SCell*/
+ isAck[1] = fdbk->isAck[1];/*SCell*/
+ }
+ else
+ {
+ isAck[0] = fdbk->isAck[0];/*PCell*/
+ isAck[1] = fdbk->isAck[0];/*PCell*/
+ }
+ break;
+ }
+ case RG_SCH_A_VAL_3:
+ {
+ if(RG_SCH_IS_CELL_SEC(ue,hqP->hqE->cell))
+ {
+#ifdef LTE_ADV
+ U8 servCellIdx = rgSchUtlGetServCellIdx(hqP->hqE->cell->instIdx,
+ hqP->hqE->cell->cellId,
+ ue);
+
+ if(rgSCHUtlGetMaxTbSupp(ue->cellInfo[servCellIdx]->txMode.txModeEnum) > 1)
+#else
+ if(rgSCHUtlGetMaxTbSupp(ue->cellInfo[RGSCH_PCELL_INDEX]->txMode.txModeEnum) > 1)
+#endif
+ { /* Sec cell is in mimo mode */
+ /* use 0 and 1 for sec in case of pucch
+ * and 1 and 2 in case of PUSCH as the primary cell is in
+ * siso case as A =3 */
+ if(!fdbk->isPusch)
+ {
+ isAck[0] = fdbk->isAck[0];
+ isAck[1] = fdbk->isAck[1];
+ }else
+ {/* PUSCH as per 36.212 serction 5.2.26*/
+ isAck[0] = fdbk->isAck[1];
+ isAck[1] = fdbk->isAck[2];
+ }
+ }else
+ {/* sec cell is in siso */
+ isAck[0] = fdbk->isAck[2];
+ }
+ }else
+ {
+ if(rgSCHUtlGetMaxTbSupp(ue->mimoInfo.txMode) > 1)
+ {/* primay cell is in mimo
+ use 0 and 1 */
+ isAck[0] = fdbk->isAck[0];
+ isAck[1] = fdbk->isAck[1];
+ }else
+ {
+ if(!fdbk->isPusch)
+ {
+ isAck[0] = fdbk->isAck[2];
+ }else
+ {/* PUSCH as per 36.212 serction 5.2.26*/
+ isAck[0] = fdbk->isAck[0];
+ }
+ }
+ }
+ break;
+ }
+ case RG_SCH_A_VAL_4:
+ {
+ if(RG_SCH_IS_CELL_SEC(ue,hqP->hqE->cell))
+ {
+ isAck[0] = fdbk->isAck[2];
+ isAck[1] = fdbk->isAck[3];
+#ifdef CA_DBG
+ {
+ if(isAck[0] == TFU_HQFDB_ACK)
+ {
+ gSCellTb1AckCount++;
+ }else if(isAck[0] == TFU_HQFDB_NACK)
+ {
+ gSCellTb1NackCount++;
+ }else
+ {
+ gSCellTb1DtxCount++;
+ }
+
+ if(isAck[1] == TFU_HQFDB_ACK)
+ {
+ gSCellTb2AckCount++;
+ }else if(isAck[1] == TFU_HQFDB_NACK)
+ {
+ gSCellTb2NackCount++;
+ }else
+ {
+ gSCellTb2DtxCount++;
+ }
+
+ }
+#endif
+ }
+ else
+ {
+ isAck[0] = fdbk->isAck[0];
+ isAck[1] = fdbk->isAck[1];
+#ifdef CA_DBG
+ {
+ if(isAck[0] == TFU_HQFDB_ACK)
+ {
+ gPCellTb1AckCount++;
+ }else if(isAck[0] == TFU_HQFDB_NACK)
+ {
+ gPCellTb1NackCount++;
+ }else
+ {
+ gPCellTb1DtxCount++;
+ }
+
+ if(isAck[1] == TFU_HQFDB_ACK)
+ {
+ gPCellTb2AckCount++;
+ }else if(isAck[1] == TFU_HQFDB_NACK)
+ {
+ gPCellTb2NackCount++;
+ }else
+ {
+ gPCellTb2DtxCount++;
+ }
+
+ }
+#endif
+
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+#endif
+ RETVOID;
+}/* End of rgSchGetHqFdbkPos */
+#ifdef LTE_ADV
+#ifdef ANSI
+PUBLIC Void rgSchGetHqFdbkPosFormat3
+(
+ RgSchDlHqProcCb *hqP,
+ U8 *isAck,
+ TfuHqFdbk *fdbk
+ )
+#else
+PUBLIC Void rgSchGetHqFdbkPosFormat3(hqP,isAck,fdbk)
+ RgSchDlHqProcCb *hqP;
+ U8 *isAck;
+ TfuHqFdbk *fdbk;
+#endif
+{
+ U8 cellIdx = RG_SCH_CMN_GET_CELL_IDX_FROM_HQP(hqP);
+ isAck[0] = (U8)fdbk[cellIdx];
+ isAck[1] = (U8)fdbk[cellIdx + 1];
+}
+#endif
+/** * @brief Handler for HARQ feedback received for DL transmission.
+ *
+ * @details
+ *
+ * Function : rgSCHDhm5gtfHqFdbkInd
+ *
+ * This function shall act on the feedback received from TOM for DL
+ * transmission. If the feedback for msg4 is final (after max transmissions
+ * or ACK) inform RAM that Msg4 transmission is done.
+ *
+ *
+ * @param[in] Void *cb
+ * @param[in] U8 cbType
+ * @param[in] RgSchCellCb *cell
+ * @param[in] RgTfuHarqAckIndInfo *fdbk
+ * @param[in] RgInfRlsHqInfo *rlsHqBufs
+ * @param[in] RgSchErrInfo *err
+ * @return S16
+ * -# ROK
+ * -# RFAILED
+ **/
+#ifdef ANSI
+PUBLIC S16 rgSCHDhm5gtfHqFdbkInd
+(
+RgSchUeCb *ue,
+RgSchCellCb *cell,
+CmLteTimingInfo timingInfo,
+TfuHqFdbk fdbk,
+RgSchErrInfo *err
+)
+#else
+PUBLIC S16 rgSCHDhm5gtfHqFdbkInd(ue, cell, timingInfo, fdbk, err)
+RgSchUeCb *ue;
+RgSchCellCb *cell;
+CmLteTimingInfo timingInfo;
+TfuHqFdbk fdbk;
+RgSchErrInfo *err;
+#endif
+{
+ RgSchDlHqProcCb *hqP = NULLP;
+ CmLList *node = NULLP;
+ CmLListCp *lnk;
+ S16 ret = ROK;
+ RgSchDlSf *sf;
+ Bool isMsg4 = FALSE;
+ U16 rnti=0;
+ U16 procId=0;
+ U8 hqPCount = 0;
+ RgInfRlsHqInfo *rlsHqBufs = NULLP;
+
+ TRC2(rgSCHDhm5gtfHqFdbkInd)
+
+ RGSCHDECRFRMCRNTTIME(timingInfo, timingInfo, 4);
+
+ sf = rgSCHUtlSubFrmGet(cell, timingInfo);
+
+ lnk = &ue->dl.dlSfHqInfo[cell->cellId][sf->dlIdx].hqPLst;
+ node = lnk->first;
+ hqPCount = lnk->count;
+ rnti = ue->ueId;
+
+ while (hqPCount)
+ {
+ hqP = (RgSchDlHqProcCb *)node->node;
+ node = node->next;
+ rlsHqBufs = &(hqP->hqE->cell->rlsHqArr[hqP->hqE->cell->crntHqIdx]);
+ procId = hqP->procId;
+
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs = 0;
+
+ if (HQ_TB_WAITING == hqP->tbInfo[0].state)
+ {
+ rgSCHDhmPrcFdbkForTb(cell, ue, hqP, sf, isMsg4, rnti, 0,
+ timingInfo, fdbk, rlsHqBufs, err);
+ }
+ if(rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs)
+ {
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].rnti = rnti;
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].hqProcId =
+ (U8)procId;
+ rlsHqBufs->numUes++;
+ }
+ hqPCount--;
+ }
+
+ RETVALUE(ret);
+} /* rgSCHDhm5gtfHqFdbkInd */
+
+/** * @brief Handler for HARQ feedback received for DL transmission.
+ *
+ * @details
+ *
+ * Function : rgSCHDhmHqFdbkInd
+ *
+ * This function shall act on the feedback received from TOM for DL
+ * transmission. If the feedback for msg4 is final (after max transmissions
+ * or ACK) inform RAM that Msg4 transmission is done.
+ *
+ *
+ * @param[in] Void *cb
+ * @param[in] U8 cbType
+ * @param[in] RgSchCellCb *cell
+ * @param[in] RgTfuHarqAckIndInfo *fdbk
+ * @param[in] RgInfRlsHqInfo *rlsHqBufs
+ * @param[in] RgSchErrInfo *err
+ * @return S16
+ * -# ROK
+ * -# RFAILED
+ **/
+#ifdef ANSI
+PUBLIC S16 rgSCHDhmHqFdbkInd
+(
+Void *cb,
+U8 cbType,
+RgSchCellCb *cell,
+CmLteTimingInfo timingInfo,
+RgTfuHqInfo *fdbk,
+RgInfRlsHqInfo *rlsHqBufs,
+RgSchErrInfo *err
+)
+#else
+PUBLIC S16 rgSCHDhmHqFdbkInd(cb, cbType, cell, timingInfo, fdbk, rlsHqBufs, err)
+Void *cb;
+U8 cbType;
+RgSchCellCb *cell;
+CmLteTimingInfo timingInfo;
+RgTfuHqInfo *fdbk;
+RgInfRlsHqInfo *rlsHqBufs;
+RgSchErrInfo *err;
+#endif
+{
+ RgSchDlHqTbCb *tbCb;
+ RgSchDlHqEnt *hqE = NULLP;
+ RgSchDlHqProcCb *hqP = NULLP;
+ CmLList *node = NULLP;
+ CmLListCp *lnk;
+ /* Create and Initialize Ue it so that Its not Deferenced Unnecessarily */
+ RgSchUeCb *ue = NULLP;
+
+ S16 ret = ROK;
+ RgSchDlSf *sf;
+ Bool isMsg4 = FALSE;
+ RgSchRaCb *raCb = NULLP;
+ U16 rnti=0;
+ /* Added Insure Fixes Of UR.Initialized procId */
+ U16 procId=0;
+ /* DTX Change: Bool is converted into U8*/
+ U8 isAck[2]={0}; /*Changed to Array of 2*/
+ U8 tbCnt;
+ U8 hqPCount = 0;
+
+#ifdef LTEMAC_SPS
+ CmLteTimingInfo fdbkRcptTime = timingInfo;
+#ifdef RGSCH_SPS_STATS
+ RgSchCmnDlHqProc *cmnHqDl;
+#endif
+#endif
+#ifdef LTE_ADV
+ TfuHqFdbk format3Ack[CM_LTE_MAX_CELLS *2] = {0};
+#endif
+ RgrSchFrmt1b3TypEnum uciFrmtTyp = RG_SCH_UCI_FORMAT1A_1B;
+
+ TRC2(rgSCHDhmHqFdbkInd)
+
+ /* Get the subframe associated with the feedback */
+ /* ccpu00133109: Removed RGSCHSUBFRMCRNTTIME as it is not giving proper output
+ * if diff is more than 10. Instead using RGSCHDECRFRMCRNTTIME() as it is
+ * serving the purpose */
+ RGSCHDECRFRMCRNTTIME(timingInfo, timingInfo, 4);
+
+ sf = rgSCHUtlSubFrmGet(cell, timingInfo);
+ if (cbType == RGSCH_HQ_FDB_IND_CB_TYPE_RA_CB)
+ {
+ raCb = (RgSchRaCb *)(cb);
+ hqE = raCb->dlHqE;
+ hqP = rgSCHDhmHqProcByTime(hqE, timingInfo, &isMsg4,\
+ sf);
+ if(hqP)
+ {
+ hqPCount = 1;
+ }
+ rnti = raCb->tmpCrnti;
+ }
+ else
+ {
+ ue = (RgSchUeCb *)(cb);
+ hqE = RG_SCH_CMN_GET_UE_HQE(ue, cell);
+ {
+ lnk = &ue->dl.dlSfHqInfo[cell->cellId][sf->dlIdx].hqPLst;
+ }
+ node = lnk->first;
+ hqPCount = lnk->count;
+ rnti = ue->ueId;
+#ifdef LTE_ADV
+ uciFrmtTyp = ue->dl.dlSfHqInfo[cell->cellId][sf->dlIdx].uciFrmtTyp;
+#endif
+ }
+ /*
+ TO ADD STATS
+ from Harq Proc get ueCb = hqP->hqEnt->ueCb
+ from ueCb get cmnUecb = (RgSchCmnUe *)ueCb->sch;
+ from ueCb get dlUe = (RgSchCmnDlUe)cmnUeCb->dl
+ from get cmInfo "RgSchCmnDlUeCwInfo" dlUe->mimoInfo->cwInfo[0]
+ from get CQI from cmInfo->cqi
+ from cmInfo get iTbs cmInfo->iTbs[0]
+ call RG_SCH_CMN_DL_TBS_TO_MCS to map iTbs=>MCS
+ Update stats in cellCb
+ cellCb->hqFailStats[cmInfo->cqi].mcs = RG_SCH_CMN_DL_TBS_TO_MCS(cmInfo->iTbs[0]);
+ if (fdbk->isAck == TRUE)
+ cellCb->hqFailStats[cmInfo->cqi].numOfNacks += 1;
+ else
+ cellCb->hqFailStats[cmInfo->cqi].numOfAcks += 1;
+ DL Ack/Nack statistics
+ */
+#ifdef MAC_SCH_STATS
+ if (hqE->ue != NULLP)
+ {
+ RgSchUeCb *ueCb = hqE->ue;
+ RgSchCmnUe *cmnUe = (RgSchCmnUe*)ueCb->sch;
+ RgSchCmnDlUe *dlUe = RG_SCH_CMN_GET_DL_UE(ueCb,hqE->cell);/*CA dev*/
+ U8 tbs = dlUe->mimoInfo.cwInfo[0].iTbs[0];
+ static U32 retxCnt = 0;
+
+ if (fdbk->isAck[0] == TFU_HQFDB_ACK)
+ {
+ hqFailStats.dlCqiStat[(dlUe->mimoInfo.cwInfo[0].cqi - 1)].numOfAcks++;
+ }
+ else
+ {
+ ++retxCnt;
+ hqFailStats.dlCqiStat[(dlUe->mimoInfo.cwInfo[0].cqi - 1)].numOfNacks++;
+ }
+ RG_SCH_CMN_DL_TBS_TO_MCS(tbs,
+ (hqFailStats.dlCqiStat[(dlUe->mimoInfo.cwInfo[0].cqi - 1)].mcs));
+ }
+#endif /* MAC_SCH_STATS */
+
+ /* Fetch the harqProc from the inUse list */
+#ifdef LTEMAC_SPS
+ /* Check if the feedback timing matches with ue->relPdcchFbkTiming*/
+ /* Call Common module with the feedback information */
+ if (ue && (ue->relPdcchFbkTiming.sfn != (RGSCH_MAX_SFN + 1)))
+ {
+ if (RGSCH_TIMEINFO_SAME(fdbkRcptTime, ue->relPdcchFbkTiming))
+ {
+ sf = rgSCHUtlSubFrmGet(cell, timingInfo);
+
+#ifdef LTE_ADV
+ if(uciFrmtTyp == RG_SCH_UCI_FORMAT1B_CS)
+ {/* Feedback for SPS Release on PCell
+ If Pcell is in mimo, feedback index will be 0
+ else 2 */
+ if(rgSCHUtlGetMaxTbSupp(ue->mimoInfo.txMode) > 1)
+ {
+ isAck[0] = fdbk->isAck[0];
+ }else
+ {
+ isAck[0] = fdbk->isAck[2];
+ }
+
+ /* Not releasing pdcch here
+ * as it is already done at the time of
+ * reception req */
+ rgSCHUtlDlRelPdcchFbk(cell, ue, isAck[0]);
+ }
+ else
+#endif
+ {
+ if (!sf->relPdcch)
+ {
+ RLOG_ARG3(L_ERROR,DBG_CELLID,cell->cellId,
+ "CRNTI:%d NO HARQ proc available for feedback: TimingInfo: "
+ "sfn %d subframe %d", ue->ueId, timingInfo.sfn,
+ timingInfo.subframe);
+ RETVALUE(RFAILED);
+ }
+
+ isAck[0] = fdbk->isAck[0];
+ /* Note: Since relPdcchFbkTimimg matches with the recieved
+ * feedback, assumed that feedback is for release PDCCH */
+ rgSCHUtlDlRelPdcchFbk(cell, ue, isAck[0]);
+
+ /* Remove release PDCCH from the subframe */
+ rgSCHUtlPdcchPut(cell, &sf->pdcchInfo, sf->relPdcch);
+ sf->relPdcch = NULLP;
+ RETVALUE(ROK);
+ }
+ }
+ }
+#endif /* LTEMAC_SPS */
+
+ /* Remove the harq process from the subframe */
+ sf = rgSCHUtlSubFrmGet(cell, timingInfo);
+ RG_SCH_ADD_TO_CRNT_TIME(timingInfo, timingInfo, 1);
+
+#ifdef CA_DBG
+ {
+ if(ue)
+ {
+ gHqFdbkCount++;
+ }
+ }
+
+#endif
+ while (hqPCount)
+ {
+ if(cbType != RGSCH_HQ_FDB_IND_CB_TYPE_RA_CB)
+ {
+ hqP = (RgSchDlHqProcCb *)node->node;
+ node = node->next;
+ rlsHqBufs = &(hqP->hqE->cell->rlsHqArr[hqP->hqE->cell->crntHqIdx]);
+ }
+ procId = hqP->procId;
+
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs = 0;
+
+ /*Get the position of Ack/Nack from 2 bytes fdbkInfo.
+ * On the basis of f1bCsAVal find the position of iAck or Nack*/
+#ifdef LTE_ADV
+ if (uciFrmtTyp == RG_SCH_UCI_FORMAT3)
+ {
+ rgSchGetHqFdbkPosFormat3(hqP,isAck,format3Ack);
+ }
+ else
+#endif
+ {
+ rgSchGetHqFdbkPos(cell,ue,hqP, uciFrmtTyp, isAck,fdbk);
+ }
+ for (tbCnt = 0; tbCnt < 2; tbCnt++)
+ {
+ if (HQ_TB_WAITING == hqP->tbInfo[tbCnt].state)
+ {
+ rgSCHDhmPrcFdbkForTb(cell, ue, hqP, sf, isMsg4, rnti, tbCnt,
+ timingInfo, isAck[tbCnt], rlsHqBufs, err);
+ }
+ }
+ if(rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs)
+ {
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].rnti = rnti;
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].hqProcId =
+ (U8)procId;
+ rlsHqBufs->numUes++;
+ }
+ hqPCount--;
+ }
+
+ node = sf->ackNakRepQ.first;
+ while (node)
+ {
+ tbCb = (RgSchDlHqTbCb *)(node->node);
+ hqP = tbCb->hqP;
+
+ procId = hqP->procId;
+ rlsHqBufs = &(hqP->hqE->cell->rlsHqArr[hqP->hqE->cell->crntHqIdx]);
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs = 0;
+ if (HQ_TB_WAITING == tbCb->state)
+ {
+ isAck[0] = fdbk->isAck[tbCb->tbIdx];
+ rgSCHDhmPrcFdbkForTb(cell, ue, hqP, sf, isMsg4, rnti, tbCb->tbIdx,
+ timingInfo, isAck[0], rlsHqBufs, err);
+ }
+ hqP->cwSwpEnabled = FALSE;
+ if(rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].numOfTBs)
+ {
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].rnti = rnti;
+ rlsHqBufs->ueHqInfo[rlsHqBufs->numUes].hqProcId =
+ (U8)procId;
+ rlsHqBufs->numUes++;
+ }
+ hqPCount--;
+ node = node->next;
+ }
+
+ RETVALUE(ret);
+} /* rgSCHDhmHqFdbkInd */
+#endif /* LTE_FDD */
+
+
+/**
+ * @brief Handler for Harq related UE configuration.
+ *
+ * @details
+ *
+ * Function : rgSCHDhmRgrUeCfg
+ *
+ * This function shall fetch the harq related information into the
+ * respective ueCb from the UE configuration as provided by the
+ * upper layers.
+ *
+ * @param[in] RgSchCellCb *cell
+ * @param[in] RgSchUeCb *ueCb
+ * @param[in] RgrUeCfg *ueCfg
+ * @param[out] RgSchErrInfo *err
+ * @return S16
+ * -# ROK
+ * -# RFAILED
+ **/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmRgrUeCfg
+(
+RgSchCellCb *cell,
+RgSchUeCb *ueCb,
+RgrUeCfg *ueCfg,
+RgSchErrInfo *err
+)
+#else
+PUBLIC Void rgSCHDhmRgrUeCfg(cell, ueCb, ueCfg, err)
+RgSchCellCb *cell;
+RgSchUeCb *ueCb;
+RgrUeCfg *ueCfg;
+RgSchErrInfo *err;
+#endif
+{
+ TRC2(rgSCHDhmRgrUeCfg)
+
+ UNUSED(err);
+
+ /* Initialize the TA Timer */
+ cmInitTimers(&ueCb->taTmr, 1);
+
+ /* Setting these values irrespective of taTmr value */
+ ueCb->dl.taCb.state = RGSCH_TA_IDLE;
+ /* Corrected default value of TA as per 36.213, 4.2.3 */
+ ueCb->dl.taCb.ta = RGSCH_NO_TA_RQD;
+
+ /*[ccpu00121813]-ADD-Initializing outstanding TA value */
+ ueCb->dl.taCb.outStndngTa = FALSE;
+ ueCb->dl.taCb.outStndngTaval = RGSCH_NO_TA_RQD;
+
+ /* Start TA timer only if cfgd as FINITE value */
+ if (ueCfg->ueTaTmrCfg.pres)
+ {
+ /* Configuring taTmr with 30 deficit, to enable eNodeB sending
+ * TA command before the expiry of TA at UE. Also considering for
+ * possible retx for this TA command */
+ /*[ccpu00121813]-ADD-Added chk if tatmr val > 30 */
+ if(ueCfg->ueTaTmrCfg.taTmr > 30)
+ {
+ ueCb->dl.taCb.cfgTaTmr = ueCfg->ueTaTmrCfg.taTmr - 30;
+ }
+ rgSCHTmrStartTmr (cell, ueCb, RG_SCH_TMR_TA, ueCb->dl.taCb.cfgTaTmr);
+ }
+ RETVOID;
+} /* rgSCHDhmRgrUeCfg */
+
+
+/**
+ * @brief Handler for HARQ related UE Reconfiguration
+ *
+ * @details
+ *
+ * Function : rgSCHDhmRgrCellCfg
+ *
+ * This function shall fetch the HARQ related information into the
+ * respective ueCb from the UE configuration as provided by the
+ * upper layers.
+ *
+ * @param[in] RgSchCellCb *cell
+ * @param[in] RgrCellCfg *cellCfg
+ * @param[out] RgSchErrInfo *err
+ *
+ * @return S16
+ * -# ROK
+ * -# RFAILED
+ **/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmRgrCellCfg
+(
+RgSchCellCb *cell,
+RgrCellCfg *cellCfg,
+RgSchErrInfo *err
+)
+#else
+PUBLIC Void rgSCHDhmRgrCellCfg(cell, cellCfg, err)
+RgSchCellCb *cell;
+RgrCellCfg *cellCfg;
+RgSchErrInfo *err;
+#endif
+{
+ RgSchDlHqEnt *hqE;
+ PTR pUeCb;/* previous UE Control block */
+ PTR nUeCb;/* next UE control block */
+ S16 ret;
+ U8 idx;
+
+ TRC2(rgSCHDhmRgrCellCfg)
+
+ UNUSED(err);
+
+ pUeCb = NULLP;
+
+ cell->dlHqCfg = cellCfg->dlHqCfg;
+ for (;;)
+ {
+ ret = cmHashListGetNext(&(cell->ueLst), pUeCb, &nUeCb);
+ if (ret != ROK)
+ {
+ break;
+ }
+ else
+ {
+ pUeCb = nUeCb;
+ /* Update the DL Harq related information */
+ hqE = RG_SCH_CMN_GET_UE_HQE(((RgSchUeCb*)nUeCb), cell);
+ hqE->maxHqTx = cell->dlHqCfg.maxDlHqTx;
+ }
+ }
+ /* Initializing the list for ueCbs that would have ta */
+ cmLListInit(&cell->taUeLst);
+#ifdef RGR_V1
+ cmLListInit(&cell->ccchSduUeLst);
+ cmLListInit(&cell->contResGrdTmrLst);
+ cmLListInit(&cell->contResTmrLst);
+#ifdef EMTC_ENABLE
+ if(cell->emtcEnable)
+ {
+ rgSCHDhmEmtcRgrCellCfg(cell);
+ }
+#endif
+#endif
+
+ /* Initializing the timer queue */
+ cell->tqCp.nxtEnt = 0;
+ cell->tqCp.tmrLen = RGSCH_UE_TQ_SIZE;
+
+ for (idx = 0; idx < RGSCH_UE_TQ_SIZE; idx++)
+ {
+ cell->tq[idx].first = NULLP;
+ cell->tq[idx].tail = NULLP;
+ }
+ RETVOID;
+} /* rgSCHDhmRgrCellCfg */
+
+/**
+ * @brief Handler for Updating HARQ Information from Cell Reconfiguration
+ *
+ * @details
+ *
+ * Function : rgSCHDhmRgrCellRecfg
+ *
+ * This function shall fetch the HARQ related information into the
+ * respective ueCb from the UE configuration as provided by the
+ * upper layers.
+ *
+ * @param[in] RgSchCellCb *cell
+ * @param[in] RgrCellRecfg *cellRecfg
+ * @param[out] RgSchErrInfo *err
+ *
+ * @return S16
+ * -# ROK
+ * -# RFAILED
+ **/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmRgrCellRecfg
+(
+RgSchCellCb *cell,
+RgrCellRecfg *cellRecfg,
+RgSchErrInfo *err
+)
+#else
+PUBLIC Void rgSCHDhmRgrCellRecfg(cell, cellRecfg, err)
+RgSchCellCb *cell;
+RgrCellRecfg *cellRecfg;
+RgSchErrInfo *err;
+#endif
+{
+ RgSchDlHqEnt *hqE;
+ PTR pUeCb;/* previous UE Control block */
+ PTR nUeCb;/* next UE control block */
+ S16 ret;
+
+ TRC2(rgSCHDhmRgrCellRecfg)
+
+ UNUSED(err);
+
+ pUeCb = NULLP;
+
+ /* Update the cell with recieved configuration */
+ if (cellRecfg->recfgTypes & RGR_CELL_DL_HARQ_RECFG)
+ {
+ cell->dlHqCfg = cellRecfg->dlHqRecfg;
+
+ for (;;)
+ {
+ ret = cmHashListGetNext(&(cell->ueLst), pUeCb, &nUeCb);
+ if (ret != ROK)
+ {
+ break;
+ }
+ else
+ {
+ pUeCb = nUeCb;
+ /* Update the DL Harq related information */
+ hqE = RG_SCH_CMN_GET_UE_HQE(((RgSchUeCb*)nUeCb), cell);
+ hqE->maxHqTx = cell->dlHqCfg.maxDlHqTx;
+ }
+ }
+ }
+ RETVOID;
+} /* rgSCHDhmRgrCellRecfg */
+
+/**
+ * @brief Handler for freeing up the HARQ related information from ueCb
+ *
+ * @details
+ *
+ * Function : rgSCHDhmFreeUe
+ *
+ * This function shall free up the HARQ specific information from ueCb.
+ *
+ * @param[in] RgSchUeCb *ueCb
+ *
+ * @return None.
+ *
+ **/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmFreeUe
+(
+RgSchUeCb *ueCb
+)
+#else
+PUBLIC Void rgSCHDhmFreeUe(ueCb)
+RgSchUeCb *ueCb;
+#endif
+{
+
+ TRC2(rgSCHDhmFreeUe)
+
+ /* If TA Timer is running. Stop it */
+ if (ueCb->taTmr.tmrEvnt != TMR_NONE)
+ {
+ rgSCHTmrStopTmr(ueCb->cell, ueCb->taTmr.tmrEvnt, ueCb);
+ }
+
+ /* ccpu00118357 - ADD - stop the periodic BSR timer so it
+ * doesn't expire after UE is deleted */
+#ifdef RGR_V1
+ if (ueCb->bsrTmr.tmrEvnt != TMR_NONE)
+ {
+ rgSCHTmrStopTmr(ueCb->cell, ueCb->bsrTmr.tmrEvnt, ueCb);
+ }
+#endif /* ifdef RGR_V1*/
+
+
+ if (RG_SCH_CMN_GET_UE_HQE(ueCb, ueCb->cell))
+ {
+ rgSCHDhmDelHqEnt(ueCb->cell, &(RG_SCH_CMN_GET_UE_HQE(ueCb, ueCb->cell)));
+ }
+
+ /* This UE needs to be removed from its entry into cell's taUeLst */
+ /*Fix for ccpu00113622 - Delete Only when taLnk Node exists*/
+ if(ueCb->taLnk.node)
+ {
+ cmLListDelFrm(&(ueCb->cell->taUeLst), &ueCb->taLnk);
+ ueCb->taLnk.node = NULLP;
+ }
+
+ if (ueCb->dlTaLnk.node != NULLP)
+ {
+ /* Fix: syed Need to raise a CR for not calling CMN or specific scheduler
+ * function directly from other modules. APIs should be defined and/or used
+ * instead. Please check for other possible incorrect usage. */
+ rgSCHCmnRmvFrmTaLst(ueCb->cell, ueCb);
+ }
+
+ RETVOID;
+
+} /* rgSCHDhmFreeUe */
+
+/**
+ * @brief Handler for updating the TA.
+ *
+ * @details
+ *
+ * Function : rgSCHDhmUpdTa
+ *
+ * This function shall update the TA received.
+ *
+ * @param[in] RgSchCellCb *cell
+ * @param[in] RgSchUeCb *ueCb
+ * @param[in] U8 ta
+ *
+ * @return None.
+ *
+ **/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmUpdTa
+(
+RgSchCellCb *cell,
+RgSchUeCb *ueCb,
+U8 ta
+)
+#else
+PUBLIC Void rgSCHDhmUpdTa(cell, ueCb, ta)
+RgSchCellCb *cell;
+RgSchUeCb *ueCb;
+U8 ta;
+#endif
+{
+ TRC2(rgSCHDhmUpdTa)
+
+ if (ueCb->dl.taCb.state == RGSCH_TA_IDLE)
+ {
+ ueCb->dl.taCb.state = RGSCH_TA_TOBE_SCHEDULED;
+ ueCb->dl.taCb.numRemSf = 2;
+ rgSCHUtlDlTARpt(cell, ueCb);
+ /* If TA Timer is running. Stop it */
+ if (ueCb->taTmr.tmrEvnt != TMR_NONE)
+ {
+ rgSCHTmrStopTmr(cell, ueCb->taTmr.tmrEvnt, ueCb);
+ }
+
+ /* SR_RACH_STATS : TA MODIFIED */
+ if (ueCb->dl.taCb.ta != ta)
+ {
+ rgNumTAModified++;
+ }
+ ueCb->dl.taCb.ta = ta;
+ }
+ else
+ {
+ /* [ccpu00121813]-ADD-Updating outstanding values
+ * TA which gets transmitted at N gets applied at UE at N+6,once TA
+ * has been scheduled,further TA values get stored in outstndngTaval.
+ * Once TA gets applied at UE or when NACK/DTX is rcvd for maxhqretx times
+ * then schedule the outstanding TA val if present */
+ ueCb->dl.taCb.outStndngTa = TRUE;
+ ueCb->dl.taCb.outStndngTaval = ta;
+ }
+
+ RETVOID;
+} /* rgSCHDhmUpdTa */
+
+ /** @brief This function handles the TA timer expiry.
+ *
+ * @details
+ *
+ * Function: This function handled the TA Expiry.
+ *
+ * Processing steps:
+ * -
+ *
+ *
+ * @param[in] RgSchUeCb *ueCb
+ *
+ * @return Void
+ * -#None.
+ */
+#ifdef ANSI
+PUBLIC Void rgSCHDhmProcTAExp
+(
+ RgSchUeCb *ueCb
+ )
+#else
+PUBLIC Void rgSCHDhmProcTAExp (ueCb)
+ RgSchUeCb *ueCb;
+#endif
+{
+ TRC2(rgSCHDhmProcTAExp);
+
+ /* Ask scheduler to schedule this UE */
+ ueCb->dl.taCb.state = RGSCH_TA_TOBE_SCHEDULED;
+ rgSCHUtlDlTARpt(ueCb->cell, ueCb);
+ RETVOID;
+} /* end of rgSCHDhmProcTAExp */
+
+/* 3.1 MIMO: LC details at TB level rather than Hq Level */
+/**
+ * @brief Handler for Adding scheduled logical channel data information
+ * to harqProc.
+ *
+ * @details
+ *
+ * Function : rgSCHDhmAddLcData
+ *
+ * This function shall add the scheduled logical channel data
+ * information to the HARQ process.
+ *
+ * @param[in] RgSchLchAllocInfo *lchData
+ * @param[in] RgSchDlHqTbCb *tbInfo
+ * @return S16
+ * -# ROK
+ * -# RFAILED
+ **/
+#ifdef ANSI
+PUBLIC S16 rgSCHDhmAddLcData
+(
+Inst inst,
+RgSchLchAllocInfo *lchData,
+RgSchDlHqTbCb *tbInfo
+)
+#else
+PUBLIC S16 rgSCHDhmAddLcData(inst, lchData, tbInfo)
+Inst inst;
+RgSchLchAllocInfo *lchData;
+RgSchDlHqTbCb *tbInfo;
+#endif
+{
+
+ TRC2(rgSCHDhmAddLcData)
+
+ if(tbInfo->numLch >= RGSCH_MAX_NUM_DED_LC)
+ {
+ RETVALUE(RFAILED);
+ }
+
+ tbInfo->lchSchdDataArr[tbInfo->numLch] = *lchData;
+
+ tbInfo->numLch++;
+
+ RETVALUE(ROK);
+
+} /* rgSCHDhmAddLcData */
+
+#ifdef LTE_TDD
+/*
+ * @brief Handler for releaseing the subframe allocation.
+ *
+ * @details
+ *
+ * Function : rgSCHDhmTddRlsSubFrm
+ *
+ * This function shall be invoked to release the DL Sf
+ * allocations for which HARQ feedback time has expired.
+ *
+ * @param[in] RgSchCellCb *cellCb
+ * @param[in] CmLteTimingInfo uciTimingInfo;
+ * @return S16
+ * -# ROK
+ * -# RFAILED
+ **/
+#ifdef ANSI
+PUBLIC S16 rgSCHDhmTddRlsSubFrm
+(
+RgSchCellCb *cellCb,
+CmLteTimingInfo uciTimingInfo
+)
+#else
+PUBLIC S16 rgSCHDhmTddRlsSubFrm(cellCb, uciTimingInfo)
+RgSchCellCb *cellCb;
+CmLteTimingInfo uciTimingInfo;
+#endif
+{
+ CmLteTimingInfo dlSfTime;
+ RgSchTddDlAscSetIdxK ascIdx;
+ U8 noFdbks;
+ U8 i;
+
+ TRC2(rgSCHDhmTddRlsSubFrm)
+
+ ascIdx =
+ rgSchTddDlAscSetIdxKTbl[cellCb->ulDlCfgIdx][uciTimingInfo.subframe];
+ noFdbks = ascIdx.numFdbkSubfrms;
+ for(i=0; i < noFdbks; i++)
+ {
+ /* Get the subframe and sfn for which HARQ Ack/Nack
+ * has to be sent */
+ /* ccpu00132341-MOD- optimized getting DLSF time using macro*/
+ /* ccpu00133109: Removed RGSCHSUBFRMCRNTTIME as it is not giving proper
+ * output if diff is more than 10. Instead using RGSCHDECRFRMCRNTTIME()
+ * as it is serving the purpose */
+ RGSCHDECRFRMCRNTTIME(uciTimingInfo, dlSfTime, ascIdx.subfrmNum[i]);
+ rgSCHUtlDlRlsSubFrm(cellCb, dlSfTime);
+ }
+ RETVALUE(ROK);
+}/* rgSCHDhmTddRlsSubFrm */
+
+#ifdef TFU_TDD
+U32 macDtx = 0;
+#endif
+/**
+ * @brief Handler for Removing the HARQ process from a dlsf.
+ *
+ * @details
+ *
+ * Function : rgSCHDhmRlsDlsfHqProc
+ *
+ * This function shall be invoked for every tti. It goes back to
+ * to the sixth last subframe to check whether it still exists. If
+ * that exists this function traverses through the entire harq
+ * proc list associated and frees up all of them.
+ *
+ * @param[in] RgSchCellCb *cellCb
+ * @param[in] CmLteTimingInfo timingInfo
+ * @return S16
+ * -# ROK
+ * -# RFAILED
+ **/
+#ifdef ANSI
+PUBLIC S16 rgSCHDhmRlsDlsfHqProc
+(
+RgSchCellCb *cellCb,
+CmLteTimingInfo uciTimingInfo
+)
+#else
+PUBLIC S16 rgSCHDhmRlsDlsfHqProc(cellCb, uciTimingInfo)
+RgSchCellCb *cellCb;
+CmLteTimingInfo uciTimingInfo;
+#endif
+{
+ RgSchDlSf *dlSf;
+ CmLteTimingInfo dlSfTime;
+ CmLteTimingInfo nxtfrm = {0,0};
+ RgSchDlHqProcCb *tmpHqProc;
+ RgSchTddDlAscSetIdxK ascIdx;
+ U8 noFdbks;
+ S16 i;
+ RgSchDlSf *nxtDlsf = NULLP;
+ CmLList *node;
+ CmLList *hqPNode;
+ U8 idx;
+ /*ccpu00130018 -MOD -Initiatizing with FALSE*/
+ U8 maxRetx=FALSE;
+ RgSchTddANInfo *anInfo = NULLP;
+ RgSchDlHqTbCb *tbCb;
+ RgSchUeCb *ue = NULLP;
+ TRC2(rgSCHDhmRlsDlsfHqProc)
+
+ ascIdx =
+ rgSchTddDlAscSetIdxKTbl[cellCb->ulDlCfgIdx][uciTimingInfo.subframe];
+ noFdbks = ascIdx.numFdbkSubfrms;
+ for(i=0; i < noFdbks; i++)
+ {
+ /* Get the subframe and sfn for which HARQ Ack/Nack
+ * has to be sent */
+ /* ccpu00132341-MOD- optimized getting DLSF time using macro*/
+ /* ccpu00133109: Removed RGSCHSUBFRMCRNTTIME as it is not giving proper
+ * output if diff is more than 10. Instead using RGSCHDECRFRMCRNTTIME()
+ * as it is serving the purpose */
+ RGSCHDECRFRMCRNTTIME(uciTimingInfo, dlSfTime, ascIdx.subfrmNum[i]);
+
+ dlSf = rgSCHUtlSubFrmGet (cellCb, dlSfTime);
+ if(cellCb->ulDlCfgIdx != 5)
+ {
+ rgSCHUtlGetNxtDlSfInfo(dlSfTime, cellCb, dlSf, &nxtDlsf, &nxtfrm);
+ }
+ /* Subframe is present. Delete all the harq associations from
+ * this subframe.
+ */
+
+ /*Handling for Msg4*/
+ node = dlSf->msg4HqPLst.first;
+ while (node)
+ {
+ tmpHqProc = (RgSchDlHqProcCb *)(node->node);
+ node = node->next;
+ tmpHqProc->cwSwpEnabled = FALSE;
+ if (HQ_TB_WAITING == tmpHqProc->tbInfo[0].state)
+ {
+ tbCb = &tmpHqProc->tbInfo[0];
+
+ /* Fix : syed MultiUe per TTI crash in TA List. */
+ maxRetx = FALSE;
+
+ tbCb->dtxCount++;
+ tbCb->isAckNackDtx = TFU_HQFDB_DTX;
+
+
+ rgSCHUtlDlHqPTbRmvFrmTx(dlSf, tmpHqProc, tbCb->tbIdx, FALSE);
+
+ /* Delete the Harq Association. Release the Harq Process */
+ rgSCHDhmHqTbTrnsFail(cellCb, tmpHqProc, tbCb->tbIdx, &maxRetx);
+
+ if (tbCb->taSnt == TRUE)
+ {
+ /* [ccpu00127148] Correcting the check */
+ if (TRUE == maxRetx)
+ {
+ tbCb->taSnt = FALSE;
+ RGSCH_NULL_CHECK(cellCb->instIdx, ue)
+ ue->dl.taCb.state = RGSCH_TA_IDLE;
+
+ rgSCHUtlReTxTa(cellCb, ue);
+ }
+ }
+ }
+ }
+
+ node = dlSf->ueLst.first;
+ while (node)
+ {
+#ifdef TFU_TDD
+ macDtx++;
+#endif
+ ue = (RgSchUeCb *)(node->node);
+ node = node->next;
+ if (NULLP != ue)
+ {
+ hqPNode = ue->dl.dlSfHqInfo[cellCb->cellId][dlSf->dlIdx].hqPLst.first;
+ while (hqPNode)
+ {
+ tmpHqProc = (RgSchDlHqProcCb *)hqPNode->node;
+ hqPNode = hqPNode->next;
+ for (idx = 0 ;idx < 2; idx++)
+ {
+ if (HQ_TB_WAITING == tmpHqProc->tbInfo[idx].state)
+ {
+ tbCb = &tmpHqProc->tbInfo[idx];
+
+ /* Fix : syed MultiUe per TTI crash in TA List. */
+ maxRetx = FALSE;
+
+ tbCb->dtxCount++;
+ tbCb->isAckNackDtx = TFU_HQFDB_DTX;
+
+
+ /* Update feedback time for this process so that
+ * next subframe its picked up */
+#ifdef LTE_ADV
+ U8 servCellIdx = rgSchUtlGetServCellIdx(
+ tmpHqProc->hqE->cell->instIdx,
+ tmpHqProc->hqE->cell->cellId,
+ ue);
+ anInfo = rgSCHUtlGetUeANFdbkInfo(ue, &tbCb->fdbkTime,servCellIdx);
+#else
+ anInfo = rgSCHUtlGetUeANFdbkInfo(ue, &tbCb->fdbkTime,RGSCH_PCELL_INDEX);
+#endif
+ if(anInfo == NULLP)
+ {
+ RGSCHDBGERR(cellCb->instIdx, (rgSchPBuf(cellCb->instIdx),
+ "Ack/Nack Info is NULL, Processing %dth feedback subframe for DTX"
+ "received on SFN [%d] and SF [%d]\n",i, uciTimingInfo.sfn,
+ uciTimingInfo.subframe));
+ }
+ else if (tbCb->fbkRepCntr == 0)
+ {
+ /* Initialise the Ack/Nack feedback */
+ anInfo->dlDai--;
+ if(!(anInfo->dlDai))
+ {
+ rgSCHUtlInitUeANFdbkInfo(anInfo);
+ }
+ }
+ else
+ {
+ /* Update feedback time for this process so that
+ * * next subframe its picked up */
+ RGSCH_NULL_CHECK(cellCb->instIdx, nxtDlsf);
+ RGSCH_UPD_HQAN_FDBKTIME(tbCb, nxtDlsf, nxtfrm);
+ RGSCH_UPD_ANINFO_WITH_HQ(anInfo, tbCb);
+ rgSCHUtlDlHqPTbRmvFrmTx(dlSf, tmpHqProc, tbCb->tbIdx, TRUE);
+ tbCb->fbkRepCntr--;
+ continue;
+
+ }
+ rgSCHUtlDlHqPTbRmvFrmTx(dlSf, tmpHqProc, tbCb->tbIdx, FALSE);
+ /*ccpu000119494-ADD- for SPS, call SPS specific DTX handler */
+
+ {
+ /* Delete the Harq Association. Release the Harq Process */
+ rgSCHDhmHqTbTrnsFail(cellCb, tmpHqProc, tbCb->tbIdx, &maxRetx);
+ }
+ if (tbCb->taSnt == TRUE)
+ {
+ /* [ccpu00127148] Correcting the check */
+ if (TRUE == maxRetx)
+ {
+ tbCb->taSnt = FALSE;
+ RGSCH_NULL_CHECK(cellCb->instIdx, ue)
+ ue->dl.taCb.state = RGSCH_TA_IDLE;
+
+ rgSCHUtlReTxTa(cellCb, ue);
+
+ RLOG_ARG0(L_DEBUG,DBG_CELLID,cellCb->cellId,
+ "Nack/DTX Rcvd for TA. Max Tries Attempted");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ node = dlSf->ackNakRepQ.first;
+ while (node)
+ {
+ tbCb = (RgSchDlHqTbCb *)(node->node);
+ tmpHqProc = tbCb->hqP;
+ /* [ccpu00121813]-ADD-Fetch ueCb */
+ ue = tmpHqProc->hqE->ue;
+ /* Fix : syed MultiUe per TTI crash in TA List. */
+ maxRetx = FALSE;
+
+ tbCb->dtxCount++;
+#ifdef TENB_STATS
+ tmpHqProc->hqE->cell->tenbStats->sch.dlDtx[tbCb->tbIdx][tbCb->dlGrnt.rv]++;
+ ue->tenbStats->stats.nonPersistent.sch[RG_SCH_CELLINDEX(tmpHqProc->hqE->cell)].dlDtxCnt[tbCb->tbIdx] ++;
+#endif
+
+ node = node->next;
+ /* If This is not the last repetition */
+ if (tbCb->fbkRepCntr > 1)
+ {
+ /* Update feedback time for this process so that
+ * next subframe its picked up */
+#ifdef LTE_ADV
+ U8 servCellIdx = rgSchUtlGetServCellIdx(
+ tmpHqProc->hqE->cell->instIdx,
+ tmpHqProc->hqE->cell->cellId,
+ ue);
+ anInfo = rgSCHUtlGetUeANFdbkInfo(ue, &tbCb->fdbkTime,servCellIdx);
+#else
+ anInfo = rgSCHUtlGetUeANFdbkInfo(ue, &tbCb->fdbkTime,0);
+#endif
+ if(anInfo == NULLP)
+ {
+ RETVALUE(RFAILED);
+ }
+ RGSCH_NULL_CHECK(cellCb->instIdx, nxtDlsf);
+ RGSCH_UPD_HQAN_FDBKTIME(tbCb, nxtDlsf, nxtfrm);
+ RGSCH_UPD_ANINFO_WITH_HQ(anInfo, tbCb);
+ rgSCHUtlDlHqPTbRmvFrmTx(dlSf,tmpHqProc,tbCb->tbIdx, TRUE);
+ tbCb->fbkRepCntr--;
+ continue;
+ }
+ else
+ {
+ rgSCHUtlDlHqPTbRmvFrmTx(dlSf,tmpHqProc,tbCb->tbIdx, TRUE);
+
+ if (((tbCb->nackCount + tbCb->dtxCount) >= tbCb->ackCount))
+ {
+ /*even if one NACK, we consider the feedback
+ * on a whole as NACk */
+ if ( tbCb->nackCount != 0 )
+ {
+ tbCb->isAckNackDtx = TFU_HQFDB_NACK;
+ }
+ else
+ {
+ tbCb->isAckNackDtx = TFU_HQFDB_DTX;
+ }
+
+ {
+ /* Delete the Harq Association. Release the Harq Process */
+ rgSCHDhmHqTbTrnsFail(cellCb, tmpHqProc, tbCb->tbIdx, &maxRetx);
+ }
+ }/*if(((tbCb->nackCount+....*/
+ }/*else....*/
+
+ if (tbCb->taSnt == TRUE)
+ {
+ /* [ccpu00127148] Correcting the check */
+ if (TRUE == maxRetx)
+ {
+ tbCb->taSnt = FALSE;
+ ue->dl.taCb.state = RGSCH_TA_IDLE;
+
+ rgSCHUtlReTxTa(cellCb, ue);
+ RLOG_ARG0(L_DEBUG,DBG_CELLID,cellCb->cellId,
+ "Nack/DTX Rcvd for TA. Max Tries Attempted");
+
+ }
+ }
+ }
+ }
+ RETVALUE(ROK);
+}/* rgSCHDhmRlsDlsfHqProc */
+#else /* ifdef LTE_TDD */
+/**
+ * @brief Handler for Removing the HARQ process from a dlsf.
+ *
+ * @details
+ *
+ * Function : rgSCHDhmRlsDlsfHqProc
+ *
+ * This function shall be invoked for every tti. It goes back to
+ * to the sixth last subframe to check whether it still exists. If
+ * that exists this function traverses through the entire harq
+ * proc list associated and frees up all of them.
+ *
+ * @param[in] RgSchCellCb *cell
+ * @return S16
+ * -# ROK
+ * -# RFAILED
+ **/
+#ifdef ANSI
+PUBLIC S16 rgSCHDhmRlsDlsfHqProc
+(
+RgSchCellCb *cell,
+CmLteTimingInfo timingInfo
+)
+#else
+PUBLIC S16 rgSCHDhmRlsDlsfHqProc(cell, timingInfo)
+RgSchCellCb *cell;
+CmLteTimingInfo timingInfo;
+#endif
+{
+ RgSchDlSf *sf;
+ CmLteTimingInfo frm;
+ RgSchDlHqProcCb *tmpHqProc;
+ Bool maxRetx;
+ CmLList *node;
+ CmLList *hqPNode;
+ U8 idx;
+ RgSchDlHqTbCb *tbCb;
+ RgSchUeCb *ue;
+
+ TRC2(rgSCHDhmRlsDlsfHqProc)
+
+ /* Fetch the current timing info. Modify it to Last sf to be rlsd.*/
+ /* ccpu00133109: Removed RGSCHSUBFRMCRNTTIME as it is not giving proper
+ * output if diff is more than 10. Instead using RGSCHDECRFRMCRNTTIME()
+ * as it is serving the purpose */
+ RGSCHDECRFRMCRNTTIME(timingInfo, frm, RG_SCH_CMN_HARQ_INTERVAL);
+
+
+ /* Get the required Last subframe */
+ sf = rgSCHUtlSubFrmGet(cell, frm);
+
+ /*CA Dev Start*/
+ /*Handling for Msg4*/
+ node = sf->msg4HqPLst.first;
+ while (node)
+ {
+ tmpHqProc = (RgSchDlHqProcCb *)(node->node);
+ if (HQ_TB_WAITING == tmpHqProc->tbInfo[0].state)
+ {
+ tbCb = &tmpHqProc->tbInfo[0];
+ /* Fix : syed MultiUe per TTI crash in TA List. */
+ maxRetx = FALSE;
+
+ RGSCHDBGINFO(cell->instIdx, (rgSchPBuf(cell->instIdx),"\n rgSCHDhmRlsDlsfHqProc():\
+ txCntr=%d tmpHqProc=%d",tbCb->txCntr,tmpHqProc->procId));
+
+ tbCb->dtxCount++;
+ if ((tmpHqProc->hqE->msg4Proc == tmpHqProc) ||
+ (tmpHqProc->hqE->ccchSduProc == tmpHqProc))
+ {
+ tbCb->isAckNackDtx = TFU_HQFDB_NACK;
+ rgNumMsg4Dtx++;
+ }
+
+ node = node->next;
+ if (tbCb->fbkRepCntr != 0)
+ {
+ /* Update timingInfo for this hqP so that next subframe its picked up */
+ RG_SCH_ADD_TO_CRNT_TIME(tbCb->timingInfo, tbCb->timingInfo, 1);
+ rgSCHUtlDlHqPTbRmvFrmTx(sf,tmpHqProc,tbCb->tbIdx, TRUE);
+ tbCb->fbkRepCntr--;
+ continue;
+ }
+ rgSCHUtlDlHqPTbRmvFrmTx(sf,tmpHqProc,tbCb->tbIdx, FALSE);
+
+ /* Delete the Harq Association. Release the Harq Process */
+ rgSCHDhmHqTbTrnsFail(cell, tmpHqProc, tbCb->tbIdx, &maxRetx);
+
+ }
+ }
+ /* Subframe is present. Delete all the harq associations from
+ * this subframe.
+ */
+ node = sf->ueLst.first;
+ while (node)
+ {
+ ue = (RgSchUeCb *)(node->node);
+ node = node->next;
+ if(ue != NULLP)
+ {
+ hqPNode = ue->dl.dlSfHqInfo[cell->cellId][sf->dlIdx].hqPLst.first;
+
+ while (hqPNode)
+ {
+ tmpHqProc = (RgSchDlHqProcCb *)hqPNode->node;
+ tmpHqProc->cwSwpEnabled = FALSE;
+ hqPNode = hqPNode->next;
+ for (idx = 0 ;idx < 2; idx++)
+ {
+ if (HQ_TB_WAITING == tmpHqProc->tbInfo[idx].state)
+ {
+ tbCb = &tmpHqProc->tbInfo[idx];
+ /* Fix : syed MultiUe per TTI crash in TA List. */
+ maxRetx = FALSE;
+
+ RGSCHDBGINFO(cell->instIdx, (rgSchPBuf(cell->instIdx),"\n rgSCHDhmRlsDlsfHqProc():\
+ txCntr=%d tmpHqProc=%d",tbCb->txCntr,tmpHqProc->procId));
+
+ tbCb->dtxCount++;
+ if ((tmpHqProc->hqE->msg4Proc == tmpHqProc) ||
+ (tmpHqProc->hqE->ccchSduProc == tmpHqProc))
+ {
+ tbCb->isAckNackDtx = TFU_HQFDB_NACK;
+ rgNumMsg4Dtx++;
+ }
+ else
+ {
+ tbCb->isAckNackDtx = TFU_HQFDB_DTX;
+ }
+
+ rgSCHUtlDlHqPTbRmvFrmTx(sf,tmpHqProc,idx, FALSE);
+
+ {
+ /* Delete the Harq Association. Release the Harq Process */
+ rgSCHDhmHqTbTrnsFail(cell, tmpHqProc, tbCb->tbIdx, &maxRetx);
+ }
+ if (tbCb->taSnt == TRUE)
+ {
+ /* [ccpu00127148] Correcting the check */
+ if (TRUE == maxRetx)
+ {
+ tbCb->taSnt = FALSE;
+ ue->dl.taCb.state = RGSCH_TA_IDLE;
+
+ rgSCHUtlReTxTa(cell, ue);
+ RGSCHDBGINFO(cell->instIdx, (rgSchPBuf(cell->instIdx),
+ "Nack/DTX Rcvd for TA. Max Tries Attempted\n"));
+ }
+ }
+ RgSchCmnDlUe *ueDl = RG_SCH_CMN_GET_DL_UE(ue,cell);
+ ueDl->mimoInfo.cwInfo[tbCb->tbIdx].dtxCnt++;
+ }
+ }
+ }
+ }
+ }
+ /*CA Dev End*/
+
+ RETVALUE(ROK);
+} /* rgSCHDhmRlsDlsfHqProc */
+#endif
+#ifdef LTEMAC_SPS
+#ifdef RG_UNUSED
+/**
+ * @brief This function marks the HARQ process with a given ID as SPS HARQ
+ * proc
+ *
+ * @details
+ *
+ * Function: rgSCHDhmMarkSpsHqProc
+ * Purpose: This function returns the HARQ process with the given ID.
+ * Invoked by: SPS Module
+ * Processing steps:
+ * - Get the HARQ process by index from the UE
+ * - Set isSpsHqProc = TRUE
+ *
+ * @param[in] RgSchUeCb *ue
+ * @param[in] U8 idx
+ * @return S16
+ * -# ROK if successful
+ * -# RFAILED otherwise
+ *
+ **/
+#ifdef ANSI
+PUBLIC S16 rgSCHDhmMarkSpsHqProc
+(
+RgSchUeCb *ue,
+U8 idx
+)
+#else
+PUBLIC S16 rgSCHDhmMarkSpsHqProc(ue, idx)
+RgSchUeCb *ue;
+U8 idx;
+#endif
+{
+ RgSchDlHqProcCb *hqP;
+ TRC2(rgSCHDhmMarkSpsHqProc)
+
+ /* Pick the proc based on the index provided */
+ rgSCHDhmGetHqProcFrmId(ue->cell, ue, idx, &hqP);
+
+ RETVALUE(ROK);
+} /* rgSCHDhmMarkSpsHqProc */
+#endif /* RG_UNUSED */
+#endif /* LTEMAC_SPS */
+
+#ifndef LTE_TDD
+/** * @brief Handler for HARQ feedback received for DL AckNack rep enabled UE
+ *
+ * @details
+ *
+ * Function : rgSCHDhmProcHqFdbkAckNackRep
+ *
+ * This function shall act on the feedback received from TOM for DL
+ * transmission.
+ *
+ *
+ * @param[in] RgSchDlHqProcCb *hqP
+ * @param[in] RgSchDlSf *sf
+ * @param[in] U8 tbCnt
+ * @param[in] U8 *isAck
+ * @return S16
+ * -# ROK
+ * -# RFAILED
+ **/
+#ifdef ANSI
+PRIVATE S16 rgSCHDhmProcHqFdbkAckNackRep
+(
+RgSchDlHqProcCb *hqP,
+RgSchDlSf *sf,
+U8 tbCnt,
+U8 *isAck
+)
+#else
+PRIVATE S16 rgSCHDhmProcHqFdbkAckNackRep(hqP,sf,tbCnt,isAck)
+RgSchDlHqProcCb *hqP;
+RgSchDlSf *sf;
+U8 tbCnt;
+U8 *isAck;
+#endif
+{
+ TRC2(rgSCHDhmProcHqFdbkAckNackRep)
+ /* Check if this is repeating UE */
+ rgSCHUtlDlHqPTbRmvFrmTx(sf, hqP, tbCnt, TRUE);
+ /* Check if last repetition */
+ if (--hqP->tbInfo[tbCnt].fbkRepCntr)
+ {
+ /* Update timingInfo for this hqP so that next subframe its picked up */
+ RG_SCH_ADD_TO_CRNT_TIME(hqP->tbInfo[tbCnt].timingInfo, \
+ hqP->tbInfo[tbCnt].timingInfo, 1);
+ RETVALUE(RFAILED);
+ }
+
+ /* Take decision here based on the number
+ * of DTX's,NACK's and ACK's received
+ */
+ if (((hqP->tbInfo[tbCnt].ackCount) > (hqP->tbInfo[tbCnt].nackCount) +
+ (hqP->tbInfo[tbCnt].dtxCount)))
+ {
+ *isAck = TFU_HQFDB_ACK;
+ }
+ /*even a single NACK indicates that UE received
+ * the transmission.
+ */
+ else if ( hqP->tbInfo[tbCnt].nackCount != 0 )
+ {
+ *isAck = TFU_HQFDB_NACK;
+ }
+ else
+ {
+ *isAck = TFU_HQFDB_DTX;
+ }
+
+
+ hqP->tbInfo[tbCnt].isAckNackDtx = *isAck;
+ RETVALUE(ROK);
+}
+#endif /* ifndef LTE_TDD */
+
+
+/* Freeing up the HARQ proc blocked for
+ * indefinite time in case of Retx */
+/**
+ * @brief This function handles the scenario in case Retx allocation is failed.
+ *
+ * @details
+ *
+ * Function: rgSCHDhmDlRetxAllocFail
+ * Purpose:
+ *
+ * @param[in] RgSchUeCb *ue
+ * @param[in] RgSchDlHqProcCb *hqP
+ * @return Void
+ *
+ **/
+#ifdef ANSI
+PUBLIC S16 rgSCHDhmDlRetxAllocFail
+(
+RgSchUeCb *ue,
+RgSchDlHqProcCb *hqP
+)
+#else
+PUBLIC S16 rgSCHDhmDlRetxAllocFail(ue, hqP)
+RgSchUeCb *ue;
+RgSchDlHqProcCb *hqP;
+#endif
+{
+ RgSchCellCb *cell;
+ RgInfRlsHqInfo *rlsHqInfo;
+ Pst pst;
+ Bool maxRetx = FALSE;
+ RgSchCmnCell *cellSch;
+
+ TRC2(rgSCHDhmDlRetxAllocFail);
+
+ cell = hqP->hqE->cell;
+ cellSch = RG_SCH_CMN_GET_CELL(cell);
+ rlsHqInfo = &(cell->rlsHqArr[cell->crntHqIdx]);
+
+ /* If retx was attempted for 1st TB, increment its retx alloc fail counter */
+ if (hqP->tbInfo[0].state == HQ_TB_NACKED)
+ {
+ hqP->tbInfo[0].cntrRetxAllocFail++;
+ }
+
+ /* If retx was attempted for 2nd TB, increment its retx alloc fail counter */
+ if (hqP->tbInfo[1].state == HQ_TB_NACKED)
+ {
+ hqP->tbInfo[1].cntrRetxAllocFail++;
+ }
+
+ /* initialize MAC-SCH interface HARQ release info */
+ rlsHqInfo->numUes = 0;
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].numOfTBs = 0;
+
+ /* Release HARQ proc for TB1 if Retx alloc failure count has reached max */
+ if (hqP->tbInfo[0].cntrRetxAllocFail == RG_SCH_MAX_RETX_ALLOC_FAIL)
+ {
+ if (hqP->hqE->msg4Proc == hqP)
+ {
+ hqP->tbInfo[0].txCntr = cell->dlHqCfg.maxMsg4HqTx;
+ }
+ else
+ {
+ hqP->tbInfo[0].txCntr = hqP->hqE->maxHqTx;
+ }
+
+ rgSCHDhmHqTbTrnsFail(cell, hqP, hqP->tbInfo[0].tbIdx, &maxRetx);
+
+#ifdef LTE_L2_MEAS
+ if (maxRetx)
+ {
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].status[\
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].numOfTBs] = 0xFF; /* RGU_NACK_LOSS */;
+ }
+ else
+ {
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].status[\
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].numOfTBs] = FALSE;
+ }
+#else
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].status[\
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].numOfTBs] = FALSE;
+#endif
+
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].tbId[\
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].numOfTBs] = 1;
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].numOfTBs++;
+ }
+
+ /* Release HARQ proc for TB2 if Retx alloc failure count has reached max */
+ if (hqP->tbInfo[1].cntrRetxAllocFail == RG_SCH_MAX_RETX_ALLOC_FAIL)
+ {
+ if (hqP->hqE->msg4Proc == hqP)
+ {
+ hqP->tbInfo[1].txCntr = cell->dlHqCfg.maxMsg4HqTx;
+ }
+ else
+ {
+ hqP->tbInfo[1].txCntr = hqP->hqE->maxHqTx;
+ }
+
+ rgSCHDhmHqTbTrnsFail(cell, hqP, hqP->tbInfo[1].tbIdx, &maxRetx);
+
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].status[\
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].numOfTBs] = FALSE;
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].tbId[\
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].numOfTBs] = 2;
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].numOfTBs++;
+ }
+
+ /* MS_WORKAROUND for ccpu00122892 Temp fix for erroeneous RETX Harq release by rgSCHCmnDlAllocRetxRb */
+
+ if ((hqP->tbInfo[0].state != HQ_TB_NACKED) &&
+ (hqP->tbInfo[1].state != HQ_TB_NACKED))
+ {
+ cellSch->apisDl->rgSCHDlProcRmvFrmRetx(cell, ue, hqP);
+ }
+
+ /* send HARQ release to MAC */
+ if (rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].numOfTBs > 0)
+ {
+ /* Fix : syed HO UE does not have a valid ue->rntiLnk */
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].rnti = ue->ueId;
+ rlsHqInfo->ueHqInfo[rlsHqInfo->numUes].hqProcId = hqP->procId;
+ rlsHqInfo->numUes = 1;
+
+ rgSCHUtlGetPstToLyr(&pst, &rgSchCb[cell->instIdx], cell->macInst);
+ RgSchMacRlsHq(&pst, rlsHqInfo);
+ }
+
+ RETVALUE(ROK);
+}
+
+#ifdef DL_LA
+#ifdef ANSI
+PRIVATE S16 rgSCHDhmUpdateAckNackHistory
+(
+RgSchCellCb *cell,
+RgSchUeCb *ueCb,
+U8 hqfdbk,
+U8 tbCnt
+)
+#else
+PRIVATE S16 rgSCHDhmUpdateAckNackHistory(cell, ueCb, hqfdbk, tbCnt)
+(
+RgSchCellCb *cell;
+RgSchUeCb *ueCb;
+U8 hqfdbk;
+U8 tbCnt;
+)
+#endif
+{
+ RgSchCmnDlUe *ueDl;
+
+ ueDl = RG_SCH_CMN_GET_DL_UE(ueCb,cell);
+
+ /*
+ * If fdbk is ack update totalNoOfAck and ackNackHistory for
+ * current idx
+ */
+ if (hqfdbk == TFU_HQFDB_ACK)
+ {
+ ueDl->laCb[tbCnt].deltaiTbs += DL_LA_STEPUP;
+ }
+ else
+ {
+ ueDl->laCb[tbCnt].deltaiTbs = ueDl->laCb[tbCnt].deltaiTbs - DL_LA_STEPDOWN;
+ }
+ /*
+ printf("deltaiTbs[%d] cqibasediTbs[%d] iTbs[%d] tbCnt[%d]\n",
+ ueDl->laCb[tbCnt].deltaiTbs, ueDl->laCb[tbCnt].cqiBasediTbs,
+ (ueDl->laCb[tbCnt].deltaiTbs + ueDl->laCb[tbCnt].cqiBasediTbs)/100,
+ tbCnt);
+ */
+ rgSCHDhmUpdBlerBasediTbsEff(cell, ueCb, tbCnt);
+
+ RETVALUE(ROK);
+}
+
+#ifdef ANSI
+PUBLIC S16 rgSCHDhmUpdBlerBasediTbsEff
+(
+RgSchCellCb *cell,
+RgSchUeCb *ueCb,
+U8 tbCnt
+)
+#else
+PUBLIC S16 rgSCHDhmUpdBlerBasediTbsEff(cell, ueCb, tbCnt)
+(
+RgSchCellCb *cell;
+RgSchUeCb *ueCb;
+U8 tbCnt;
+)
+#endif
+{
+ S32 iTbs;
+ RgSchCmnDlUe *ueDl;
+ RgSchCmnCell *cellSch = RG_SCH_CMN_GET_CELL(cell);
+ U8 cfi = cellSch->dl.currCfi;
+ U8 maxiTbs = (*(RgSchCmnCqiToTbs *)(cellSch->dl.cqiToTbsTbl[0][cfi]))[RG_SCH_CMN_MAX_CQI - 1];
+ maxiTbs = RG_SCH_DL_MAX_ITBS;
+
+ ueDl = RG_SCH_CMN_GET_DL_UE(ueCb,cell);
+ iTbs = (ueDl->laCb[tbCnt].deltaiTbs + ueDl->laCb[tbCnt].cqiBasediTbs)/100;
+
+ if (iTbs > maxiTbs)
+ {
+ ueDl->laCb[tbCnt].deltaiTbs = (maxiTbs * 100) - ueDl->laCb[tbCnt].cqiBasediTbs;
+ ueDl->mimoInfo.cwInfo[tbCnt].iTbs[0] = RGSCH_MIN(maxiTbs, ueCb->cell->thresholds.maxDlItbs);
+ }
+ else if (iTbs < 0)
+ {
+ ueDl->laCb[tbCnt].deltaiTbs = -(ueDl->laCb[tbCnt].cqiBasediTbs);
+ ueDl->mimoInfo.cwInfo[tbCnt].iTbs[0] = 0;
+ }
+ else
+ {
+ ueDl->mimoInfo.cwInfo[tbCnt].iTbs[0] = RGSCH_MIN(((ueDl->laCb[tbCnt].cqiBasediTbs +\
+ ueDl->laCb[tbCnt].deltaiTbs)/100),
+ ueCb->cell->thresholds.maxDlItbs);
+ }
+#ifdef RG_5GTF
+ ueCb->ue5gtfCb.mcs = ueDl->mimoInfo.cwInfo[tbCnt].iTbs[0];
+#endif
+ ueDl->mimoInfo.cwInfo[tbCnt].iTbs[1] = ueDl->mimoInfo.cwInfo[tbCnt].iTbs[0];
+
+ /* Eff for CW for 1 Layer Tx */
+ ueDl->mimoInfo.cwInfo[tbCnt].eff[0] =
+ (*(RgSchCmnTbSzEff *)(cellSch->dl.cqiToEffTbl[0][cfi]))\
+ [ueDl->mimoInfo.cwInfo[tbCnt].iTbs[0]];
+
+ /* Eff for CW for 2 Layer Tx */
+ ueDl->mimoInfo.cwInfo[tbCnt].eff[1] =
+ (*(RgSchCmnTbSzEff *)(cellSch->dl.cqiToEffTbl[1][cfi]))\
+ [ueDl->mimoInfo.cwInfo[tbCnt].iTbs[1]];
+
+ RETVALUE(ROK);
+}
+#endif
+
+#ifdef LTE_TDD
+/**
+ * @brief This function Processes the Hq Fdbk in case of
+ * special Bundling in TDD (FAPIv1.1: Table 79)
+ *
+ * @details
+ *
+ * Function: rgSCHDhmPrcSplBundlFdbk
+ * Purpose: To Interpret the Harq Feedback according to
+ * table 7.3-1: 36.213
+ *
+ * 0 = 0 or None (UE detect at least one DL is missed)
+ * 1 = 1 or 4 or 7 ACKs reported
+ * 2 = 2 or 5 or 8 ACKs reported
+ * 3 = 3 or 6 or 9 ACKs reported
+ * 4 = DTX (UE did not transmit anything)
+ *
+ * @param[in] TfuHqInfo *fdbk
+ * @param[in] U8 hqCnt
+ * @return Void
+ *
+ **/
+#ifdef ANSI
+PRIVATE Void rgSCHDhmPrcSplBundlFdbk
+(
+RgSchCellCb *cell,
+TfuHqInfo *fdbk,
+U8 hqCnt
+)
+#else
+PRIVATE Void rgSCHDhmPrcSplBundlFdbk(cell, fdbk, hqCnt)
+(
+RgSchCellCb *cell;
+TfuHqInfo *fdbk;
+U8 hqCnt;
+)
+#endif
+{
+ U8 numOfAcks;
+
+ TRC2(rgSCHDhmPrcSplBundlFdbk);
+
+ /* Num of ACKs reported by UE */
+ numOfAcks = fdbk->isAck[0];
+
+ if(fdbk->isAck[0] == TFU_HQFDB_NACK ||
+ fdbk->isAck[0] == TFU_HQFDB_DTX)
+ {
+ /* NACK/DTX CASE */
+ }
+ else
+ {
+ RGSCH_ARRAY_BOUND_CHECK(cell->instIdx,
+ rgSchNumOfAcksToAckNack[(hqCnt-1)], (numOfAcks - 1));
+
+ fdbk->isAck[0] = rgSchNumOfAcksToAckNack[(hqCnt-1)]
+ [(numOfAcks-1)];
+ }
+ /* The Hq Fdbk is a combined Ack/Nack for multiple Codewords within
+ the PDSCH trasnmission (spatial bundling). So we have
+ to assume same feedback for both codewords */
+#ifdef LTE_ADV
+ for(U8 idx = 1 ; idx < TFU_MAX_HARQ_FDBKS; idx++)
+ {
+ fdbk->isAck[idx] = fdbk->isAck[0];
+ }
+#else
+ fdbk->isAck[1] = fdbk->isAck[0];
+#endif
+
+ RETVOID;
+}
+#endif
+
+/**
+ * @brief This function adds HARQ process to FREE list
+ *
+ * @details
+ *
+ * Function: rgSCHDhmHqPAdd2FreeLst
+ * Purpose:
+ *
+ * Invoked by: scheduler
+ *
+ * @param[out] RgDlHqProc *hqP
+ * @return Void
+ *
+ **/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmHqPAdd2FreeLst
+(
+RgSchDlHqProcCb *hqP
+)
+#else
+PUBLIC Void rgSCHDhmHqPAdd2FreeLst(hqP)
+RgSchDlHqProcCb *hqP;
+#endif
+{
+ TRC2(rgSCHDhmHqPAdd2FreeLst)
+
+#ifdef LAA_DBG
+ if (hqP->hqPLst)
+ {
+ int *p = NULL;
+ printf("Crashing already part of free lst\n");
+ printf("Crashing %d \n", *p);
+ *p = 10;
+ }
+#endif
+ cmLListAdd2Tail(&hqP->hqE->free, &hqP->lnk);
+ hqP->hqPLst = &hqP->hqE->free;
+
+
+#ifdef LAA_DBG
+ if (hqP->hqE->free.count > 8)
+ {
+ int *p = NULL;
+ printf("Crashing invalid hq count\n");
+ printf("Crashing %d \n", *p);
+ *p = 10;
+ }
+#endif
+
+#ifdef LTE_ADV
+ rgSCHLaaHndlHqProcFree(hqP);
+#endif
+
+ RETVOID;
+} /* rgSCHDhmHqPAdd2FreeLst */
+
+
+/**
+ * @brief This function adds HARQ process to inUse list
+ *
+ * @details
+ *
+ * Function: rgSCHDhmHqPAdd2InUseLst
+ * Purpose:
+ *
+ * Invoked by: scheduler
+ *
+ * @param[out] RgDlHqProc *hqP
+ * @return Void
+ *
+ **/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmHqPAdd2InUseLst
+(
+RgSchDlHqProcCb *hqP
+)
+#else
+PUBLIC Void rgSCHDhmHqPAdd2InUseLst(hqP)
+RgSchDlHqProcCb *hqP;
+#endif
+{
+ TRC2(rgSCHDhmHqPAdd2InUseLst)
+
+#ifdef LAA_DBG
+ if (hqP->hqPLst)
+ {
+ int *p = NULL;
+ printf("Crashing already part of inuse lst\n");
+ printf("Crashing %d \n", *p);
+ *p = 10;
+ }
+#endif
+ cmLListAdd2Tail(&hqP->hqE->inUse, &hqP->lnk);
+ hqP->hqPLst = &hqP->hqE->inUse;
+
+
+#ifdef LAA_DBG
+ if (hqP->hqE->inUse.count > 8)
+ {
+ int *p = NULL;
+ printf("Crashing invalid hq count \n");
+ printf("Crashing %d \n", *p);
+ *p = 10;
+ }
+#endif
+
+ RETVOID;
+} /* rgSCHDhmHqPAdd2InUseLst */
+
+/**
+ * @brief This function adds HARQ process to FREE list
+ *
+ * @details
+ *
+ * Function: rgSCHDhmHqPDelFrmFreeLst
+ * Purpose:
+ *
+ * Invoked by: scheduler
+ *
+ * @param[out] RgDlHqProc *hqP
+ * @return Void
+ *
+ **/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmHqPDelFrmFreeLst
+(
+RgSchDlHqProcCb *hqP
+)
+#else
+PUBLIC Void rgSCHDhmHqPDelFrmFreeLst(hqP)
+RgSchDlHqProcCb *hqP;
+#endif
+{
+ TRC2(rgSCHDhmHqPDelFrmFreeLst)
+
+#ifdef LAA_DBG
+ if (!hqP->hqPLst)
+ {
+ int *p = NULL;
+ printf("Crashing not part of any lst\n");
+ printf("Crashing %d \n", *p);
+ *p = 10;
+ }
+#endif
+#ifdef LAA_DBG
+ if (hqP->hqPLst != &hqP->hqE->free)
+ {
+ int *p = NULL;
+ printf("Crashing del from wrong lst\n");
+ printf("Crashing %d \n", *p);
+ *p = 10;
+ }
+#endif
+
+ cmLListDelFrm(&hqP->hqE->free, &hqP->lnk);
+ hqP->hqPLst = NULLP;
+
+#ifdef LAA_DBG
+ if (hqP->hqE->free.count > 8)
+ {
+ int *p = NULL;
+ printf("Crashing invalid hq count\n");
+ printf("Crashing %d \n", *p);
+ *p = 10;
+ }
+#endif
+
+ RETVOID;
+} /* rgSCHDhmHqPDelFrmFreeLst */
+
+
+
+/**
+ * @brief This function adds HARQ process to FREE list
+ *
+ * @details
+ *
+ * Function: rgSCHDhmHqPDelFrmInUseLst
+ * Purpose:
+ *
+ * Invoked by: scheduler
+ *
+ * @param[out] RgDlHqProc *hqP
+ * @return Void
+ *
+ **/
+#ifdef ANSI
+PUBLIC Void rgSCHDhmHqPDelFrmInUseLst
+(
+RgSchDlHqProcCb *hqP
+)
+#else
+PUBLIC Void rgSCHDhmHqPDelFrmInUseLst(hqP)
+RgSchDlHqProcCb *hqP;
+#endif
+{
+ TRC2(rgSCHDhmHqPDelFrmInUseLst)
+
+#ifdef LAA_DBG
+ if (!hqP->hqPLst)
+ {
+ int *p = NULL;
+ printf("Crashing not part of any lst\n");
+ printf("Crashing %d \n", *p);
+ *p = 10;
+
+ }
+#endif
+#ifdef LAA_DBG
+ if (hqP->hqPLst != &hqP->hqE->inUse)
+ {
+ int *p = NULL;
+ printf("Crashing del from wrong lst\n");
+ printf("Crashing %d \n", *p);
+ *p = 10;
+ }
+#endif
+
+ cmLListDelFrm(&hqP->hqE->inUse, &hqP->lnk);
+ hqP->hqPLst = NULLP;
+
+#ifdef LAA_DBG
+ if (hqP->hqE->inUse.count > 8)
+ {
+ int *p = NULL;
+ printf("Crashing invalid hq count\n");
+ printf("Crashing %d \n", *p);
+ *p = 10;
+ }
+#endif
+
+ RETVOID;
+} /* rgSCHDhmHqPDelFrmInUseLst */
+
+\f
+/**********************************************************************
+
+ End of file
+**********************************************************************/