1 /*******************************************************************************
2 ################################################################################
3 # Copyright (c) [2017-2019] [Radisys] #
5 # Licensed under the Apache License, Version 2.0 (the "License"); #
6 # you may not use this file except in compliance with the License. #
7 # You may obtain a copy of the License at #
9 # http://www.apache.org/licenses/LICENSE-2.0 #
11 # Unless required by applicable law or agreed to in writing, software #
12 # distributed under the License is distributed on an "AS IS" BASIS, #
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
14 # See the License for the specific language governing permissions and #
15 # limitations under the License. #
16 ################################################################################
17 *******************************************************************************/
19 /************************************************************************
25 Desc: C source code for power control functionality
29 **********************************************************************/
31 /** @file rg_sch_pwr.c
32 @brief This module handles schedulers' power control functionality
35 static const char* RLOG_MODULE_NAME="MAC";
36 static int RLOG_MODULE_ID=4096;
37 static int RLOG_FILE_ID=188;
38 /* header include files -- defines (.h) */
39 #include "common_def.h"
45 #include "rg_sch_inf.h"
46 #include "rg_sch_err.h"
48 #include "rg_sch_cmn.h"
50 /* header/extern include files (.x) */
51 #include "tfu.x" /* RGU types */
52 #include "lrg.x" /* layer management typedefs for MAC */
53 #include "rgr.x" /* layer management typedefs for MAC */
54 #include "rgm.x" /* layer management typedefs for MAC */
55 #include "rg_sch_inf.x" /* typedefs for Scheduler */
56 #include "rg_sch.x" /* typedefs for Scheduler */
57 #include "rg_sch_cmn.x"
58 #include "rl_interface.h"
59 #include "rl_common.h"
62 /* Current specs have 23 dBm as max tx power capability for UEs */
63 #define RG_SCH_PWR_UE_MAX_PWR 23
65 #define RG_SCH_REF_PCMAX 0xFF
67 #define RG_SCH_CMN_GET_UL_UE(_ue,_cell) (&(((RgSchCmnUe *)((_ue->cellInfo[_ue->cellIdToCellIdxMap\
68 [RG_SCH_CELLINDEX(_cell)]])->sch))->ul))
69 #define RG_SCH_PWR_GETUEPWR(_ue, _cell) &(((RgSchCmnUe *)((_ue->cellInfo[_ue->cellIdToCellIdxMap\
70 [RG_SCH_CELLINDEX(_cell)]])->sch))->ul.ulPwrCb)
71 #define RG_SCH_PWR_GETCELLPWR(cell) &((RgSchCmnCell *)((cell)->sc.sch))->ul.ulPwrCb
74 typedef S8 RgSchCmnUlPwrCqiToPwrTbl[RG_SCH_CMN_UL_NUM_CQI];
76 static RgSchCmnUlPwrCqiToPwrTbl rgSchPwrCqiToPwrTbl;
78 /* This table maps a given number of RBs (given by array index)
79 * to the power in dB that these many RBs map to. */
80 const uint8_t rgSchPwrRbToPwrTbl[111] = { 0, /* First entry is dummy */
81 0, 3, 4, 6, 7, 7, 8, 9, 9, 10,
82 10, 10, 11, 11, 11, 12, 12, 12, 12, 13,
83 13, 13, 13, 13, 14, 14, 14, 14, 14, 14,
84 15, 15, 15, 15, 15, 15, 15, 15, 16, 16,
85 16, 16, 16, 16, 16, 16, 16, 16, 17, 17,
86 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
87 17, 18, 18, 18, 18, 18, 18, 18, 18, 18,
88 18, 18, 18, 18, 18, 18, 18, 19, 19, 19,
89 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
90 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
91 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
95 /* This table maps power (in dB) to number of RBs */
96 /* The array size comes from max power in rgSchPwrRbToPwrTbl */
97 const uint8_t rgSchPwrToRbTbl[20+1] = {
98 1, 1, 2, 2, 3, 4, 5, 6, 7, 9, 11,
99 13, 17, 21, 26, 33, 41, 52, 65, 82, 103
104 static S8 rgSCHPwrGetCqiPwr ARGS((
107 static S8 rgSCHPwrGetCqiPwrForUe ARGS((
112 static S8 rgSCHPwrCalcEfficncyPwr ARGS((
115 static S8 rgSCHPwrGetDelta2FrmCqi ARGS((
121 static Void rgSCHPwrGetPuschTpc ARGS((
128 static uint8_t rgSCHPwrGetMaxRb ARGS((
132 static uint8_t rgSCHPwrRbToPwr ARGS((
136 static Void rgSCHPwrSchedPucchRnti ARGS((
138 RgSchCmnTpcRntiCb *cb,
143 static Void rgSCHPwrPuschCntrl ARGS((
147 static Void rgSCHPwrPucchCntrl ARGS((
151 static Void rgSCHPwrSchedPuschRnti ARGS((
153 RgSchCmnTpcRntiCb *cb,
158 static Void rgSCHPwrGetPucchFmt3TpcForUe ARGS((
163 static Void rgSCHPwrGetPucchFmt3aTpcForUe ARGS((
168 static Void rgSCHPwrGetPuschFmt3TpcForUe ARGS((
173 static Void rgSCHPwrGetPuschFmt3aTpcForUe ARGS((
178 static Void rgSCHPwrGetAcc1bitTpc ARGS((
183 static Void rgSCHPwrGetAcc2bitTpc ARGS((
188 static Void rgSCHPwrGetAbsTpc ARGS((
193 static Void rgSCHPwrOnPucchGrpPwrForUe ARGS((
198 static Void rgSCHPwrOnPuschGrpPwrForUe ARGS((
203 static Bool rgSCHPwrIsDlUeSched ARGS((
208 static Bool rgSCHPwrIsUlUeSched ARGS((
213 static Void rgSCHPwrOnSchedPucchTpc ARGS((
218 static Void rgSCHPwrOnSchedPuschTpc ARGS((
222 static S16 rgSCHPwrApplyUePwrCfg ARGS((
225 RgrUeUlPwrCfg *pwrCfg
227 static Void rgSCHPwrUeResetPucch ARGS((
231 static Void rgSCHPwrUeResetPusch ARGS((
235 static Void rgSCHPwrOnPuschPwrUpd ARGS((
239 static Void rgSCHPwrAddRntiToPucchRntiLst ARGS((
244 static Void rgSCHPwrAddRntiToPuschRntiLst ARGS((
249 static Void rgSCHPwrInitTpcRntiCb ARGS((
250 RgSchCmnTpcRntiCb *cb,
254 static RgSchCmnTpcRntiCb* rgSCHPwrGetPucchRntiCb ARGS((
258 static RgSchCmnTpcRntiCb* rgSCHPwrGetPuschRntiCb ARGS((
262 static Void rgSCHPwrAddUeToPucchTpcRntiCb ARGS((
264 RgSchCmnTpcRntiCb *cb,
267 static Void rgSCHPwrDelUeFrmPucchTpcRntiCb ARGS((
269 RgSchCmnTpcRntiCb *cb,
272 static Void rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb ARGS((
274 RgSchCmnTpcRntiCb *cb,
277 static Void rgSCHPwrRmvSchdUeOnlyFrmPucchTpcRntiCb ARGS((
279 RgSchCmnTpcRntiCb *cb,
282 static Void rgSCHPwrRmvSchdPucchTpcRntiCb ARGS((
284 RgSchCmnTpcRntiCb *cb
286 static Void rgSCHPwrAddSchdUeToPucchTpcRntiCb ARGS((
288 RgSchCmnTpcRntiCb *cb,
291 static Void rgSCHPwrAddSchdPucchTpcRntiCb ARGS((
293 RgSchCmnTpcRntiCb *cb
295 static Void rgSCHPwrAddUeToPuschTpcRntiCb ARGS((
296 RgSchCmnTpcRntiCb *cb,
299 static Void rgSCHPwrAddSchdUeToPuschTpcRntiCb ARGS((
301 RgSchCmnTpcRntiCb *cb,
304 static Void rgSCHPwrDelUeFrmPuschTpcRntiCb ARGS((
306 RgSchCmnTpcRntiCb *cb,
309 static Void rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb ARGS((
311 RgSchCmnTpcRntiCb *cb,
314 static Void rgSCHPwrRmvSchdUeOnlyFrmPuschTpcRntiCb ARGS((
316 RgSchCmnTpcRntiCb *cb,
319 static Void rgSCHPwrAddSchdPuschTpcRntiCb ARGS((
321 RgSchCmnTpcRntiCb *cb
323 static Void rgSCHPwrRmvSchdPuschTpcRntiCb ARGS((
325 RgSchCmnTpcRntiCb *cb
327 static S16 rgSCHPwrChkPucchTpcRntiIdx ARGS((
328 RgSchCmnTpcRntiCb *cb,
331 static S16 rgSCHPwrChkPuschTpcRntiIdx ARGS((
332 RgSchCmnTpcRntiCb *cb,
335 static S16 rgSCHPwrChkUniqPucchTpcRntiIdx ARGS((
336 RgSchCmnTpcRntiCb *cb,
339 static S16 rgSCHPwrChkUniqPuschTpcRntiIdx ARGS((
340 RgSchCmnTpcRntiCb *cb,
343 static S16 rgSCHPwrChkTpcRntiIdx ARGS((
344 RgSchCmnTpcRntiCb *cb,
347 static S8 rgSCHPwrGetPhValFromPhr ARGS((
350 static S8 rgSCHPwrGetPCMaxValFromPCMax ARGS((
358 * @brief Does power related initialisation (not cell specific).
363 * Function : rgSCHPwrInit
366 * - This shall precompute coding efficiency to power
367 * mappings (assuming beta of 1).
375 rgSchPwrCqiToPwrTbl[0] = 0; /* This should never be used anyway */
376 for (idx = 1; idx < RG_SCH_CMN_UL_NUM_CQI; ++idx)
378 rgSchPwrCqiToPwrTbl[idx] = rgSCHPwrCalcEfficncyPwr(rgSchCmnUlCqiTbl[idx].eff);
383 /***********************************************************
385 * Func : rgSCHPwrGetCqiPwr
387 * Desc : Returns power corresponding to coding efficiency
388 * when beta pusch is assumed 1.
396 **********************************************************/
397 static S8 rgSCHPwrGetCqiPwr(uint8_t cqi)
400 return (rgSchPwrCqiToPwrTbl[cqi]);
401 } /* rgSCHPwrGetCqiPwr */
403 /***********************************************************
405 * Func : rgSCHPwrGetCqiPwrForUe
407 * Desc : If MCS control is enabled for UE, returns
408 * power corresponding to CQI, else 0.
416 **********************************************************/
417 static S8 rgSCHPwrGetCqiPwrForUe(RgSchCellCb *cell,RgSchUeCb *ue,uint8_t cqi)
419 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
421 if (!uePwr->deltaMcsEnbld)
425 return (rgSCHPwrGetCqiPwr(cqi));
426 } /* rgSCHPwrGetCqiPwrForUe */
428 /***********************************************************
430 * Func : rgSCHPwrCalcEfficncyPwr
432 * Desc : Computes power corresponding to a coding
437 * Notes: Assumes beta pusch to be 1
441 **********************************************************/
442 static S8 rgSCHPwrCalcEfficncyPwr(uint32_t eff)
444 F64 ks = 1.25; /* or F64 */
445 F64 tmp = cmPow(2, ks*eff/1024) - 1;
449 return ((S8)(10 * cmLog10(tmp)));
450 } /* rgSCHPwrCalcEfficncyPwr */
454 * @brief Returns TPC to be sent in UL allocation
458 * Function : rgSCHPwrPuschTpcForUe
460 * Invoking Module Processing:
461 * - After allocation for UE, this function shall
462 * be invoked to retrieve TPC.
463 * - This assumes that rgSCHPwrGetMaxUlRb() was
464 * invoked prior to final allocation for UE.
467 * - Just return TPC that was determined
469 * - After this, do necessary updates.
471 * @param[in] RgSchCellCb *cell
472 * @param[in] RgSchUeCb *ue
475 uint8_t rgSCHPwrPuschTpcForUe(RgSchCellCb *cell,RgSchUeCb *ue)
477 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue,cell);
481 rgSCHPwrOnSchedPuschTpc(cell, ue);
482 return (uePwr->puschTpc);
486 * @brief Handles Pusch power control for DCI format 0
490 * Function : rgSCHPwrGetMaxUlRb
492 * Invoking Module Processing:
493 * - This shall be invoked to determine maximum
494 * number of UL RBs for scheduling.
495 * - This is expected to be invoked every time
496 * priority to attempt at UE allocation. Later
497 * TPC retrieval depends on it.
500 * - Returns maximum allowed UL RBs to be granted
501 * after invoking Pusch power control.
503 * @param[in] RgSchCellCb *cell
504 * @param[in] RgSchUeCb *ue
507 uint8_t rgSCHPwrGetMaxUlRb(RgSchCellCb *cell,RgSchUeCb *ue)
509 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
511 rgSCHPwrPuschCntrl(cell, ue); /* This stores tpc, delta and maxRb
513 return (uePwr->maxUlRbs);
517 * @brief Handles Pusch power control for DCI format 0
521 * Function : rgSCHPwrPuschCntrl
523 * Invoking Module Processing:
524 * - This shall be invoked to determine TPC
525 * and maximum number of UL RBs for scheduling
526 * (through DCI format 0).
529 * - 'remPuschPwr' is the final delta power that the UE
530 * should apply to get to target CQI.
531 * - The available headroom (availPwr) is determined.
532 * - Power command is given by considering remPuschPwr and
534 * - After factoring in the power command into availPwr, the
535 * maximum number of RBs that can be supported is determined
536 * assuming that UE is going to use transmission efficiency
537 * corresponding to current CQI.
538 * - The results determined in this function are stored
539 * in the UE power control block.
540 * - [Not doing anything of power control of msg3
541 * retransmissions now]
543 * @param[in] RgSchCellCb *cell
544 * @param[in] RgSchUeCb *ue
547 static Void rgSCHPwrPuschCntrl(RgSchCellCb *cell,RgSchUeCb *ue)
549 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
550 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
551 RgSchCmnUlCell *cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
554 uint8_t cqi = ueUl->validUlCqi;
557 uint8_t cqi = ueUl->crntUlCqi[0];
559 Bool isAcc = uePwr->isAccumulated;
566 if (!uePwr->isPhrAvail)
568 availPwr = 60; /* setting a large value so that availPwr does
569 * not constrain delta */
573 availPwr = uePwr->maxUePwr - uePwr->pwrPerRb;
574 availPwr -= rgSCHPwrGetCqiPwrForUe(cell, ue, cqi);
576 delta = uePwr->remPuschPwr;
577 rgSCHPwrGetPuschTpc(isAcc, delta, availPwr, &tpc, &delta);
580 maxRb = rgSCHPwrGetMaxRb(cell,availPwr);
582 /* Store the results in ue power control block to be used later */
583 if(maxRb < cellUl->sbSize)
585 maxRb = cellUl->sbSize;
587 if(uePwr->maxPwrDeltaByPhr < 0)
589 tmp = ueUl->validUlCqi;
590 tmp = tmp + uePwr->maxPwrDeltaByPhr;
593 ueUl->validUlCqi = 1;
597 ueUl->validUlCqi = tmp;
602 RLOG_ARG4(L_UNUSED,DBG_CELLID,cell->cellId,
603 "UEID:%d Output Max Rb (%d), phVal (%d) AvailPwr (%d) ",
604 ue->ueId, maxRb, uePwr->phVal, availPwr);
605 RLOG_ARG3(L_UNUSED,DBG_CELLID,cell->cellId,
606 "UEID:%d pwrPerRb %d remPuschPwr %d",
610 uePwr->delta = delta;
611 uePwr->maxUlRbs = maxRb;
612 uePwr->puschTpc = tpc;
617 * @brief Returns TPC to be sent in DL allocation
621 * Function : rgSCHPwrPucchTpcForUe
623 * Invoking Module Processing:
624 * - After DL allocation for UE, this function shall
625 * be invoked to obtain TPC.
628 * - Do Pucch power control processing
631 * @param[in] RgSchCellCb *cell
632 * @param[in] RgSchUeCb *ue
635 uint8_t rgSCHPwrPucchTpcForUe(RgSchCellCb *cell,RgSchUeCb *ue)
637 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
639 rgSCHPwrPucchCntrl(cell, ue);
640 return (uePwr->pucchTpc);
643 /***********************************************************
645 * Func : rgSCHPwrGetDelta2FrmCqi
647 * Desc : Get power to be applied to achieve
648 * target CQI (the power returned is
649 * twice is actual power)
657 **********************************************************/
658 static S8 rgSCHPwrGetDelta2FrmCqi(uint8_t crntCqi,uint8_t trgCqi,RgSchUeCb *ue,RgSchCellCb *cell)
660 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
662 if (uePwr->isPhrAvail)
664 //uePwr->maxPwrDeltaByPhr = uePwr->maxPwrPerRb - uePwr->pwrPerRb - uePwr->remPuschPwr;
665 uePwr->maxPwrDeltaByPhr = uePwr->maxPwrPerRb - uePwr->pwrPerRb;
669 uePwr->maxPwrDeltaByPhr = 0;
672 if (uePwr->maxPwrDeltaByPhr < 0 && (trgCqi - crntCqi) *
673 RG_SCH_UL_CQI_DB_STEP_2 > 0)
677 return (RGSCH_MIN(uePwr->maxPwrDeltaByPhr,
678 (trgCqi - crntCqi) * RG_SCH_UL_CQI_DB_STEP_2));
679 } /* rgSCHPwrGetDelta2FrmCqi */
681 /***********************************************************
683 * Func : rgSCHPwrGetPuschTpc
685 * Desc : Based on whether accumulation is enabled or
686 * not, this returns an applicable power delta
687 * to be applied based on the input delta.
695 **********************************************************/
696 static Void rgSCHPwrGetPuschTpc(uint8_t isAcc,S8 delta,S8 availPwr,uint8_t *tpc,S8 *tpcDelta)
699 delta = RGSCH_MIN(delta, availPwr);
701 /* As of now, the functions below possibly cause delta
702 * to be breached by 1 only. So calling these as is. */
705 rgSCHPwrGetAcc2bitTpc(delta, tpc, tpcDelta);
709 rgSCHPwrGetAbsTpc(delta, tpc, tpcDelta);
712 } /* rgSCHPwrGetPuschTpc */
714 /***********************************************************
716 * Func : rgSCHPwrGetMaxRb
718 * Desc : Get the maximum number of RBs that can be
719 * expected to be supported by the passed
728 **********************************************************/
729 static uint8_t rgSCHPwrGetMaxRb(RgSchCellCb *cell,S8 pwr)
731 RgSchCmnUlCell *cellUl;
733 cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
736 /* Give 4 RBS so that UE can report changed power status*/
737 /* [ccpu00119916] Mod -return 0th index of rgSchPwrToRbTbl when pwr <=0
738 * Change the Macros from RGSCH_MAX_DL_BW to RGSCH_MAX_UL_BW*/
739 return (rgSchPwrToRbTbl[0]);
741 if (pwr > rgSchPwrRbToPwrTbl[cellUl->maxUlBwPerUe])
743 return (cellUl->maxUlBwPerUe);
745 return (RGSCH_MIN(cellUl->maxUlBwPerUe,rgSchPwrToRbTbl[(uint8_t)pwr]));
746 } /* rgSCHPwrGetMaxRb */
748 /***********************************************************
750 * Func : rgSCHPwrRbToPwr
752 * Desc : Get the power corresponding to number of RBs
760 **********************************************************/
761 static uint8_t rgSCHPwrRbToPwr(RgSchCellCb *cell,uint8_t numRb)
764 RgSchCmnUlCell *cellUl;
766 #if (ERRCLASS & ERRCLS_DEBUG)
767 cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
768 if (numRb > cellUl->maxUlBwPerUe)
770 numRb = cellUl->maxUlBwPerUe;
773 return (rgSchPwrRbToPwrTbl[numRb]);
774 } /* rgSCHPwrRbToPwr */
778 * @brief Handles Pucch power control for DCI formats 1A/1B/1D/1/2A/2
782 * Function : rgSCHPwrPucchCntrl
785 * - Determine 2 bit TPC to be sent using remPucchPwr.
786 * - Update remPucchPwr appropriately
788 * @param[in] RgSchCellCb *cell
789 * @param[in] RgSchUeCb *ue
792 static Void rgSCHPwrPucchCntrl(RgSchCellCb *cell,RgSchUeCb *ue)
795 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
797 rgSCHPwrGetAcc2bitTpc(uePwr->remPucchPwr, &uePwr->pucchTpc, &delta);
798 rgSCHPwrOnSchedPucchTpc(cell, ue, delta);
803 * @brief Handles group power control for DCI formats 3/3A for Pucch and Pusch
807 * Function : rgSCHPwrGrpCntrlPucch
809 * Invoking Module Processing:
810 * - This shall be invoked to do group power control for
811 * all TPC RNTIs for which it is deemed necessary to
812 * do the same (group power control).
813 * - This function should only be invoked after all UEs
814 * have been scheduled for uplink (re)transmissions
815 * requiring DL DCI format in the passed subframe.
818 * - For Pucch group power control
819 * - For each TPC-Pucch-RNTI in the pucchGrpPwr List and
820 * TPC-Pusch-RNTI in the puschGrpPwr List,
821 * - Request for PDCCH, skip if not available
822 * - Form DCI format 3/3A information depending
823 * on the format type of the TPC-RNTI and add it to the sub-frame.
824 * - For each Ue in ueLst of TPC RNTI Cb
825 * - if (fmtType == 3A)
826 * - if((Ue not scheduled DL dci formats)
827 * && (remPwr >= 2 || remPwr <= -2))
828 * - Determine TPC. Set puschTpc/pucchTpc.
830 * - if (remPwr >= -1 && remPwr <= 1)
831 * - If already added, remove from toBeSchdLst
833 * - Toggle the remainig power value
834 * - else if (fmtType == 3)
835 * - if((Ue not scheduled DL dci formats)
837 * - Determine TPC. Set puschTpc/pucchTpc.
840 * - If already added, remove from toBeSchdLst
841 * - if (!toBeSchdUeCnt)
842 * - Remove the tpcRntiCb frm pucchGrpPwr/puschGrpPwr List
843 * - else, Move the tpcRntiCb to end of the list (not doing
846 * @param[in] RgSchCellCb *cell
847 * @param[in] RgSchDlSf *dlSf
850 Void rgSCHPwrGrpCntrlPucch(RgSchCellCb *cell,RgSchDlSf *dlSf)
852 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
857 lst = &cellPwr->pucchGrpPwr;
859 while (lnk && ((pdcch = rgSCHCmnCmnPdcchAlloc(cell, dlSf)) != NULLP))
861 RgSchCmnTpcRntiCb *cb = (RgSchCmnTpcRntiCb *)lnk->node;
864 rgSCHPwrSchedPucchRnti(cell, cb, pdcch, dlSf, &sched);
867 rgSCHUtlPdcchPut(cell, &dlSf->pdcchInfo, pdcch);
869 /* TPC RNTI would not have been removed if needs to
870 * be scheduled again */
877 * @brief Handles group power control for DCI formats 3/3A for Pusch and Pusch
881 * Function : rgSCHPwrGrpCntrlPusch
883 * Invoking Module Processing:
884 * - This shall be invoked to do group power control for
885 * all TPC RNTIs for which it is deemed necessary to
886 * do the same (group power control).
887 * - This function should only be invoked after all UEs
888 * have been scheduled for uplink (re)transmissions
889 * requiring DCI format 0 in the passed subframe.
892 * - For Pusch group power control
893 * - For each TPC-Pusch-RNTI in the puschGrpPwr List and
894 * - Request for PDCCH, skip if not available
895 * - Form DCI format 3/3A information depending
896 * on the format type of the TPC-RNTI and add it to the sub-frame.
897 * - For each Ue in ueLst of TPC RNTI Cb
898 * - if (fmtType == 3A)
899 * - if (Ue not scheduled for dci format 0) and
900 * (remPwr >= 2 || remPwr <= -2))
901 * - Determine TPC. Set puschTpc/puschTpc.
903 * - if (remPwr >= -1 && remPwr <= 1)
904 * - If already added, remove from toBeSchdLst
906 * - Toggle the remainig power value
907 * - else if (fmtType == 3)
908 * - if((Ue not scheduled for dci format 0) && (remPwr))
909 * - Determine TPC. Set puschTpc.
912 * - If already added, remove from toBeSchdLst
913 * - if (!toBeSchdUeCnt)
914 * - Remove the tpcRntiCb frm puschGrpPwr/puschGrpPwr List
915 * - else, Move the tpcRntiCb to end of the list (not doing
918 * @param[in] RgSchCellCb *cell
919 * @param[in] RgSchDlSf *sf
922 Void rgSCHPwrGrpCntrlPusch(RgSchCellCb *cell,RgSchDlSf *dlSf,RgSchUlSf *ulSf)
924 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
929 lst = &cellPwr->puschGrpPwr;
931 while (lnk && ((pdcch = rgSCHCmnCmnPdcchAlloc(cell, dlSf)) != NULLP))
933 RgSchCmnTpcRntiCb *cb = (RgSchCmnTpcRntiCb *)lnk->node;
936 rgSCHPwrSchedPuschRnti(cell, cb, pdcch, ulSf, &sched);
939 rgSCHUtlPdcchPut(cell, &dlSf->pdcchInfo, pdcch);
941 /* TPC RNTI would not have been removed if needs to
942 * be scheduled again */
948 /***********************************************************
950 * Func : rgSCHPwrSchedPucchRnti
952 * Desc : Schedule TPC RNTI to be sent out
960 **********************************************************/
961 static Void rgSCHPwrSchedPucchRnti(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchPdcch *pdcch,RgSchDlSf *dlSf,Bool *sched)
970 pdcch->rnti = cb->tpcRnti;
974 /* Go through all UEs for format 3A case */
976 pdcch->dci.dciFormat = TFU_DCI_FORMAT_3A;
977 pdcch->dciNumOfBits = cell->dciSize.size[TFU_DCI_FORMAT_3A];
978 pdcch->dci.u.format3AInfo.isPucch = TRUE;
980 tpcCmds = pdcch->dci.u.format3AInfo.tpcCmd;
981 /* No need to memset zero initially as every TPC is going
982 * to be filled up for every configured UE */
983 for (atleastOne = FALSE, lnk = lst->first; lnk; lnk = lnk->next)
985 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
986 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
988 if ( ue->isDrxEnabled == TRUE &&
989 !RG_SCH_DRX_DL_IS_UE_ACTIVE(ue->drxCb))
991 /* UE is in its DRX time. So we cannot give command
997 if (rgSCHPwrIsDlUeSched(cell, ue, dlSf))
999 /* UE already scheduled in downlink with PDCCH
1000 * carrying PUCCH pwr cmd. So don't care about
1001 * giving command to this UE. */
1004 rgSCHPwrGetPucchFmt3aTpcForUe(ue, &tpc, &delta);
1005 tpcCmds[uePwr->pucchIdx] = tpc;
1007 rgSCHPwrOnPucchGrpPwrForUe(cell, ue, delta);
1012 /* Go through to-be-scheduled UEs for format 3 case */
1013 lst = &cb->toBeSchdUes;
1014 pdcch->dci.dciFormat = TFU_DCI_FORMAT_3;
1015 pdcch->dciNumOfBits = cell->dciSize.size[TFU_DCI_FORMAT_3];
1016 tpcCmds = pdcch->dci.u.format3Info.tpcCmd;
1017 pdcch->dci.u.format3Info.isPucch = TRUE;
1019 /* Fill TPC 1 (corresponding to no power change) initially */
1020 memset(tpcCmds, 1, sizeof(pdcch->dci.u.format3Info.tpcCmd));
1022 for (atleastOne = FALSE, lnk = lst->first; lnk; lnk = lnk->next)
1024 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
1025 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1027 if ( ue->isDrxEnabled == TRUE &&
1028 !RG_SCH_DRX_DL_IS_UE_ACTIVE(ue->drxCb))
1030 /* UE is in its DRX time. So we cannot give command
1036 if (rgSCHPwrIsDlUeSched(cell, ue, dlSf))
1038 /* UE already scheduled in downlink with PDCCH
1039 * carrying PUCCH pwr cmd. So don't care about
1040 * giving command to this UE. */
1043 rgSCHPwrGetPucchFmt3TpcForUe(ue, &tpc, &delta);
1044 tpcCmds[uePwr->pucchIdx] = tpc;
1046 rgSCHPwrOnPucchGrpPwrForUe(cell, ue, delta);
1050 *sched = atleastOne;
1052 /* Check if no more UEs in TPC RNTI, and then remove
1053 * this TPC RNTI from scheduled list */
1054 if (cb->toBeSchdUes.count == 0)
1056 rgSCHPwrRmvSchdPucchTpcRntiCb(cell, cb);
1060 } /* rgSCHPwrSchedPucchRnti */
1062 /***********************************************************
1064 * Func : rgSCHPwrSchedPuschRnti
1066 * Desc : Schedule TPC RNTI to be sent out
1074 **********************************************************/
1075 static Void rgSCHPwrSchedPuschRnti(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchPdcch *pdcch,RgSchUlSf *ulSf,Bool *sched)
1084 pdcch->rnti = cb->tpcRnti;
1088 /* Go through all UEs for format 3A case */
1090 pdcch->dci.dciFormat = TFU_DCI_FORMAT_3A;
1091 pdcch->dciNumOfBits = cell->dciSize.size[TFU_DCI_FORMAT_3A];
1092 pdcch->dci.u.format3AInfo.isPucch = FALSE;
1093 tpcCmds = pdcch->dci.u.format3AInfo.tpcCmd;
1094 /* No need to memset zero initially as every TPC is going
1095 * to be filled up for every configured UE */
1096 for (atleastOne = FALSE, lnk = lst->first; lnk; lnk = lnk->next)
1098 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
1099 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1100 if (rgSCHPwrIsUlUeSched(cell, ue, ulSf))
1102 /* UE already scheduled in uplink with DCI
1103 * format 0. So don't care about giving
1104 * command to this UE. */
1108 if ( ue->isDrxEnabled == TRUE &&
1109 !RG_SCH_DRX_DL_IS_UE_ACTIVE(ue->drxCb))
1111 /* UE is in its DRX time. So we cannot give command
1117 rgSCHPwrGetPuschFmt3aTpcForUe(ue, &tpc, &delta);
1118 tpcCmds[uePwr->puschIdx] = tpc;
1120 rgSCHPwrOnPuschGrpPwrForUe(cell, ue, delta);
1125 /* Go through to-be-scheduled UEs for format 3 case */
1126 lst = &cb->toBeSchdUes;
1127 pdcch->dci.dciFormat = TFU_DCI_FORMAT_3;
1128 pdcch->dciNumOfBits = cell->dciSize.size[TFU_DCI_FORMAT_3];
1129 pdcch->dci.u.format3Info.isPucch = FALSE;
1130 tpcCmds = pdcch->dci.u.format3Info.tpcCmd;
1132 /* Fill TPC 1 (corresponding to no power change) initially */
1133 memset(tpcCmds, 1, sizeof(pdcch->dci.u.format3Info.tpcCmd));
1135 for (atleastOne = FALSE, lnk = lst->first; lnk; lnk = lnk->next)
1137 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
1138 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1139 if (rgSCHPwrIsUlUeSched(cell, ue, ulSf))
1141 /* UE already scheduled in uplink with DCI
1142 * format 0. So don't care about giving
1143 * command to this UE. */
1147 if ( ue->isDrxEnabled == TRUE &&
1148 !RG_SCH_DRX_DL_IS_UE_ACTIVE(ue->drxCb))
1150 /* UE is in its DRX time. So we cannot give command
1156 rgSCHPwrGetPuschFmt3TpcForUe(ue, &tpc, &delta);
1157 tpcCmds[uePwr->puschIdx] = tpc;
1159 rgSCHPwrOnPuschGrpPwrForUe(cell, ue, delta);
1163 *sched = atleastOne;
1165 /* Check if no more UEs in TPC RNTI, and then remove
1166 * this TPC RNTI from scheduled list */
1167 if (cb->toBeSchdUes.count == 0)
1169 rgSCHPwrRmvSchdPuschTpcRntiCb(cell, cb);
1173 } /* rgSCHPwrSchedPuschRnti */
1175 /***********************************************************
1177 * Func : rgSCHPwrGetPucchFmt3TpcForUe
1179 * Desc : Gets 2 bit TPC cmd for PUCCH
1187 **********************************************************/
1188 static Void rgSCHPwrGetPucchFmt3TpcForUe(RgSchUeCb *ue,uint8_t *tpc,S8 *delta)
1190 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1192 rgSCHPwrGetAcc2bitTpc(uePwr->remPucchPwr, tpc, delta);
1194 } /* rgSCHPwrGetPucchFmt3TpcForUe */
1196 /***********************************************************
1198 * Func : rgSCHPwrGetPucchFmt3aTpcForUe
1200 * Desc : Gets 1 bit TPC cmd for PUCCH
1208 **********************************************************/
1209 static Void rgSCHPwrGetPucchFmt3aTpcForUe(RgSchUeCb *ue,uint8_t *tpc,S8 *delta)
1211 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1213 rgSCHPwrGetAcc1bitTpc(uePwr->remPucchPwr, tpc, delta);
1215 } /* rgSCHPwrGetPucchFmt3aTpcForUe */
1217 /***********************************************************
1219 * Func : rgSCHPwrGetPuschFmt3TpcForUe
1221 * Desc : Gets 2 bit TPC cmd for PUCCH
1229 **********************************************************/
1230 static Void rgSCHPwrGetPuschFmt3TpcForUe(RgSchUeCb *ue,uint8_t *tpc,S8 *delta)
1232 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1233 S8 adj = RGSCH_MIN(uePwr->remPuschPwr, uePwr->phVal);
1235 rgSCHPwrGetAcc2bitTpc(adj, tpc, delta);
1237 } /* rgSCHPwrGetPuschFmt3TpcForUe */
1239 /***********************************************************
1241 * Func : rgSCHPwrGetPuschFmt3aTpcForUe
1243 * Desc : Gets 1 bit TPC cmd for PUCCH
1251 **********************************************************/
1252 static Void rgSCHPwrGetPuschFmt3aTpcForUe(RgSchUeCb *ue,uint8_t *tpc,S8 *delta)
1254 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1256 /* Don't attempt to look at headroom now, power
1257 * adjustment is small anyway */
1258 rgSCHPwrGetAcc1bitTpc(uePwr->remPuschPwr, tpc, delta);
1260 } /* rgSCHPwrGetPuschFmt3aTpcForUe */
1262 /***********************************************************
1264 * Func : rgSCHPwrGetAcc1bitTpc
1266 * Desc : Gets 1 bit TPC cmd
1274 **********************************************************/
1275 static Void rgSCHPwrGetAcc1bitTpc(S8 remPwr,uint8_t *tpc,S8 *delta)
1293 } /* rgSCHPwrGetAcc1bitTpc */
1295 /***********************************************************
1297 * Func : rgSCHPwrGetAcc2bitTpc
1299 * Desc : Allocate PDCCH for group power control
1307 **********************************************************/
1308 static Void rgSCHPwrGetAcc2bitTpc(S8 remPwr,uint8_t *tpc,S8 *delta)
1317 uint8_t tpcs[3] = {1, 2, 2};
1318 uint8_t deltas[3] = {0, 1, 1};
1324 else if (remPwr >= 3)
1331 *tpc = tpcs[(uint8_t)remPwr];
1332 *delta = deltas[(uint8_t)remPwr];
1335 } /* rgSCHPwrGetAcc2bitTpc */
1337 /***********************************************************
1339 * Func : rgSCHPwrGetAbsTpc
1341 * Desc : Allocate PDCCH for group power control
1349 **********************************************************/
1350 static Void rgSCHPwrGetAbsTpc(S8 remPwr,uint8_t *tpc,S8 *delta)
1364 else if (remPwr < 1)
1369 else if (remPwr < 4)
1380 } /* rgSCHPwrGetAbsTpc */
1382 /***********************************************************
1384 * Func : rgSCHPwrOnPucchGrpPwrForUe
1386 * Desc : Processing on sending TPC for UE through group power
1387 * control. Apart from updating remPwr, this only takes
1388 * care of possibly removing UE from scheduled
1390 * It does not take care of possibly removing TPC RNTI
1391 * from scheduled list in cell. This is done
1392 * in the caller after TPC for all UEs has been
1393 * determined. (This is where it differs
1394 * from the usual OnSendingPu[cs]ch TPC]
1402 **********************************************************/
1403 static Void rgSCHPwrOnPucchGrpPwrForUe(RgSchCellCb *cell,RgSchUeCb *ue,S8 delta)
1405 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1410 uePwr->remPucchPwr -= delta;
1412 /* UE was already scheduled for PUCCH group power
1413 * control which is why we came here. Don't
1414 * again check for this. */
1416 /* UE was scheduled for pucch grp pwr, sent TPC may
1417 * possibly cause it to be removed. */
1418 if (!uePwr->remPucchPwr)
1424 rgSCHPwrRmvSchdUeOnlyFrmPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb, ue);
1425 /* Not removing TPC RNTI from scheduled list,
1426 * this will happen in the caller once this
1427 * function is called for every UE scheduled. */
1432 /***********************************************************
1434 * Func : rgSCHPwrOnPuschGrpPwrForUe
1436 * Desc : Processing on sending TPC for UE through group power
1437 * control. Apart from updating remPwr, this only takes
1438 * care of possibly removing UE from scheduled
1440 * It does not take care of possibly removing TPC RNTI
1441 * from scheduled list in cell. This is done
1442 * in the caller after TPC for all UEs has been
1443 * determined. (This is where it differs
1444 * from the usual OnSendingPu[cs]ch TPC]
1452 **********************************************************/
1453 static Void rgSCHPwrOnPuschGrpPwrForUe(RgSchCellCb *cell,RgSchUeCb *ue,S8 delta)
1455 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1460 uePwr->delta = delta;
1461 uePwr->remPuschPwr -= delta;
1462 if (uePwr->isPhrAvail)
1464 uePwr->phVal -= uePwr->delta;
1465 uePwr->phVal = RGSCH_MAX(-23, uePwr->phVal);
1468 /* UE was already scheduled for PUSCH group power
1469 * control which is why we came here. Don't
1470 * again check for this. */
1472 /* UE was scheduled for pusch grp pwr, sent TPC may
1473 * possibly cause it to be removed. */
1475 if (!uePwr->remPuschPwr)
1482 rgSCHPwrRmvSchdUeOnlyFrmPuschTpcRntiCb(cell, uePwr->tpcPuschRntiCb, ue);
1483 /* Not removing TPC RNTI from scheduled list,
1484 * this will happen in the caller once this
1485 * function is called for every UE scheduled. */
1490 /***********************************************************
1492 * Func : rgSCHPwrIsDlUeSched
1494 * Desc : Check if UE is scheduled in the passed DL SF
1502 **********************************************************/
1503 static Bool rgSCHPwrIsDlUeSched(RgSchCellCb *cell,RgSchUeCb *ue,RgSchDlSf *sf)
1505 RgSchDlHqEnt *hqEnt = RG_SCH_CMN_GET_UE_HQE(ue, cell);
1506 RgSchDlHqProcCb *proc = rgSCHDhmLastSchedHqProc(hqEnt);
1514 * The following subframe check is assumed enough, since
1515 * scheduled procs stay for a short time (until feedback
1516 * arrives), which typically is expected to have a
1517 * turnaround time of less than 8 subframes. So
1518 * we are probably never going to come across cases
1519 * where a process stays in the list for more than
1520 * 10 subframes, which would have otherwise caused
1521 * the check to succeed for a possibly older process.
1523 if ((proc->tbInfo[0].timingInfo.slot == sf->sfNum) ||
1524 (proc->tbInfo[1].timingInfo.slot == sf->sfNum))
1527 * Later, if a proc can be scheduled without having an
1528 * associated PDCCH, need to also check if PDCCH exists.
1529 * This is because for power, what matters is whether
1530 * TPC is going out for UE at this time or not, at least
1531 * that is what this function was introduced for.
1532 * Checking for PDCCH would have to be in common proc
1533 * the way things are now.
1541 } /* rgSCHPwrIsDlUeSched */
1543 /***********************************************************
1545 * Func : rgSCHPwrIsUlUeSched
1547 * Desc : Check if UE is scheduled in the passed UL SF
1555 **********************************************************/
1556 static Bool rgSCHPwrIsUlUeSched(RgSchCellCb *cell,RgSchUeCb *ue,RgSchUlSf *sf)
1558 RgSchCmnUlCell *cmnCell = RG_SCH_CMN_GET_UL_CELL(cell);
1559 RgSchUlHqProcCb *proc = rgSCHUhmGetUlHqProc(cell, ue, cmnCell->schdHqProcIdx);
1563 #if (ERRCLASS & ERRCLS_DEBUG)
1578 } /* rgSCHPwrIsUlUeSched */
1581 * @brief Handles Pucch power delta indication recieved from PHY
1585 * Function : rgSCHPwrPucchDeltaInd
1587 * Invoking Module Processing:
1588 * - This shall be invoked on reception of Pucch power
1589 * delta indication from PHY.
1592 * - Update the remPucchPwr
1593 * ue->remPucchPwr = pwrDelta
1594 * - If (ue->tpcPucchRntiCb)
1595 * - If (fmtType = 3A)
1596 * - if (remPucchPwr >= 2 || remPucchPwr <= -2 )
1597 * - if (tpcPucchRntiCb is not in the pucchGrpPwr List)
1598 * - Add tpcPucchRntiCb to the pucchGrpPwr list.
1599 * - If not added, add to toBeSchdLst
1601 * - If already added, remove from toBeSchdLst
1602 * - else If (fmtType == 3)
1603 * - if (remPucchPwr)
1604 * - if (tpcPucchRntiCb is not in the pucchGrpPwr List)
1605 * - Add tpcPucchRntiCb to the pucchGrpPwr list.
1606 * - If not added, add to toBeSchdLst
1608 * - If already added, remove from toBeSchdLst
1610 * @param[in] RgSchCellCb *cell
1611 * @param[in] RgSchUeCb *ue
1612 * @param[in] uint8_t pwrDelta
1615 Void rgSCHPwrPucchDeltaInd(RgSchCellCb *cell,RgSchUeCb *ue,S8 pwrDelta)
1617 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1618 RgSchCmnTpcRntiCb *cb;
1621 uePwr->remPucchPwr = pwrDelta;
1623 if ((cb = uePwr->tpcPucchRntiCb) == NULLP)
1630 if (0 != uePwr->remPucchPwr)
1638 rgSCHPwrAddSchdUeToPucchTpcRntiCb(cell, cb, ue);
1642 rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb(cell, cb, ue);
1649 * @brief Does processing after TPC for Pucch has been sent
1653 * Function : rgSCHPwrOnSchedPucchTpc
1655 * Invoking Module Processing:
1656 * - It shall be invoked after it is determined that PDCCH for UE
1657 * is finalised to go out, and thus TPC for PUCCH is being
1661 * - Update remPucchPwr with the delta
1662 * - Do group power control related processing
1664 * @param[in] RgSchCellCb *cell
1665 * @param[in] RgSchUeCb *ue
1666 * @param[in] S8 delta
1669 static Void rgSCHPwrOnSchedPucchTpc(RgSchCellCb *cell,RgSchUeCb *ue,S8 delta)
1671 /* Similar to rgSCHPwrPucchDeltaInd.. not reusing
1672 * that since we use the fact that UE could only have
1673 * improved its remPwr as part of power control. */
1674 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1677 uePwr->remPucchPwr -= delta;
1679 if (uePwr->schdPucchGrpLnk.node == NULLP)
1684 /* UE was scheduled for TPC, sent TPC may
1685 * possibly cause it to be removed. */
1687 if (!uePwr->remPucchPwr)
1694 rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb, ue);
1695 if (uePwr->tpcPucchRntiCb->toBeSchdUes.count == 0)
1697 rgSCHPwrRmvSchdPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb);
1705 * @brief Does processing after TPC for Pusch has been sent
1709 * Function : rgSCHPwrOnSchedPuschTpc
1713 * - Update remPuschPwr with the delta
1714 * - Do group power related processing if applicable
1716 * @param[in] RgSchCellCb *cell
1717 * @param[in] RgSchUeCb *ue
1720 static Void rgSCHPwrOnSchedPuschTpc(RgSchCellCb *cell,RgSchUeCb *ue)
1722 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1725 /* Don't do anything for the case of absolute TPC commands */
1726 if (!uePwr->isAccumulated)
1731 uePwr->remPuschPwr -= uePwr->delta;
1732 if (uePwr->isPhrAvail)
1734 uePwr->phVal -= uePwr->delta;
1735 uePwr->phVal = RGSCH_MAX(-23, uePwr->phVal);
1738 if (uePwr->schdPuschGrpLnk.node == NULLP)
1743 /* UE was scheduled for pusch TPC, sent TPC may
1744 * possibly cause it to be removed. */
1746 if (!uePwr->remPuschPwr)
1753 rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb(cell, uePwr->tpcPuschRntiCb, ue);
1760 * @brief Handles PHR updation for the UE
1764 * Function : rgSCHPwrUpdExtPhr
1765 * @param[in] RgSchCellCb *cell
1766 * @param[in] RgSchUeCb *ue
1767 * @param[in] RgInfExtPhrCEInfo *extPhr
1768 * @param[in] RgSchCmnAllocRecord allocInfo
1771 Void rgSCHPwrUpdExtPhr(RgSchCellCb *cell,RgSchUeCb *ue,RgInfExtPhrCEInfo *extPhr,RgSchCmnAllocRecord *allocInfo)
1774 RgInfExtPhrSCellInfo *servCellPhr;
1777 for (idx = 0; idx < extPhr->numServCells; idx++)
1779 servCellPhr = &extPhr->servCellPhr[idx];
1781 if (RG_SCH_REF_PCMAX == servCellPhr->pCmax)
1783 pCMax = RG_SCH_CMN_PWR_USE_CFG_MAX_PWR;
1787 pCMax = rgSCHPwrGetPCMaxValFromPCMax(servCellPhr->pCmax);
1789 rgSCHPwrUpdPhr(ue->cellInfo[servCellPhr->sCellIdx]->cell,
1790 ue, servCellPhr->phr, allocInfo, pCMax);
1796 * @brief Handles PHR updation for the UE
1800 * Function : rgSCHPwrUpdPhr
1802 * Invoking Module Processing:
1803 * - This shall be invoked on reception of PHR from MAC to SCH. It shall
1804 * pass the information of number of RBs, coding efficiency and TPC for
1805 * the Pusch transmission for which PHR has been reported.
1808 * - Compute power per RB using the PHR report
1809 * - ue_transmit_pwr = ue_max_pwr - PHR
1810 * - if isDeltaMcs = TRUE
1811 * - ue_transmit_pwr -
1812 * [10log(phr_num_rb) + 10log(2^ (1.25 * phr_coding_effeciency) -1)
1813 * + phr_tpc(if absolute TPC)] = pwrPerRB
1815 * - ue_transmit_pwr - [10log(phr_num_rb) + phr_tpc(if absolute TPC)]
1817 * (Use the number of RBs and efficiency used by UE which caused the PHR
1819 * - Adjust PHR according to last allocation (take into account
1820 * number of RBs granted in the last allocation)
1821 * - Update the PHR report in the control block
1822 * - Set isPhrAvail = TRUE
1823 * - Do group power control related processing if applicable
1825 * @param[in] RgSchCellCb *cell
1826 * @param[in] RgSchUeCb *ue
1827 * @param[in] uint8_t phr
1828 * @param[in] RgSchCmnAllocRecord allocInfo
1829 * @param[in] uint8_t maxUePwr
1832 Void rgSCHPwrUpdPhr(RgSchCellCb *cell,RgSchUeCb *ue,uint8_t phr,RgSchCmnAllocRecord *allocInfo,S8 maxUePwr )
1834 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1837 RgSchCmnUlCell *cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
1839 uePwr->phVal = rgSCHPwrGetPhValFromPhr(phr);
1841 if (maxUePwr == RG_SCH_CMN_PWR_USE_CFG_MAX_PWR)
1843 maxUePwr = uePwr->maxUePwr;
1845 rbPwr = rgSCHPwrRbToPwr(cell,allocInfo->numRb);
1846 effPwr = rgSCHPwrGetCqiPwrForUe(cell, ue, allocInfo->cqi);
1847 uePwr->pwrPerRb = maxUePwr - uePwr->phVal - rbPwr - effPwr;
1848 /*if (!uePwr->isAccumulated)
1850 uePwr->pwrPerRb -= rgSCHPwrGetDeltaFrmAbsTpc(allocInfo->tpc);
1853 /* Let headroom reflect remaining power according to last
1854 * allocated number of RBs. Intermediate TPCs not yet
1855 * taken care of (for accumulated case, it is anyway
1856 * not applicable for absolute commands). */
1857 uePwr->phVal -= (rgSCHPwrRbToPwr(cell, cellUl->sbSize)) - rbPwr;
1858 uePwr->phVal = RGSCH_MAX(-23, uePwr->phVal);
1859 uePwr->isPhrAvail = TRUE;
1861 rgSCHPwrOnPuschPwrUpd(cell, ue);
1863 RLOG_ARG4(L_DEBUG,DBG_UEID,ue->ueId,
1864 "Output: Reported PHR[%d] cqi[%u] allocRb[%u] uePwr->pwrPerRb[%d]",
1873 * @brief Handles UL CQI indication
1877 * Function : rgSCHPwrUlCqiInd
1879 * Invoking Module Processing:
1880 * - This shall be invoked when uplink CQI indication
1881 * is receiving from PHY for a UE.
1884 * - Update remPuschPwr.
1885 * - Possibly schedule for group power control.
1887 * @param[in] RgSchCellCb *cell
1888 * @param[in] RgSchUeCb *ue
1889 * @param[in] uint8_t numRb
1892 Void rgSCHPwrUlCqiInd(RgSchCellCb *cell,RgSchUeCb *ue)
1894 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
1895 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1901 * For absolute power cmd case, we could look at the time
1902 * at which CQI was received, determine if there was a
1903 * PUSCH TPC cmd for that time (this could come from
1904 * group power control too), and (if this
1905 * CQI report is indeed based on the the PUSCH tx)
1906 * then factor in that cmd here. Not doing
1910 /* See how much power needs to be adjusted based on cqi
1912 uePwr->remPuschPwr =
1914 rgSCHPwrGetDelta2FrmCqi(ueUl->validUlCqi, uePwr->trgCqi, ue, cell);
1916 rgSCHPwrGetDelta2FrmCqi(ueUl->crntUlCqi[0], uePwr->trgCqi, ue, cell);
1919 rgSCHPwrOnPuschPwrUpd(cell, ue);
1921 if(uePwr->maxPwrDeltaByPhr < 0)
1923 tmp = ueUl->validUlCqi;
1924 tmp = tmp + uePwr->maxPwrDeltaByPhr;
1927 ueUl->validUlCqi = 1;
1931 ueUl->validUlCqi = tmp;
1940 * @brief Updates the stored last number of RBs allocated
1944 * Function : rgSCHPwrRecordRbAlloc
1946 * Invoking Module Processing:
1947 * - This shall be invoked when uplink allocation is made for
1949 * - Note: If outstanding TPCs are considered at the time
1950 * of PHR report, the last numRb would also be known
1951 * and then this API would not be needed.
1954 * - Adjust PHR according to now allocated number of RBs
1955 * - Store the number of RBs
1957 * @param[in] RgSchCellCb *cell
1958 * @param[in] RgSchUeCb *ue
1959 * @param[in] uint8_t numRb
1962 Void rgSCHPwrRecordRbAlloc(RgSchCellCb *cell,RgSchUeCb *ue,uint8_t numRb)
1964 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1968 if (uePwr->isPhrAvail)
1970 uePwr->phVal += rgSCHPwrRbToPwr(cell,numRb) - rgSCHPwrRbToPwr(cell,uePwr->numRb);
1971 uePwr->phVal = RGSCH_MIN(40, uePwr->phVal);
1973 uePwr->numRb = numRb;
1978 * @brief Handles power related configuration for a cell
1982 * Function : rgSCHPwrCellCfg
1984 * Invoking Module Processing:
1985 * - This shall be invoked during cell config
1990 * - Update TPC-RNTI information for the cell for Pucch and Pusch.
1991 * - For each TPC-Pucch-RNTI,
1992 * - Call rgSCHAddRntiToPucchRntiLst()
1993 * - For each TPC-Pusch-RNTI,
1994 * - Call rgSCHAddRntiToPuschRntiLst()
1997 * @param[in] RgSchCellCb *cell
1998 * @param[in] RgrCellCfg *cfg
2003 S16 rgSCHPwrCellCfg(RgSchCellCb *cell,RgrCellCfg *cfg)
2005 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2007 CmLteRnti startRnti;
2011 /* Right now, all UEs have fixed maximum power capability. So
2012 * we store cell wide pMax as minimum of configured pMax and
2014 cellPwr->pMax = RGSCH_MIN(cfg->pMax, RG_SCH_PWR_UE_MAX_PWR);
2016 /* trgUlCqi already validated by common */
2017 cellPwr->trgUlCqi = cfg->trgUlCqi.trgCqi;
2019 /* Validate number of TPC RNTIs */
2020 if ((cfg->pwrCfg.pucchPwrFmt3.size + cfg->pwrCfg.pucchPwrFmt3a.size
2021 > RG_SCH_CMN_MAX_NUM_TPC_PUCCH_RNTI)
2022 || (cfg->pwrCfg.puschPwrFmt3.size + cfg->pwrCfg.puschPwrFmt3a.size
2023 > RG_SCH_CMN_MAX_NUM_TPC_PUSCH_RNTI))
2028 /* Now initialise TPC RNTIs */
2030 /* Format 3 Pucch TPC RNTIs */
2032 startRnti = cfg->pwrCfg.pucchPwrFmt3.startTpcRnti;
2033 size = cfg->pwrCfg.pucchPwrFmt3.size;
2034 for (rnti = startRnti; (rnti < startRnti + size); ++rnti)
2036 rgSCHPwrAddRntiToPucchRntiLst(cell, rnti, isFmt3a);
2039 /* Format 3A Pucch TPC RNTIs */
2041 startRnti = cfg->pwrCfg.pucchPwrFmt3a.startTpcRnti;
2042 size = cfg->pwrCfg.pucchPwrFmt3a.size;
2043 for (rnti = startRnti; (rnti < startRnti + size); ++rnti)
2045 rgSCHPwrAddRntiToPucchRntiLst(cell, rnti, isFmt3a);
2048 /* Format 3 Pusch TPC RNTIs */
2050 startRnti = cfg->pwrCfg.puschPwrFmt3.startTpcRnti;
2051 size = cfg->pwrCfg.puschPwrFmt3.size;
2052 for (rnti = startRnti; (rnti < startRnti + size); ++rnti)
2054 rgSCHPwrAddRntiToPuschRntiLst(cell, rnti, isFmt3a);
2057 /* Format 3A Pusch TPC RNTIs */
2059 startRnti = cfg->pwrCfg.puschPwrFmt3a.startTpcRnti;
2060 size = cfg->pwrCfg.puschPwrFmt3a.size;
2061 for (rnti = startRnti; (rnti < startRnti + size); ++rnti)
2063 rgSCHPwrAddRntiToPuschRntiLst(cell, rnti, isFmt3a);
2070 * @brief Handles power related re-configuration for a cell
2074 * Function : rgSCHPwrCellRecfg
2079 * @param[in] RgSchCellCb *cell
2080 * @param[in] RgrCellRecfg *recfg
2084 S16 rgSCHPwrCellRecfg(RgSchCellCb *cell,RgrCellRecfg *recfg)
2089 /* Not doing anything for power reconfig, so such structure
2095 * @brief Frees power related data structures in cell
2099 * Function : rgSCHPwrCellDel
2104 * @param[in] RgSchCellCb *cell
2107 Void rgSCHPwrCellDel(RgSchCellCb *cell)
2111 /* There is no allocated memory, so do nothing */
2118 * @brief Configures ULPC CB for a SCELL being added
2122 * Function : rgSCHPwrUeSCellCfg
2124 * @param[in] RgSchCellCb *cell
2125 * @param[in] RgSchUeCb *ue
2126 * @param[in] RgrUeCfg *cfg
2131 S16 rgSCHPwrUeSCellCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeSecCellCfg *sCellInfoCfg)
2133 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2134 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2135 RgSchCmnUeUlPwrCb *uePwrPCell = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2136 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
2138 RgSchCmnUlCell *cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
2141 uePwr->maxUePwr = cellPwr->pMax;
2142 uePwr->trgCqi = cellPwr->trgUlCqi; /* Overriding with UE's happens later */
2145 uePwr->maxPwrPerRb = uePwr->maxUePwr - rgSchPwrRbToPwrTbl[cellUl->sbSize];
2147 uePwr->isPhrAvail = FALSE;
2149 uePwr->maxUlRbs = RGSCH_MAX_DL_BW;
2151 uePwr->puschTpc = 1;
2152 uePwr->remPuschPwr = 0;
2154 /* Rest of the vars update and group power control related
2155 * config happens in the function below */
2156 uePwr->isAccumulated = sCellInfoCfg->ueSCellUlDedPwrCfg.isAccumulated;
2157 uePwr->deltaMcsEnbld = sCellInfoCfg->ueSCellUlDedPwrCfg.isDeltaMCSEnabled;
2159 uePwr->trgCqi = uePwrPCell->trgCqi;
2161 if (ueUl->maxUlCqi < uePwr->trgCqi)
2163 uePwr->trgCqi = ueUl->maxUlCqi;
2165 uePwr->p0UePusch = sCellInfoCfg->ueSCellUlDedPwrCfg.p0UePusch;
2172 * @brief Handles power related configuration for a UE
2176 * Function : rgSCHPwrUeCfg
2179 * - If Pusch group power configuration exists && accumulation enabled,
2180 * - Fetch the TPC-Pusch-RNTI control block for the configured
2181 * TPC-Pusch-RNTI. Call rgSCHGetRntiFrmPuschRntiLst(). If it does not
2182 * exist, return RFAILED.
2183 * - Add Ue to the ueLst of TPC-Pusch-RNTI control block.
2184 * - Update tpcPuschRntiCb pointer in UE.
2185 * - Update the puschIdx value.
2186 * - If Pucch group power configuration exists && accumulation enabled,
2187 * - Fetch the TPC-Pucch-RNTI control block for the configured
2188 * TPC-Pucch-RNTI. Call rgSCHGetRntiFrmPucchRntiLst(). If it does not
2189 * exist, return RFAILED.
2190 * - Add Ue to the ueLst of TPC-Pucch-RNTI control block.
2191 * - Update tpcPucchRntiCb pointer in UE.
2192 * - Update the pucchIdx value.
2193 * - Update isAccumulated and isDeltaMcs variables.
2194 * - maxUlRbs = configured maximum UL bandwidth value per UE.
2195 * - trgUlCqi = configured value, if any, else cell-wide default trg CQI value.
2196 * - If format type is format 3A, update remaining power to +1
2197 * - Update TPC-RNTI information for the cell for Pucch and Pusch.
2200 * @param[in] RgSchCellCb *cell
2201 * @param[in] RgSchUeCb *ue
2202 * @param[in] RgrUeCfg *cfg
2207 S16 rgSCHPwrUeCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeCfg *cfg)
2210 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2211 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2213 RgSchCmnUlCell *cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
2215 uePwr->maxUePwr = cellPwr->pMax;
2216 uePwr->trgCqi = cellPwr->trgUlCqi; /* Overriding with UE's happens later */
2219 uePwr->maxPwrPerRb = uePwr->maxUePwr - rgSchPwrRbToPwrTbl[cellUl->sbSize];
2221 rgSCHPwrUeResetPucch(cell, ue);
2222 rgSCHPwrUeResetPusch(cell, ue);
2224 /* Rest of the vars update and group power control related
2225 * config happens in the function below */
2226 ret = rgSCHPwrApplyUePwrCfg(cell, ue, &cfg->ueUlPwrCfg);
2232 * @brief Handles power related re-configuration for a UE
2236 * Function : rgSCHPwrUeRecfg
2238 * Invoking Module Processing:
2239 * - This shall be invoked by SCH_GOM at UE re-configuration.
2242 * - If change in TPC-RNTI, update the pointer and the TPC RNTI Cb appropriately.
2243 * - If accumulation disabled, remove the UE from TPC-RNTI lists of UE, if
2245 * - If group power configuration disabled, remove the UE from TPC-RNTI lists of UE, if
2248 * @param[in] RgSchCellCb *cell
2249 * @param[in] RgSchUeCb *ue
2250 * @param[in] RgrUeRecfg *recfg
2256 S16 rgSCHPwrUeRecfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeRecfg *recfg)
2259 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2260 RgrUeUlPwrCfg *pwrCfg = &recfg->ueUlPwrRecfg;
2262 if (pwrCfg->p0UePucch != uePwr->p0UePucch)
2264 rgSCHPwrUeResetPucch(cell, ue);
2266 if ((pwrCfg->isAccumulated != uePwr->isAccumulated)
2267 || (pwrCfg->p0UePusch != uePwr->p0UePusch))
2269 rgSCHPwrUeResetPusch(cell, ue);
2271 ret = rgSCHPwrApplyUePwrCfg(cell, ue, &recfg->ueUlPwrRecfg);
2276 /***********************************************************
2278 * Func : rgSCHPwrApplyUePwrCfg
2280 * Desc : Applies power config for UE. Meants to be
2281 * used during both power config and reconfig.
2289 **********************************************************/
2290 static S16 rgSCHPwrApplyUePwrCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeUlPwrCfg *pwrCfg)
2293 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
2294 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2295 RgSchCmnTpcRntiCb *pucchRntiCb = NULLP;
2296 RgSchCmnTpcRntiCb *puschRntiCb = NULLP;
2297 uint8_t pucchIdx = 0;
2298 uint8_t puschIdx = 0;
2300 /* Validate Pucch group power control config */
2301 if (pwrCfg->uePucchPwr.pres)
2304 rgSCHPwrGetPucchRntiCb(cell, pwrCfg->uePucchPwr.tpcRnti);
2305 if (pucchRntiCb == NULLP)
2309 pucchIdx = pwrCfg->uePucchPwr.idx;
2310 ret = rgSCHPwrChkPucchTpcRntiIdx(pucchRntiCb, pucchIdx);
2317 /* Validate Pusch group power control config */
2318 if (pwrCfg->uePuschPwr.pres)
2321 rgSCHPwrGetPuschRntiCb(cell, pwrCfg->uePuschPwr.tpcRnti);
2322 if (puschRntiCb == NULLP)
2326 puschIdx = pwrCfg->uePuschPwr.idx;
2327 ret = rgSCHPwrChkPuschTpcRntiIdx(puschRntiCb, puschIdx);
2334 /* Apply Pucch group power control config */
2337 if (uePwr->tpcPucchRntiCb != pucchRntiCb) /* This part for recfg */
2339 if (uePwr->tpcPucchRntiCb)
2341 rgSCHPwrDelUeFrmPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb, ue);
2343 uePwr->tpcPucchRntiCb = pucchRntiCb;
2344 rgSCHPwrAddUeToPucchTpcRntiCb(cell, pucchRntiCb, ue);
2346 uePwr->pucchIdx = pucchIdx;
2348 RLOG_ARG4(L_UNUSED,DBG_CELLID,cell->cellId,
2349 "<GRP_PWR>PucchRntiCb cfgdUes(%ld %lu %lu) UEID:%d",
2350 pucchRntiCb->cfgdUes.count,((uint32_t)pucchRntiCb->cfgdUes.first),
2351 ((uint32_t)pucchRntiCb->cfgdUes.last),ue->ueId);
2352 RLOG_ARG3(L_UNUSED,DBG_CELLID,cell->cellId,
2353 "UEID:%d isFmt3a(%u) ueNode(%ld)",
2354 ue->ueId,pucchRntiCb->isFmt3a,
2355 pucchRntiCb->schdLnk.node);
2356 RLOG_ARG4(L_UNUSED,DBG_CELLID,cell->cellId,
2357 "toBeSchdUes(%ld %lu %lu) tpcRnti(%u)",
2358 pucchRntiCb->toBeSchdUes.count,
2359 ((uint32_t)pucchRntiCb->toBeSchdUes.first),
2360 ((uint32_t)pucchRntiCb->toBeSchdUes.last),
2361 pucchRntiCb->tpcRnti);
2363 RLOG_ARG4(L_UNUSED,DBG_CELLID,cell->cellId,
2364 "<GRP_PWR>PucchRntiCb cfgdUes(%ld %lu %lu) UEID:%d",
2365 pucchRntiCb->cfgdUes.count,((uint64_t)pucchRntiCb->cfgdUes.first),
2366 ((uint64_t)pucchRntiCb->cfgdUes.last),ue->ueId);
2367 RLOG_ARG3(L_UNUSED,DBG_CELLID,cell->cellId,
2368 "UEID:%d isFmt3a(%u) ueNode(%ld)",
2369 ue->ueId,pucchRntiCb->isFmt3a,
2370 pucchRntiCb->schdLnk.node);
2371 RLOG_ARG4(L_UNUSED,DBG_CELLID,cell->cellId,
2372 "toBeSchdUes(%ld %lu %lu) tpcRnti(%u)",
2373 pucchRntiCb->toBeSchdUes.count,
2374 ((uint64_t)pucchRntiCb->toBeSchdUes.first),
2375 ((uint64_t)pucchRntiCb->toBeSchdUes.last),
2376 pucchRntiCb->tpcRnti);
2381 /* Apply Pusch group power control config */
2384 if (uePwr->tpcPuschRntiCb != puschRntiCb) /* This part for recfg */
2386 if (uePwr->tpcPuschRntiCb)
2388 rgSCHPwrDelUeFrmPuschTpcRntiCb(cell, uePwr->tpcPuschRntiCb, ue);
2390 uePwr->tpcPuschRntiCb = puschRntiCb;
2391 rgSCHPwrAddUeToPuschTpcRntiCb(puschRntiCb, ue);
2393 uePwr->puschIdx = puschIdx;
2397 uePwr->isAccumulated = pwrCfg->isAccumulated;
2398 uePwr->deltaMcsEnbld = pwrCfg->isDeltaMCSEnabled;
2401 uePwr->trgCqi = pwrCfg->trgCqi;
2403 if (ueUl->maxUlCqi < uePwr->trgCqi)
2405 uePwr->trgCqi = ueUl->maxUlCqi;
2407 uePwr->p0UePusch = pwrCfg->p0UePusch;
2408 uePwr->p0UePucch = pwrCfg->p0UePucch;
2415 * @brief Deletes power related information for UE
2419 * Function : rgSCHPwrUeDel
2421 * Invoking Module Processing:
2422 * - This shall be invoked by at the time of UE deletion.
2425 * - if (ue->tpcPucchRntiCb)
2426 * - delete UE from tpcPucchRntiCb->ueLst
2427 * - ue->tpcPucchRntiCb = NULLP
2428 * - If in (ue->tpcPucchRntiCb->toBeSchdLst)
2429 * - remove from the list.
2430 * - if (ue->tpcPuschRntiCb)
2431 * - delete UE from tpcPuschRntiCb->ueLst
2432 * - ue->tpcPuschRntiCb = NULLP
2433 * - If in (ue->tpcPuschRntiCb->toBeSchdLst)
2434 * - remove from the list.
2436 * @param[in] RgSchCellCb *cell
2437 * @param[in] RgSchUeCb *ue
2440 Void rgSCHPwrUeDel(RgSchCellCb *cell,RgSchUeCb *ue)
2442 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2444 if (uePwr->tpcPucchRntiCb)
2446 rgSCHPwrDelUeFrmPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb, ue);
2447 uePwr->tpcPucchRntiCb = NULLP;
2449 if (uePwr->tpcPuschRntiCb)
2451 rgSCHPwrDelUeFrmPuschTpcRntiCb(cell, uePwr->tpcPuschRntiCb, ue);
2452 uePwr->tpcPuschRntiCb = NULLP;
2458 * @brief Resets UE's power state
2462 * Function : rgSCHPwrUeReset
2464 * Invoking Module Processing:
2465 * - This shall be invoked by at the time PDCCH order.
2468 * - Reset PUSCH power state
2469 * - Reset PUCCH power state
2471 * @param[in] RgSchCellCb *cell
2472 * @param[in] RgSchUeCb *ue
2475 Void rgSCHPwrUeReset(RgSchCellCb *cell,RgSchUeCb *ue)
2478 rgSCHPwrUeResetPucch(cell, ue);
2479 rgSCHPwrUeResetPusch(cell, ue);
2483 /***********************************************************
2485 * Func : rgSCHPwrUeResetPucch
2487 * Desc : This function is called to reset UE
2488 * to initial PUCCH power state.
2496 **********************************************************/
2497 static Void rgSCHPwrUeResetPucch(RgSchCellCb *cell,RgSchUeCb *ue)
2499 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2501 uePwr->pucchTpc = 1;
2502 uePwr->remPucchPwr = 0;
2503 if (uePwr->tpcPucchRntiCb)
2505 rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb, ue);
2508 /* Stack Crash problem for TRACE5 changes. Added the line below */
2513 /***********************************************************
2515 * Func : rgSCHPwrUeResetPusch
2517 * Desc : This function is called to reset UE
2518 * to initial PUSCH power state.
2526 **********************************************************/
2527 static Void rgSCHPwrUeResetPusch(RgSchCellCb *cell,RgSchUeCb *ue)
2529 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2531 uePwr->isPhrAvail = FALSE;
2533 uePwr->maxUlRbs = RGSCH_MAX_DL_BW;
2535 uePwr->puschTpc = 1;
2536 uePwr->remPuschPwr = 0;
2537 if (uePwr->tpcPuschRntiCb)
2539 rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb(cell, uePwr->tpcPuschRntiCb, ue);
2544 /***********************************************************
2546 * Func : rgSCHPwrOnPuschPwrUpd
2548 * Desc : This function is called whenever 'remPuschPwr'
2557 **********************************************************/
2558 static Void rgSCHPwrOnPuschPwrUpd(RgSchCellCb *cell,RgSchUeCb *ue)
2560 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2561 RgSchCmnTpcRntiCb *cb;
2564 if ((cb = uePwr->tpcPuschRntiCb) == NULLP)
2569 /* Not checking for uwPwr->isPhrAvail as uePwr->phVal
2570 * is set to a large value initially */
2574 if ((uePwr->phVal != 0) && (uePwr->remPuschPwr != 0))
2582 rgSCHPwrAddSchdUeToPuschTpcRntiCb(cell, cb, ue);
2586 rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb(cell, cb, ue);
2593 /***********************************************************
2595 * Func : rgSCHPwrAddRntiToPucchRntiLst
2598 * Desc : Adds RNTI to Pucch Rnti list and updates requisite
2603 * Notes: Assumed that array bounds are checked
2604 * in caller before adding.
2608 **********************************************************/
2609 static Void rgSCHPwrAddRntiToPucchRntiLst(RgSchCellCb *cell,CmLteRnti rnti,Bool isFmt3a)
2611 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2613 rgSCHPwrInitTpcRntiCb(&cellPwr->tpcPucchRntiLst[cellPwr->tpcPucchRntiCnt++],
2618 /***********************************************************
2620 * Func : rgSCHPwrAddRntiToPuschRntiLst
2623 * Desc : Adds RNTI to Pusch Rnti list and updates requisite
2628 * Notes: Assumed that array bounds are checked
2629 * in caller before adding.
2633 **********************************************************/
2634 static Void rgSCHPwrAddRntiToPuschRntiLst(RgSchCellCb *cell,CmLteRnti rnti,Bool isFmt3a)
2636 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2638 rgSCHPwrInitTpcRntiCb(&cellPwr->tpcPuschRntiLst[cellPwr->tpcPuschRntiCnt++],
2643 /***********************************************************
2645 * Func : rgSCHPwrInitTpcRntiCb
2648 * Desc : Initialises a TPC RNTI CB
2656 **********************************************************/
2657 static Void rgSCHPwrInitTpcRntiCb(RgSchCmnTpcRntiCb *cb,CmLteRnti rnti,Bool isFmt3a)
2660 memset(cb, 0, sizeof(*cb));
2662 cb->isFmt3a = isFmt3a;
2663 /* Not initialising lists as memset 0 takes care of it */
2664 /* cb->schdLnk.node is set when this rnti is to be scheduled */
2668 /***********************************************************
2670 * Func : rgSCHPwrGetPucchRntiCb
2673 * Desc : Gets TPC RNTI control block from Pucch rnti list
2675 * Ret : RgSchCmnTpcRntiCb * - Success
2682 **********************************************************/
2683 static RgSchCmnTpcRntiCb* rgSCHPwrGetPucchRntiCb(RgSchCellCb *cell,CmLteRnti tpcRnti)
2685 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2688 if (!cellPwr->tpcPucchRntiCnt)
2692 for (idx = 0; idx < cellPwr->tpcPucchRntiCnt; ++idx)
2694 if (cellPwr->tpcPucchRntiLst[idx].tpcRnti == tpcRnti)
2696 return (&cellPwr->tpcPucchRntiLst[idx]);
2702 /***********************************************************
2704 * Func : rgSCHPwrGetPuschRntiCb
2707 * Desc : Gets TPC RNTI control block from Pusch rnti list
2709 * Ret : RgSchCmnTpcRntiCb * - Success
2716 **********************************************************/
2717 static RgSchCmnTpcRntiCb* rgSCHPwrGetPuschRntiCb(RgSchCellCb *cell,CmLteRnti tpcRnti)
2719 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2722 if (!cellPwr->tpcPuschRntiCnt)
2726 for (idx = 0; idx < cellPwr->tpcPuschRntiCnt; ++idx)
2728 if (cellPwr->tpcPuschRntiLst[idx].tpcRnti == tpcRnti)
2730 return (&cellPwr->tpcPuschRntiLst[idx]);
2737 /***********************************************************
2739 * Func : rgSCHPwrAddUeToPucchTpcRntiCb
2742 * Desc : Add UE to cfgd list of UEs in rnti cb
2750 **********************************************************/
2751 static Void rgSCHPwrAddUeToPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2753 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2756 cmLListAdd2Tail(&cb->cfgdUes, &uePwr->pucchGrpLnk);
2757 uePwr->pucchGrpLnk.node = (PTR)ue;
2761 /***********************************************************
2763 * Func : rgSCHPwrDelUeFrmPucchTpcRntiCb
2766 * Desc : Remove UE from Pucch TPC RNTI CB
2774 **********************************************************/
2775 static Void rgSCHPwrDelUeFrmPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2777 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2779 rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb(cell, cb, ue);
2780 cmLListDelFrm(&cb->cfgdUes, &uePwr->pucchGrpLnk);
2781 uePwr->pucchGrpLnk.node = NULLP;
2785 /***********************************************************
2787 * Func : rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb
2790 * Desc : Remove UE from to-be-scheduled list of UEs
2799 **********************************************************/
2800 static Void rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2802 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2804 if (uePwr->schdPucchGrpLnk.node == NULLP)
2808 rgSCHPwrRmvSchdUeOnlyFrmPucchTpcRntiCb(cell, cb, ue);
2809 if (!cb->toBeSchdUes.count)
2811 rgSCHPwrRmvSchdPucchTpcRntiCb(cell, cb);
2816 /***********************************************************
2818 * Func : rgSCHPwrRmvSchdUeOnlyFrmPucchTpcRntiCb
2820 * Desc : Remove UE from to-be-scheduled list of UEs
2821 * in Pucch RNTI CB. Do not both about
2822 * possibly removing Pucch RNTI CB from
2823 * the cell wide to-be-scheduled list.
2831 **********************************************************/
2832 static Void rgSCHPwrRmvSchdUeOnlyFrmPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2834 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2836 if (uePwr->schdPucchGrpLnk.node != NULLP)
2838 cmLListDelFrm(&cb->toBeSchdUes, &uePwr->schdPucchGrpLnk);
2839 uePwr->schdPucchGrpLnk.node = NULLP;
2844 /***********************************************************
2846 * Func : rgSCHPwrRmvSchdPucchTpcRntiCb
2848 * Desc : Remove Pucch TPC RNTI CB from to-be-scheduled
2857 **********************************************************/
2858 static Void rgSCHPwrRmvSchdPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb)
2860 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2862 if (cb->schdLnk.node == NULLP)
2866 cmLListDelFrm(&cellPwr->pucchGrpPwr, &cb->schdLnk);
2867 cb->schdLnk.node = NULLP;
2871 /***********************************************************
2873 * Func : rgSCHPwrAddSchdUeToPucchTpcRntiCb
2875 * Desc : Add UE to to-be-scheduled list of UEs
2884 **********************************************************/
2885 static Void rgSCHPwrAddSchdUeToPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2887 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2889 if (uePwr->schdPucchGrpLnk.node != NULLP)
2891 /* UE is already in the list */
2894 cmLListAdd2Tail(&cb->toBeSchdUes, &uePwr->schdPucchGrpLnk);
2895 uePwr->schdPucchGrpLnk.node = (PTR)ue;
2896 if (cb->toBeSchdUes.count == 1)
2898 /* This is first UE, so queue up this TPC RNTI
2900 rgSCHPwrAddSchdPucchTpcRntiCb(cell, cb);
2905 /***********************************************************
2907 * Func : rgSCHPwrAddSchdPucchTpcRntiCb
2909 * Desc : Add Pucch TPC RNTI CB from to-be-scheduled
2918 **********************************************************/
2919 static Void rgSCHPwrAddSchdPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb)
2921 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2923 cmLListAdd2Tail(&cellPwr->pucchGrpPwr, &cb->schdLnk);
2924 cb->schdLnk.node = (PTR)cb;
2929 /***********************************************************
2931 * Func : rgSCHPwrAddUeToPuschTpcRntiCb
2934 * Desc : Add UE to cfgd list of UEs in rnti cb
2942 **********************************************************/
2943 static Void rgSCHPwrAddUeToPuschTpcRntiCb(RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2945 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2947 cmLListAdd2Tail(&cb->cfgdUes, &uePwr->puschGrpLnk);
2948 uePwr->puschGrpLnk.node = (PTR)ue;
2952 /***********************************************************
2954 * Func : rgSCHPwrAddSchdUeToPuschTpcRntiCb
2956 * Desc : Add UE to to-be-scheduled list of UEs
2965 **********************************************************/
2966 static Void rgSCHPwrAddSchdUeToPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2968 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2970 if (uePwr->schdPuschGrpLnk.node != NULLP)
2972 /* UE is already in the list */
2975 cmLListAdd2Tail(&cb->toBeSchdUes, &uePwr->schdPuschGrpLnk);
2976 uePwr->schdPuschGrpLnk.node = (PTR)ue;
2977 if (cb->toBeSchdUes.count == 1)
2979 /* This is first UE, so queue up this TPC RNTI
2981 rgSCHPwrAddSchdPuschTpcRntiCb(cell, cb);
2986 /***********************************************************
2988 * Func : rgSCHPwrDelUeFrmPuschTpcRntiCb
2991 * Desc : Add UE to cfgd list of UEs in rnti cb
2999 **********************************************************/
3000 static Void rgSCHPwrDelUeFrmPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
3002 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
3004 rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb(cell, cb, ue);
3005 cmLListDelFrm(&cb->cfgdUes, &uePwr->puschGrpLnk);
3006 uePwr->puschGrpLnk.node = NULLP;
3010 /***********************************************************
3012 * Func : rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb
3014 * Desc : Remove UE from to-be-scheduled list of UEs
3023 **********************************************************/
3024 static Void rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
3026 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
3028 if (uePwr->schdPuschGrpLnk.node == NULLP)
3032 rgSCHPwrRmvSchdUeOnlyFrmPuschTpcRntiCb(cell, cb, ue);
3033 if (!cb->toBeSchdUes.count)
3035 rgSCHPwrRmvSchdPuschTpcRntiCb(cell, cb);
3040 /***********************************************************
3042 * Func : rgSCHPwrRmvSchdUeOnlyFrmPuschTpcRntiCb
3044 * Desc : Remove UE from to-be-scheduled list of UEs
3045 * in Pusch RNTI CB. Do not both about
3046 * possibly removing Pusch RNTI CB from
3047 * the cell wide to-be-scheduled list.
3055 **********************************************************/
3056 static Void rgSCHPwrRmvSchdUeOnlyFrmPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
3058 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
3060 if (uePwr->schdPuschGrpLnk.node != NULLP)
3062 cmLListDelFrm(&cb->toBeSchdUes, &uePwr->schdPuschGrpLnk);
3063 uePwr->schdPuschGrpLnk.node = NULLP;
3068 /***********************************************************
3070 * Func : rgSCHPwrAddSchdPuschTpcRntiCb
3072 * Desc : Add Pusch TPC RNTI CB from to-be-scheduled
3081 **********************************************************/
3082 static Void rgSCHPwrAddSchdPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb)
3084 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
3086 cmLListAdd2Tail(&cellPwr->puschGrpPwr, &cb->schdLnk);
3087 cb->schdLnk.node = (PTR)cb;
3091 /***********************************************************
3093 * Func : rgSCHPwrRmvSchdPuschTpcRntiCb
3095 * Desc : Remove Pusch TPC RNTI CB from to-be-scheduled
3104 **********************************************************/
3105 static Void rgSCHPwrRmvSchdPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb)
3107 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
3109 if (cb->schdLnk.node == NULLP)
3113 cmLListDelFrm(&cellPwr->puschGrpPwr, &cb->schdLnk);
3114 cb->schdLnk.node = NULLP;
3118 /***********************************************************
3120 * Func : rgSCHPwrChkPucchTpcRntiIdx
3122 * Desc : Validate that the given index is OK to
3123 * be assigned to a new UE for the Pucch TPC
3132 **********************************************************/
3133 static S16 rgSCHPwrChkPucchTpcRntiIdx(RgSchCmnTpcRntiCb *cb,uint8_t idx)
3136 if (rgSCHPwrChkTpcRntiIdx(cb, idx) != ROK)
3140 if (rgSCHPwrChkUniqPucchTpcRntiIdx(cb, idx) != ROK)
3147 /***********************************************************
3149 * Func : rgSCHPwrChkPuschTpcRntiIdx
3151 * Desc : Validate that the given index is OK to
3152 * be assigned to a new UE for the Pusch TPC
3161 **********************************************************/
3162 static S16 rgSCHPwrChkPuschTpcRntiIdx(RgSchCmnTpcRntiCb *cb,uint8_t idx)
3165 if (rgSCHPwrChkTpcRntiIdx(cb, idx) != ROK)
3169 if (rgSCHPwrChkUniqPuschTpcRntiIdx(cb, idx) != ROK)
3176 /***********************************************************
3178 * Func : rgSCHPwrChkUniqPucchTpcRntiIdx
3180 * Desc : Validate index against format type of TPC RNTI
3188 **********************************************************/
3189 static S16 rgSCHPwrChkUniqPucchTpcRntiIdx(RgSchCmnTpcRntiCb *cb,uint8_t idx)
3193 for (lnk = cb->cfgdUes.first; lnk; lnk = lnk->next)
3195 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
3196 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
3197 if (uePwr->pucchIdx == idx)
3205 /***********************************************************
3207 * Func : rgSCHPwrChkUniqPuschTpcRntiIdx
3209 * Desc : Validate index against format type of TPC RNTI
3217 **********************************************************/
3218 static S16 rgSCHPwrChkUniqPuschTpcRntiIdx(RgSchCmnTpcRntiCb *cb,uint8_t idx)
3222 for (lnk = cb->cfgdUes.first; lnk; lnk = lnk->next)
3224 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
3225 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
3226 if (uePwr->puschIdx == idx)
3234 /***********************************************************
3236 * Func : rgSCHPwrChkTpcRntiIdx
3238 * Desc : Validate index against format type of TPC RNTI.
3246 **********************************************************/
3247 static S16 rgSCHPwrChkTpcRntiIdx(RgSchCmnTpcRntiCb *cb,uint8_t idx)
3251 if (idx >= TFU_MAX_1BIT_TPC)
3258 if (idx >= TFU_MAX_2BIT_TPC)
3265 /* Warning Fix: Commenting out as not used */
3267 /***********************************************************
3269 * Func : rgSCHPwrGetPCMaxValFromPCMax
3271 * Desc : Returns the power headroom in dB
3272 * corresponding to a power headroom
3281 **********************************************************/
3282 static S8 rgSCHPwrGetPCMaxValFromPCMax(uint8_t pCMax)
3284 return ((pCMax & 63) - 30);
3289 /***********************************************************
3291 * Func : rgSCHPwrGetPhValFromPhr
3293 * Desc : Returns the power headroom in dB
3294 * corresponding to a power headroom
3303 **********************************************************/
3304 static S8 rgSCHPwrGetPhValFromPhr(uint8_t phr)
3306 return ((phr & 63) - 23);
3311 /**********************************************************************
3314 **********************************************************************/