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 /* header include files -- defines (.h) */
36 #include "common_def.h"
42 #include "rg_sch_inf.h"
43 #include "rg_sch_err.h"
45 #include "rg_sch_cmn.h"
47 /* header/extern include files (.x) */
48 #include "tfu.x" /* RGU types */
49 #include "lrg.x" /* layer management typedefs for MAC */
50 #include "rgr.x" /* layer management typedefs for MAC */
51 #include "rgm.x" /* layer management typedefs for MAC */
52 #include "rg_sch_inf.x" /* typedefs for Scheduler */
53 #include "rg_sch.x" /* typedefs for Scheduler */
54 #include "rg_sch_cmn.x"
57 /* Current specs have 23 dBm as max tx power capability for UEs */
58 #define RG_SCH_PWR_UE_MAX_PWR 23
60 #define RG_SCH_REF_PCMAX 0xFF
62 #define RG_SCH_CMN_GET_UL_UE(_ue,_cell) (&(((RgSchCmnUe *)((_ue->cellInfo[_ue->cellIdToCellIdxMap\
63 [RG_SCH_CELLINDEX(_cell)]])->sch))->ul))
64 #define RG_SCH_PWR_GETUEPWR(_ue, _cell) &(((RgSchCmnUe *)((_ue->cellInfo[_ue->cellIdToCellIdxMap\
65 [RG_SCH_CELLINDEX(_cell)]])->sch))->ul.ulPwrCb)
66 #define RG_SCH_PWR_GETCELLPWR(cell) &((RgSchCmnCell *)((cell)->sc.sch))->ul.ulPwrCb
69 typedef S8 RgSchCmnUlPwrCqiToPwrTbl[RG_SCH_CMN_UL_NUM_CQI];
71 static RgSchCmnUlPwrCqiToPwrTbl rgSchPwrCqiToPwrTbl;
73 /* This table maps a given number of RBs (given by array index)
74 * to the power in dB that these many RBs map to. */
75 const uint8_t rgSchPwrRbToPwrTbl[111] = { 0, /* First entry is dummy */
76 0, 3, 4, 6, 7, 7, 8, 9, 9, 10,
77 10, 10, 11, 11, 11, 12, 12, 12, 12, 13,
78 13, 13, 13, 13, 14, 14, 14, 14, 14, 14,
79 15, 15, 15, 15, 15, 15, 15, 15, 16, 16,
80 16, 16, 16, 16, 16, 16, 16, 16, 17, 17,
81 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
82 17, 18, 18, 18, 18, 18, 18, 18, 18, 18,
83 18, 18, 18, 18, 18, 18, 18, 19, 19, 19,
84 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
85 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
86 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
90 /* This table maps power (in dB) to number of RBs */
91 /* The array size comes from max power in rgSchPwrRbToPwrTbl */
92 const uint8_t rgSchPwrToRbTbl[20+1] = {
93 1, 1, 2, 2, 3, 4, 5, 6, 7, 9, 11,
94 13, 17, 21, 26, 33, 41, 52, 65, 82, 103
99 static S8 rgSCHPwrGetCqiPwr ARGS((
102 static S8 rgSCHPwrGetCqiPwrForUe ARGS((
107 static S8 rgSCHPwrCalcEfficncyPwr ARGS((
110 static S8 rgSCHPwrGetDelta2FrmCqi ARGS((
116 static Void rgSCHPwrGetPuschTpc ARGS((
123 static uint8_t rgSCHPwrGetMaxRb ARGS((
127 static uint8_t rgSCHPwrRbToPwr ARGS((
131 static Void rgSCHPwrSchedPucchRnti ARGS((
133 RgSchCmnTpcRntiCb *cb,
138 static Void rgSCHPwrPuschCntrl ARGS((
142 static Void rgSCHPwrPucchCntrl ARGS((
146 static Void rgSCHPwrSchedPuschRnti ARGS((
148 RgSchCmnTpcRntiCb *cb,
153 static Void rgSCHPwrGetPucchFmt3TpcForUe ARGS((
158 static Void rgSCHPwrGetPucchFmt3aTpcForUe ARGS((
163 static Void rgSCHPwrGetPuschFmt3TpcForUe ARGS((
168 static Void rgSCHPwrGetPuschFmt3aTpcForUe ARGS((
173 static Void rgSCHPwrGetAcc1bitTpc ARGS((
178 static Void rgSCHPwrGetAcc2bitTpc ARGS((
183 static Void rgSCHPwrGetAbsTpc ARGS((
188 static Void rgSCHPwrOnPucchGrpPwrForUe ARGS((
193 static Void rgSCHPwrOnPuschGrpPwrForUe ARGS((
198 static Bool rgSCHPwrIsDlUeSched ARGS((
203 static Bool rgSCHPwrIsUlUeSched ARGS((
208 static Void rgSCHPwrOnSchedPucchTpc ARGS((
213 static Void rgSCHPwrOnSchedPuschTpc ARGS((
217 static S16 rgSCHPwrApplyUePwrCfg ARGS((
220 RgrUeUlPwrCfg *pwrCfg
222 static Void rgSCHPwrUeResetPucch ARGS((
226 static Void rgSCHPwrUeResetPusch ARGS((
230 static Void rgSCHPwrOnPuschPwrUpd ARGS((
234 static Void rgSCHPwrAddRntiToPucchRntiLst ARGS((
239 static Void rgSCHPwrAddRntiToPuschRntiLst ARGS((
244 static Void rgSCHPwrInitTpcRntiCb ARGS((
245 RgSchCmnTpcRntiCb *cb,
249 static RgSchCmnTpcRntiCb* rgSCHPwrGetPucchRntiCb ARGS((
253 static RgSchCmnTpcRntiCb* rgSCHPwrGetPuschRntiCb ARGS((
257 static Void rgSCHPwrAddUeToPucchTpcRntiCb ARGS((
259 RgSchCmnTpcRntiCb *cb,
262 static Void rgSCHPwrDelUeFrmPucchTpcRntiCb ARGS((
264 RgSchCmnTpcRntiCb *cb,
267 static Void rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb ARGS((
269 RgSchCmnTpcRntiCb *cb,
272 static Void rgSCHPwrRmvSchdUeOnlyFrmPucchTpcRntiCb ARGS((
274 RgSchCmnTpcRntiCb *cb,
277 static Void rgSCHPwrRmvSchdPucchTpcRntiCb ARGS((
279 RgSchCmnTpcRntiCb *cb
281 static Void rgSCHPwrAddSchdUeToPucchTpcRntiCb ARGS((
283 RgSchCmnTpcRntiCb *cb,
286 static Void rgSCHPwrAddSchdPucchTpcRntiCb ARGS((
288 RgSchCmnTpcRntiCb *cb
290 static Void rgSCHPwrAddUeToPuschTpcRntiCb ARGS((
291 RgSchCmnTpcRntiCb *cb,
294 static Void rgSCHPwrAddSchdUeToPuschTpcRntiCb ARGS((
296 RgSchCmnTpcRntiCb *cb,
299 static Void rgSCHPwrDelUeFrmPuschTpcRntiCb ARGS((
301 RgSchCmnTpcRntiCb *cb,
304 static Void rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb ARGS((
306 RgSchCmnTpcRntiCb *cb,
309 static Void rgSCHPwrRmvSchdUeOnlyFrmPuschTpcRntiCb ARGS((
311 RgSchCmnTpcRntiCb *cb,
314 static Void rgSCHPwrAddSchdPuschTpcRntiCb ARGS((
316 RgSchCmnTpcRntiCb *cb
318 static Void rgSCHPwrRmvSchdPuschTpcRntiCb ARGS((
320 RgSchCmnTpcRntiCb *cb
322 static S16 rgSCHPwrChkPucchTpcRntiIdx ARGS((
323 RgSchCmnTpcRntiCb *cb,
326 static S16 rgSCHPwrChkPuschTpcRntiIdx ARGS((
327 RgSchCmnTpcRntiCb *cb,
330 static S16 rgSCHPwrChkUniqPucchTpcRntiIdx ARGS((
331 RgSchCmnTpcRntiCb *cb,
334 static S16 rgSCHPwrChkUniqPuschTpcRntiIdx ARGS((
335 RgSchCmnTpcRntiCb *cb,
338 static S16 rgSCHPwrChkTpcRntiIdx ARGS((
339 RgSchCmnTpcRntiCb *cb,
342 static S8 rgSCHPwrGetPhValFromPhr ARGS((
345 static S8 rgSCHPwrGetPCMaxValFromPCMax ARGS((
353 * @brief Does power related initialisation (not cell specific).
358 * Function : rgSCHPwrInit
361 * - This shall precompute coding efficiency to power
362 * mappings (assuming beta of 1).
370 rgSchPwrCqiToPwrTbl[0] = 0; /* This should never be used anyway */
371 for (idx = 1; idx < RG_SCH_CMN_UL_NUM_CQI; ++idx)
373 rgSchPwrCqiToPwrTbl[idx] = rgSCHPwrCalcEfficncyPwr(rgSchCmnUlCqiTbl[idx].eff);
378 /***********************************************************
380 * Func : rgSCHPwrGetCqiPwr
382 * Desc : Returns power corresponding to coding efficiency
383 * when beta pusch is assumed 1.
391 **********************************************************/
392 static S8 rgSCHPwrGetCqiPwr(uint8_t cqi)
395 return (rgSchPwrCqiToPwrTbl[cqi]);
396 } /* rgSCHPwrGetCqiPwr */
398 /***********************************************************
400 * Func : rgSCHPwrGetCqiPwrForUe
402 * Desc : If MCS control is enabled for UE, returns
403 * power corresponding to CQI, else 0.
411 **********************************************************/
412 static S8 rgSCHPwrGetCqiPwrForUe(RgSchCellCb *cell,RgSchUeCb *ue,uint8_t cqi)
414 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
416 if (!uePwr->deltaMcsEnbld)
420 return (rgSCHPwrGetCqiPwr(cqi));
421 } /* rgSCHPwrGetCqiPwrForUe */
423 /***********************************************************
425 * Func : rgSCHPwrCalcEfficncyPwr
427 * Desc : Computes power corresponding to a coding
432 * Notes: Assumes beta pusch to be 1
436 **********************************************************/
437 static S8 rgSCHPwrCalcEfficncyPwr(uint32_t eff)
439 F64 ks = 1.25; /* or F64 */
440 F64 tmp = cmPow(2, ks*eff/1024) - 1;
444 return ((S8)(10 * cmLog10(tmp)));
445 } /* rgSCHPwrCalcEfficncyPwr */
449 * @brief Returns TPC to be sent in UL allocation
453 * Function : rgSCHPwrPuschTpcForUe
455 * Invoking Module Processing:
456 * - After allocation for UE, this function shall
457 * be invoked to retrieve TPC.
458 * - This assumes that rgSCHPwrGetMaxUlRb() was
459 * invoked prior to final allocation for UE.
462 * - Just return TPC that was determined
464 * - After this, do necessary updates.
466 * @param[in] RgSchCellCb *cell
467 * @param[in] RgSchUeCb *ue
470 uint8_t rgSCHPwrPuschTpcForUe(RgSchCellCb *cell,RgSchUeCb *ue)
472 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue,cell);
476 rgSCHPwrOnSchedPuschTpc(cell, ue);
477 return (uePwr->puschTpc);
481 * @brief Handles Pusch power control for DCI format 0
485 * Function : rgSCHPwrGetMaxUlRb
487 * Invoking Module Processing:
488 * - This shall be invoked to determine maximum
489 * number of UL RBs for scheduling.
490 * - This is expected to be invoked every time
491 * priority to attempt at UE allocation. Later
492 * TPC retrieval depends on it.
495 * - Returns maximum allowed UL RBs to be granted
496 * after invoking Pusch power control.
498 * @param[in] RgSchCellCb *cell
499 * @param[in] RgSchUeCb *ue
502 uint8_t rgSCHPwrGetMaxUlRb(RgSchCellCb *cell,RgSchUeCb *ue)
504 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
506 rgSCHPwrPuschCntrl(cell, ue); /* This stores tpc, delta and maxRb
508 return (uePwr->maxUlRbs);
512 * @brief Handles Pusch power control for DCI format 0
516 * Function : rgSCHPwrPuschCntrl
518 * Invoking Module Processing:
519 * - This shall be invoked to determine TPC
520 * and maximum number of UL RBs for scheduling
521 * (through DCI format 0).
524 * - 'remPuschPwr' is the final delta power that the UE
525 * should apply to get to target CQI.
526 * - The available headroom (availPwr) is determined.
527 * - Power command is given by considering remPuschPwr and
529 * - After factoring in the power command into availPwr, the
530 * maximum number of RBs that can be supported is determined
531 * assuming that UE is going to use transmission efficiency
532 * corresponding to current CQI.
533 * - The results determined in this function are stored
534 * in the UE power control block.
535 * - [Not doing anything of power control of msg3
536 * retransmissions now]
538 * @param[in] RgSchCellCb *cell
539 * @param[in] RgSchUeCb *ue
542 static Void rgSCHPwrPuschCntrl(RgSchCellCb *cell,RgSchUeCb *ue)
544 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
545 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
546 RgSchCmnUlCell *cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
549 uint8_t cqi = ueUl->validUlCqi;
552 uint8_t cqi = ueUl->crntUlCqi[0];
554 Bool isAcc = uePwr->isAccumulated;
561 if (!uePwr->isPhrAvail)
563 availPwr = 60; /* setting a large value so that availPwr does
564 * not constrain delta */
568 availPwr = uePwr->maxUePwr - uePwr->pwrPerRb;
569 availPwr -= rgSCHPwrGetCqiPwrForUe(cell, ue, cqi);
571 delta = uePwr->remPuschPwr;
572 rgSCHPwrGetPuschTpc(isAcc, delta, availPwr, &tpc, &delta);
575 maxRb = rgSCHPwrGetMaxRb(cell,availPwr);
577 /* Store the results in ue power control block to be used later */
578 if(maxRb < cellUl->sbSize)
580 maxRb = cellUl->sbSize;
582 if(uePwr->maxPwrDeltaByPhr < 0)
584 tmp = ueUl->validUlCqi;
585 tmp = tmp + uePwr->maxPwrDeltaByPhr;
588 ueUl->validUlCqi = 1;
592 ueUl->validUlCqi = tmp;
597 DU_LOG("\nDEBUG --> SCH : UEID:%d Output Max Rb (%d), phVal (%d) AvailPwr (%d) ",
598 ue->ueId, maxRb, uePwr->phVal, availPwr);
599 DU_LOG("\nDEBUG --> SCH : UEID:%d pwrPerRb %d remPuschPwr %d",
603 uePwr->delta = delta;
604 uePwr->maxUlRbs = maxRb;
605 uePwr->puschTpc = tpc;
610 * @brief Returns TPC to be sent in DL allocation
614 * Function : rgSCHPwrPucchTpcForUe
616 * Invoking Module Processing:
617 * - After DL allocation for UE, this function shall
618 * be invoked to obtain TPC.
621 * - Do Pucch power control processing
624 * @param[in] RgSchCellCb *cell
625 * @param[in] RgSchUeCb *ue
628 uint8_t rgSCHPwrPucchTpcForUe(RgSchCellCb *cell,RgSchUeCb *ue)
630 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
632 rgSCHPwrPucchCntrl(cell, ue);
633 return (uePwr->pucchTpc);
636 /***********************************************************
638 * Func : rgSCHPwrGetDelta2FrmCqi
640 * Desc : Get power to be applied to achieve
641 * target CQI (the power returned is
642 * twice is actual power)
650 **********************************************************/
651 static S8 rgSCHPwrGetDelta2FrmCqi(uint8_t crntCqi,uint8_t trgCqi,RgSchUeCb *ue,RgSchCellCb *cell)
653 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
655 if (uePwr->isPhrAvail)
657 //uePwr->maxPwrDeltaByPhr = uePwr->maxPwrPerRb - uePwr->pwrPerRb - uePwr->remPuschPwr;
658 uePwr->maxPwrDeltaByPhr = uePwr->maxPwrPerRb - uePwr->pwrPerRb;
662 uePwr->maxPwrDeltaByPhr = 0;
665 if (uePwr->maxPwrDeltaByPhr < 0 && (trgCqi - crntCqi) *
666 RG_SCH_UL_CQI_DB_STEP_2 > 0)
670 return (RGSCH_MIN(uePwr->maxPwrDeltaByPhr,
671 (trgCqi - crntCqi) * RG_SCH_UL_CQI_DB_STEP_2));
672 } /* rgSCHPwrGetDelta2FrmCqi */
674 /***********************************************************
676 * Func : rgSCHPwrGetPuschTpc
678 * Desc : Based on whether accumulation is enabled or
679 * not, this returns an applicable power delta
680 * to be applied based on the input delta.
688 **********************************************************/
689 static Void rgSCHPwrGetPuschTpc(uint8_t isAcc,S8 delta,S8 availPwr,uint8_t *tpc,S8 *tpcDelta)
692 delta = RGSCH_MIN(delta, availPwr);
694 /* As of now, the functions below possibly cause delta
695 * to be breached by 1 only. So calling these as is. */
698 rgSCHPwrGetAcc2bitTpc(delta, tpc, tpcDelta);
702 rgSCHPwrGetAbsTpc(delta, tpc, tpcDelta);
705 } /* rgSCHPwrGetPuschTpc */
707 /***********************************************************
709 * Func : rgSCHPwrGetMaxRb
711 * Desc : Get the maximum number of RBs that can be
712 * expected to be supported by the passed
721 **********************************************************/
722 static uint8_t rgSCHPwrGetMaxRb(RgSchCellCb *cell,S8 pwr)
724 RgSchCmnUlCell *cellUl;
726 cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
729 /* Give 4 RBS so that UE can report changed power status*/
730 /* [ccpu00119916] Mod -return 0th index of rgSchPwrToRbTbl when pwr <=0
731 * Change the Macros from RGSCH_MAX_DL_BW to RGSCH_MAX_UL_BW*/
732 return (rgSchPwrToRbTbl[0]);
734 if (pwr > rgSchPwrRbToPwrTbl[cellUl->maxUlBwPerUe])
736 return (cellUl->maxUlBwPerUe);
738 return (RGSCH_MIN(cellUl->maxUlBwPerUe,rgSchPwrToRbTbl[(uint8_t)pwr]));
739 } /* rgSCHPwrGetMaxRb */
741 /***********************************************************
743 * Func : rgSCHPwrRbToPwr
745 * Desc : Get the power corresponding to number of RBs
753 **********************************************************/
754 static uint8_t rgSCHPwrRbToPwr(RgSchCellCb *cell,uint8_t numRb)
757 RgSchCmnUlCell *cellUl;
759 #if (ERRCLASS & ERRCLS_DEBUG)
760 cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
761 if (numRb > cellUl->maxUlBwPerUe)
763 numRb = cellUl->maxUlBwPerUe;
766 return (rgSchPwrRbToPwrTbl[numRb]);
767 } /* rgSCHPwrRbToPwr */
771 * @brief Handles Pucch power control for DCI formats 1A/1B/1D/1/2A/2
775 * Function : rgSCHPwrPucchCntrl
778 * - Determine 2 bit TPC to be sent using remPucchPwr.
779 * - Update remPucchPwr appropriately
781 * @param[in] RgSchCellCb *cell
782 * @param[in] RgSchUeCb *ue
785 static Void rgSCHPwrPucchCntrl(RgSchCellCb *cell,RgSchUeCb *ue)
788 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
790 rgSCHPwrGetAcc2bitTpc(uePwr->remPucchPwr, &uePwr->pucchTpc, &delta);
791 rgSCHPwrOnSchedPucchTpc(cell, ue, delta);
796 * @brief Handles group power control for DCI formats 3/3A for Pucch and Pusch
800 * Function : rgSCHPwrGrpCntrlPucch
802 * Invoking Module Processing:
803 * - This shall be invoked to do group power control for
804 * all TPC RNTIs for which it is deemed necessary to
805 * do the same (group power control).
806 * - This function should only be invoked after all UEs
807 * have been scheduled for uplink (re)transmissions
808 * requiring DL DCI format in the passed subframe.
811 * - For Pucch group power control
812 * - For each TPC-Pucch-RNTI in the pucchGrpPwr List and
813 * TPC-Pusch-RNTI in the puschGrpPwr List,
814 * - Request for PDCCH, skip if not available
815 * - Form DCI format 3/3A information depending
816 * on the format type of the TPC-RNTI and add it to the sub-frame.
817 * - For each Ue in ueLst of TPC RNTI Cb
818 * - if (fmtType == 3A)
819 * - if((Ue not scheduled DL dci formats)
820 * && (remPwr >= 2 || remPwr <= -2))
821 * - Determine TPC. Set puschTpc/pucchTpc.
823 * - if (remPwr >= -1 && remPwr <= 1)
824 * - If already added, remove from toBeSchdLst
826 * - Toggle the remainig power value
827 * - else if (fmtType == 3)
828 * - if((Ue not scheduled DL dci formats)
830 * - Determine TPC. Set puschTpc/pucchTpc.
833 * - If already added, remove from toBeSchdLst
834 * - if (!toBeSchdUeCnt)
835 * - Remove the tpcRntiCb frm pucchGrpPwr/puschGrpPwr List
836 * - else, Move the tpcRntiCb to end of the list (not doing
839 * @param[in] RgSchCellCb *cell
840 * @param[in] RgSchDlSf *dlSf
843 Void rgSCHPwrGrpCntrlPucch(RgSchCellCb *cell,RgSchDlSf *dlSf)
845 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
850 lst = &cellPwr->pucchGrpPwr;
852 while (lnk && ((pdcch = rgSCHCmnCmnPdcchAlloc(cell, dlSf)) != NULLP))
854 RgSchCmnTpcRntiCb *cb = (RgSchCmnTpcRntiCb *)lnk->node;
857 rgSCHPwrSchedPucchRnti(cell, cb, pdcch, dlSf, &sched);
860 rgSCHUtlPdcchPut(cell, &dlSf->pdcchInfo, pdcch);
862 /* TPC RNTI would not have been removed if needs to
863 * be scheduled again */
870 * @brief Handles group power control for DCI formats 3/3A for Pusch and Pusch
874 * Function : rgSCHPwrGrpCntrlPusch
876 * Invoking Module Processing:
877 * - This shall be invoked to do group power control for
878 * all TPC RNTIs for which it is deemed necessary to
879 * do the same (group power control).
880 * - This function should only be invoked after all UEs
881 * have been scheduled for uplink (re)transmissions
882 * requiring DCI format 0 in the passed subframe.
885 * - For Pusch group power control
886 * - For each TPC-Pusch-RNTI in the puschGrpPwr List and
887 * - Request for PDCCH, skip if not available
888 * - Form DCI format 3/3A information depending
889 * on the format type of the TPC-RNTI and add it to the sub-frame.
890 * - For each Ue in ueLst of TPC RNTI Cb
891 * - if (fmtType == 3A)
892 * - if (Ue not scheduled for dci format 0) and
893 * (remPwr >= 2 || remPwr <= -2))
894 * - Determine TPC. Set puschTpc/puschTpc.
896 * - if (remPwr >= -1 && remPwr <= 1)
897 * - If already added, remove from toBeSchdLst
899 * - Toggle the remainig power value
900 * - else if (fmtType == 3)
901 * - if((Ue not scheduled for dci format 0) && (remPwr))
902 * - Determine TPC. Set puschTpc.
905 * - If already added, remove from toBeSchdLst
906 * - if (!toBeSchdUeCnt)
907 * - Remove the tpcRntiCb frm puschGrpPwr/puschGrpPwr List
908 * - else, Move the tpcRntiCb to end of the list (not doing
911 * @param[in] RgSchCellCb *cell
912 * @param[in] RgSchDlSf *sf
915 Void rgSCHPwrGrpCntrlPusch(RgSchCellCb *cell,RgSchDlSf *dlSf,RgSchUlSf *ulSf)
917 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
922 lst = &cellPwr->puschGrpPwr;
924 while (lnk && ((pdcch = rgSCHCmnCmnPdcchAlloc(cell, dlSf)) != NULLP))
926 RgSchCmnTpcRntiCb *cb = (RgSchCmnTpcRntiCb *)lnk->node;
929 rgSCHPwrSchedPuschRnti(cell, cb, pdcch, ulSf, &sched);
932 rgSCHUtlPdcchPut(cell, &dlSf->pdcchInfo, pdcch);
934 /* TPC RNTI would not have been removed if needs to
935 * be scheduled again */
941 /***********************************************************
943 * Func : rgSCHPwrSchedPucchRnti
945 * Desc : Schedule TPC RNTI to be sent out
953 **********************************************************/
954 static Void rgSCHPwrSchedPucchRnti(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchPdcch *pdcch,RgSchDlSf *dlSf,Bool *sched)
963 pdcch->rnti = cb->tpcRnti;
967 /* Go through all UEs for format 3A case */
969 pdcch->dci.dciFormat = TFU_DCI_FORMAT_3A;
970 pdcch->dciNumOfBits = cell->dciSize.size[TFU_DCI_FORMAT_3A];
971 pdcch->dci.u.format3AInfo.isPucch = TRUE;
973 tpcCmds = pdcch->dci.u.format3AInfo.tpcCmd;
974 /* No need to memset zero initially as every TPC is going
975 * to be filled up for every configured UE */
976 for (atleastOne = FALSE, lnk = lst->first; lnk; lnk = lnk->next)
978 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
979 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
981 if ( ue->isDrxEnabled == TRUE &&
982 !RG_SCH_DRX_DL_IS_UE_ACTIVE(ue->drxCb))
984 /* UE is in its DRX time. So we cannot give command
990 if (rgSCHPwrIsDlUeSched(cell, ue, dlSf))
992 /* UE already scheduled in downlink with PDCCH
993 * carrying PUCCH pwr cmd. So don't care about
994 * giving command to this UE. */
997 rgSCHPwrGetPucchFmt3aTpcForUe(ue, &tpc, &delta);
998 tpcCmds[uePwr->pucchIdx] = tpc;
1000 rgSCHPwrOnPucchGrpPwrForUe(cell, ue, delta);
1005 /* Go through to-be-scheduled UEs for format 3 case */
1006 lst = &cb->toBeSchdUes;
1007 pdcch->dci.dciFormat = TFU_DCI_FORMAT_3;
1008 pdcch->dciNumOfBits = cell->dciSize.size[TFU_DCI_FORMAT_3];
1009 tpcCmds = pdcch->dci.u.format3Info.tpcCmd;
1010 pdcch->dci.u.format3Info.isPucch = TRUE;
1012 /* Fill TPC 1 (corresponding to no power change) initially */
1013 memset(tpcCmds, 1, sizeof(pdcch->dci.u.format3Info.tpcCmd));
1015 for (atleastOne = FALSE, lnk = lst->first; lnk; lnk = lnk->next)
1017 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
1018 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1020 if ( ue->isDrxEnabled == TRUE &&
1021 !RG_SCH_DRX_DL_IS_UE_ACTIVE(ue->drxCb))
1023 /* UE is in its DRX time. So we cannot give command
1029 if (rgSCHPwrIsDlUeSched(cell, ue, dlSf))
1031 /* UE already scheduled in downlink with PDCCH
1032 * carrying PUCCH pwr cmd. So don't care about
1033 * giving command to this UE. */
1036 rgSCHPwrGetPucchFmt3TpcForUe(ue, &tpc, &delta);
1037 tpcCmds[uePwr->pucchIdx] = tpc;
1039 rgSCHPwrOnPucchGrpPwrForUe(cell, ue, delta);
1043 *sched = atleastOne;
1045 /* Check if no more UEs in TPC RNTI, and then remove
1046 * this TPC RNTI from scheduled list */
1047 if (cb->toBeSchdUes.count == 0)
1049 rgSCHPwrRmvSchdPucchTpcRntiCb(cell, cb);
1053 } /* rgSCHPwrSchedPucchRnti */
1055 /***********************************************************
1057 * Func : rgSCHPwrSchedPuschRnti
1059 * Desc : Schedule TPC RNTI to be sent out
1067 **********************************************************/
1068 static Void rgSCHPwrSchedPuschRnti(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchPdcch *pdcch,RgSchUlSf *ulSf,Bool *sched)
1077 pdcch->rnti = cb->tpcRnti;
1081 /* Go through all UEs for format 3A case */
1083 pdcch->dci.dciFormat = TFU_DCI_FORMAT_3A;
1084 pdcch->dciNumOfBits = cell->dciSize.size[TFU_DCI_FORMAT_3A];
1085 pdcch->dci.u.format3AInfo.isPucch = FALSE;
1086 tpcCmds = pdcch->dci.u.format3AInfo.tpcCmd;
1087 /* No need to memset zero initially as every TPC is going
1088 * to be filled up for every configured UE */
1089 for (atleastOne = FALSE, lnk = lst->first; lnk; lnk = lnk->next)
1091 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
1092 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1093 if (rgSCHPwrIsUlUeSched(cell, ue, ulSf))
1095 /* UE already scheduled in uplink with DCI
1096 * format 0. So don't care about giving
1097 * command to this UE. */
1101 if ( ue->isDrxEnabled == TRUE &&
1102 !RG_SCH_DRX_DL_IS_UE_ACTIVE(ue->drxCb))
1104 /* UE is in its DRX time. So we cannot give command
1110 rgSCHPwrGetPuschFmt3aTpcForUe(ue, &tpc, &delta);
1111 tpcCmds[uePwr->puschIdx] = tpc;
1113 rgSCHPwrOnPuschGrpPwrForUe(cell, ue, delta);
1118 /* Go through to-be-scheduled UEs for format 3 case */
1119 lst = &cb->toBeSchdUes;
1120 pdcch->dci.dciFormat = TFU_DCI_FORMAT_3;
1121 pdcch->dciNumOfBits = cell->dciSize.size[TFU_DCI_FORMAT_3];
1122 pdcch->dci.u.format3Info.isPucch = FALSE;
1123 tpcCmds = pdcch->dci.u.format3Info.tpcCmd;
1125 /* Fill TPC 1 (corresponding to no power change) initially */
1126 memset(tpcCmds, 1, sizeof(pdcch->dci.u.format3Info.tpcCmd));
1128 for (atleastOne = FALSE, lnk = lst->first; lnk; lnk = lnk->next)
1130 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
1131 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1132 if (rgSCHPwrIsUlUeSched(cell, ue, ulSf))
1134 /* UE already scheduled in uplink with DCI
1135 * format 0. So don't care about giving
1136 * command to this UE. */
1140 if ( ue->isDrxEnabled == TRUE &&
1141 !RG_SCH_DRX_DL_IS_UE_ACTIVE(ue->drxCb))
1143 /* UE is in its DRX time. So we cannot give command
1149 rgSCHPwrGetPuschFmt3TpcForUe(ue, &tpc, &delta);
1150 tpcCmds[uePwr->puschIdx] = tpc;
1152 rgSCHPwrOnPuschGrpPwrForUe(cell, ue, delta);
1156 *sched = atleastOne;
1158 /* Check if no more UEs in TPC RNTI, and then remove
1159 * this TPC RNTI from scheduled list */
1160 if (cb->toBeSchdUes.count == 0)
1162 rgSCHPwrRmvSchdPuschTpcRntiCb(cell, cb);
1166 } /* rgSCHPwrSchedPuschRnti */
1168 /***********************************************************
1170 * Func : rgSCHPwrGetPucchFmt3TpcForUe
1172 * Desc : Gets 2 bit TPC cmd for PUCCH
1180 **********************************************************/
1181 static Void rgSCHPwrGetPucchFmt3TpcForUe(RgSchUeCb *ue,uint8_t *tpc,S8 *delta)
1183 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1185 rgSCHPwrGetAcc2bitTpc(uePwr->remPucchPwr, tpc, delta);
1187 } /* rgSCHPwrGetPucchFmt3TpcForUe */
1189 /***********************************************************
1191 * Func : rgSCHPwrGetPucchFmt3aTpcForUe
1193 * Desc : Gets 1 bit TPC cmd for PUCCH
1201 **********************************************************/
1202 static Void rgSCHPwrGetPucchFmt3aTpcForUe(RgSchUeCb *ue,uint8_t *tpc,S8 *delta)
1204 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1206 rgSCHPwrGetAcc1bitTpc(uePwr->remPucchPwr, tpc, delta);
1208 } /* rgSCHPwrGetPucchFmt3aTpcForUe */
1210 /***********************************************************
1212 * Func : rgSCHPwrGetPuschFmt3TpcForUe
1214 * Desc : Gets 2 bit TPC cmd for PUCCH
1222 **********************************************************/
1223 static Void rgSCHPwrGetPuschFmt3TpcForUe(RgSchUeCb *ue,uint8_t *tpc,S8 *delta)
1225 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1226 S8 adj = RGSCH_MIN(uePwr->remPuschPwr, uePwr->phVal);
1228 rgSCHPwrGetAcc2bitTpc(adj, tpc, delta);
1230 } /* rgSCHPwrGetPuschFmt3TpcForUe */
1232 /***********************************************************
1234 * Func : rgSCHPwrGetPuschFmt3aTpcForUe
1236 * Desc : Gets 1 bit TPC cmd for PUCCH
1244 **********************************************************/
1245 static Void rgSCHPwrGetPuschFmt3aTpcForUe(RgSchUeCb *ue,uint8_t *tpc,S8 *delta)
1247 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1249 /* Don't attempt to look at headroom now, power
1250 * adjustment is small anyway */
1251 rgSCHPwrGetAcc1bitTpc(uePwr->remPuschPwr, tpc, delta);
1253 } /* rgSCHPwrGetPuschFmt3aTpcForUe */
1255 /***********************************************************
1257 * Func : rgSCHPwrGetAcc1bitTpc
1259 * Desc : Gets 1 bit TPC cmd
1267 **********************************************************/
1268 static Void rgSCHPwrGetAcc1bitTpc(S8 remPwr,uint8_t *tpc,S8 *delta)
1286 } /* rgSCHPwrGetAcc1bitTpc */
1288 /***********************************************************
1290 * Func : rgSCHPwrGetAcc2bitTpc
1292 * Desc : Allocate PDCCH for group power control
1300 **********************************************************/
1301 static Void rgSCHPwrGetAcc2bitTpc(S8 remPwr,uint8_t *tpc,S8 *delta)
1310 uint8_t tpcs[3] = {1, 2, 2};
1311 uint8_t deltas[3] = {0, 1, 1};
1317 else if (remPwr >= 3)
1324 *tpc = tpcs[(uint8_t)remPwr];
1325 *delta = deltas[(uint8_t)remPwr];
1328 } /* rgSCHPwrGetAcc2bitTpc */
1330 /***********************************************************
1332 * Func : rgSCHPwrGetAbsTpc
1334 * Desc : Allocate PDCCH for group power control
1342 **********************************************************/
1343 static Void rgSCHPwrGetAbsTpc(S8 remPwr,uint8_t *tpc,S8 *delta)
1357 else if (remPwr < 1)
1362 else if (remPwr < 4)
1373 } /* rgSCHPwrGetAbsTpc */
1375 /***********************************************************
1377 * Func : rgSCHPwrOnPucchGrpPwrForUe
1379 * Desc : Processing on sending TPC for UE through group power
1380 * control. Apart from updating remPwr, this only takes
1381 * care of possibly removing UE from scheduled
1383 * It does not take care of possibly removing TPC RNTI
1384 * from scheduled list in cell. This is done
1385 * in the caller after TPC for all UEs has been
1386 * determined. (This is where it differs
1387 * from the usual OnSendingPu[cs]ch TPC]
1395 **********************************************************/
1396 static Void rgSCHPwrOnPucchGrpPwrForUe(RgSchCellCb *cell,RgSchUeCb *ue,S8 delta)
1398 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1403 uePwr->remPucchPwr -= delta;
1405 /* UE was already scheduled for PUCCH group power
1406 * control which is why we came here. Don't
1407 * again check for this. */
1409 /* UE was scheduled for pucch grp pwr, sent TPC may
1410 * possibly cause it to be removed. */
1411 if (!uePwr->remPucchPwr)
1417 rgSCHPwrRmvSchdUeOnlyFrmPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb, ue);
1418 /* Not removing TPC RNTI from scheduled list,
1419 * this will happen in the caller once this
1420 * function is called for every UE scheduled. */
1425 /***********************************************************
1427 * Func : rgSCHPwrOnPuschGrpPwrForUe
1429 * Desc : Processing on sending TPC for UE through group power
1430 * control. Apart from updating remPwr, this only takes
1431 * care of possibly removing UE from scheduled
1433 * It does not take care of possibly removing TPC RNTI
1434 * from scheduled list in cell. This is done
1435 * in the caller after TPC for all UEs has been
1436 * determined. (This is where it differs
1437 * from the usual OnSendingPu[cs]ch TPC]
1445 **********************************************************/
1446 static Void rgSCHPwrOnPuschGrpPwrForUe(RgSchCellCb *cell,RgSchUeCb *ue,S8 delta)
1448 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1453 uePwr->delta = delta;
1454 uePwr->remPuschPwr -= delta;
1455 if (uePwr->isPhrAvail)
1457 uePwr->phVal -= uePwr->delta;
1458 uePwr->phVal = RGSCH_MAX(-23, uePwr->phVal);
1461 /* UE was already scheduled for PUSCH group power
1462 * control which is why we came here. Don't
1463 * again check for this. */
1465 /* UE was scheduled for pusch grp pwr, sent TPC may
1466 * possibly cause it to be removed. */
1468 if (!uePwr->remPuschPwr)
1475 rgSCHPwrRmvSchdUeOnlyFrmPuschTpcRntiCb(cell, uePwr->tpcPuschRntiCb, ue);
1476 /* Not removing TPC RNTI from scheduled list,
1477 * this will happen in the caller once this
1478 * function is called for every UE scheduled. */
1483 /***********************************************************
1485 * Func : rgSCHPwrIsDlUeSched
1487 * Desc : Check if UE is scheduled in the passed DL SF
1495 **********************************************************/
1496 static Bool rgSCHPwrIsDlUeSched(RgSchCellCb *cell,RgSchUeCb *ue,RgSchDlSf *sf)
1498 RgSchDlHqEnt *hqEnt = RG_SCH_CMN_GET_UE_HQE(ue, cell);
1499 RgSchDlHqProcCb *proc = rgSCHDhmLastSchedHqProc(hqEnt);
1507 * The following subframe check is assumed enough, since
1508 * scheduled procs stay for a short time (until feedback
1509 * arrives), which typically is expected to have a
1510 * turnaround time of less than 8 subframes. So
1511 * we are probably never going to come across cases
1512 * where a process stays in the list for more than
1513 * 10 subframes, which would have otherwise caused
1514 * the check to succeed for a possibly older process.
1516 if ((proc->tbInfo[0].timingInfo.slot == sf->sfNum) ||
1517 (proc->tbInfo[1].timingInfo.slot == sf->sfNum))
1520 * Later, if a proc can be scheduled without having an
1521 * associated PDCCH, need to also check if PDCCH exists.
1522 * This is because for power, what matters is whether
1523 * TPC is going out for UE at this time or not, at least
1524 * that is what this function was introduced for.
1525 * Checking for PDCCH would have to be in common proc
1526 * the way things are now.
1534 } /* rgSCHPwrIsDlUeSched */
1536 /***********************************************************
1538 * Func : rgSCHPwrIsUlUeSched
1540 * Desc : Check if UE is scheduled in the passed UL SF
1548 **********************************************************/
1549 static Bool rgSCHPwrIsUlUeSched(RgSchCellCb *cell,RgSchUeCb *ue,RgSchUlSf *sf)
1551 RgSchCmnUlCell *cmnCell = RG_SCH_CMN_GET_UL_CELL(cell);
1552 RgSchUlHqProcCb *proc = rgSCHUhmGetUlHqProc(cell, ue, cmnCell->schdHqProcIdx);
1556 #if (ERRCLASS & ERRCLS_DEBUG)
1571 } /* rgSCHPwrIsUlUeSched */
1574 * @brief Handles Pucch power delta indication recieved from PHY
1578 * Function : rgSCHPwrPucchDeltaInd
1580 * Invoking Module Processing:
1581 * - This shall be invoked on reception of Pucch power
1582 * delta indication from PHY.
1585 * - Update the remPucchPwr
1586 * ue->remPucchPwr = pwrDelta
1587 * - If (ue->tpcPucchRntiCb)
1588 * - If (fmtType = 3A)
1589 * - if (remPucchPwr >= 2 || remPucchPwr <= -2 )
1590 * - if (tpcPucchRntiCb is not in the pucchGrpPwr List)
1591 * - Add tpcPucchRntiCb to the pucchGrpPwr list.
1592 * - If not added, add to toBeSchdLst
1594 * - If already added, remove from toBeSchdLst
1595 * - else If (fmtType == 3)
1596 * - if (remPucchPwr)
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
1603 * @param[in] RgSchCellCb *cell
1604 * @param[in] RgSchUeCb *ue
1605 * @param[in] uint8_t pwrDelta
1608 Void rgSCHPwrPucchDeltaInd(RgSchCellCb *cell,RgSchUeCb *ue,S8 pwrDelta)
1610 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1611 RgSchCmnTpcRntiCb *cb;
1614 uePwr->remPucchPwr = pwrDelta;
1616 if ((cb = uePwr->tpcPucchRntiCb) == NULLP)
1623 if (0 != uePwr->remPucchPwr)
1631 rgSCHPwrAddSchdUeToPucchTpcRntiCb(cell, cb, ue);
1635 rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb(cell, cb, ue);
1642 * @brief Does processing after TPC for Pucch has been sent
1646 * Function : rgSCHPwrOnSchedPucchTpc
1648 * Invoking Module Processing:
1649 * - It shall be invoked after it is determined that PDCCH for UE
1650 * is finalised to go out, and thus TPC for PUCCH is being
1654 * - Update remPucchPwr with the delta
1655 * - Do group power control related processing
1657 * @param[in] RgSchCellCb *cell
1658 * @param[in] RgSchUeCb *ue
1659 * @param[in] S8 delta
1662 static Void rgSCHPwrOnSchedPucchTpc(RgSchCellCb *cell,RgSchUeCb *ue,S8 delta)
1664 /* Similar to rgSCHPwrPucchDeltaInd.. not reusing
1665 * that since we use the fact that UE could only have
1666 * improved its remPwr as part of power control. */
1667 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1670 uePwr->remPucchPwr -= delta;
1672 if (uePwr->schdPucchGrpLnk.node == NULLP)
1677 /* UE was scheduled for TPC, sent TPC may
1678 * possibly cause it to be removed. */
1680 if (!uePwr->remPucchPwr)
1687 rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb, ue);
1688 if (uePwr->tpcPucchRntiCb->toBeSchdUes.count == 0)
1690 rgSCHPwrRmvSchdPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb);
1698 * @brief Does processing after TPC for Pusch has been sent
1702 * Function : rgSCHPwrOnSchedPuschTpc
1706 * - Update remPuschPwr with the delta
1707 * - Do group power related processing if applicable
1709 * @param[in] RgSchCellCb *cell
1710 * @param[in] RgSchUeCb *ue
1713 static Void rgSCHPwrOnSchedPuschTpc(RgSchCellCb *cell,RgSchUeCb *ue)
1715 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1718 /* Don't do anything for the case of absolute TPC commands */
1719 if (!uePwr->isAccumulated)
1724 uePwr->remPuschPwr -= uePwr->delta;
1725 if (uePwr->isPhrAvail)
1727 uePwr->phVal -= uePwr->delta;
1728 uePwr->phVal = RGSCH_MAX(-23, uePwr->phVal);
1731 if (uePwr->schdPuschGrpLnk.node == NULLP)
1736 /* UE was scheduled for pusch TPC, sent TPC may
1737 * possibly cause it to be removed. */
1739 if (!uePwr->remPuschPwr)
1746 rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb(cell, uePwr->tpcPuschRntiCb, ue);
1753 * @brief Handles PHR updation for the UE
1757 * Function : rgSCHPwrUpdExtPhr
1758 * @param[in] RgSchCellCb *cell
1759 * @param[in] RgSchUeCb *ue
1760 * @param[in] RgInfExtPhrCEInfo *extPhr
1761 * @param[in] RgSchCmnAllocRecord allocInfo
1764 Void rgSCHPwrUpdExtPhr(RgSchCellCb *cell,RgSchUeCb *ue,RgInfExtPhrCEInfo *extPhr,RgSchCmnAllocRecord *allocInfo)
1767 RgInfExtPhrSCellInfo *servCellPhr;
1770 for (idx = 0; idx < extPhr->numServCells; idx++)
1772 servCellPhr = &extPhr->servCellPhr[idx];
1774 if (RG_SCH_REF_PCMAX == servCellPhr->pCmax)
1776 pCMax = RG_SCH_CMN_PWR_USE_CFG_MAX_PWR;
1780 pCMax = rgSCHPwrGetPCMaxValFromPCMax(servCellPhr->pCmax);
1782 rgSCHPwrUpdPhr(ue->cellInfo[servCellPhr->sCellIdx]->cell,
1783 ue, servCellPhr->phr, allocInfo, pCMax);
1789 * @brief Handles PHR updation for the UE
1793 * Function : rgSCHPwrUpdPhr
1795 * Invoking Module Processing:
1796 * - This shall be invoked on reception of PHR from MAC to SCH. It shall
1797 * pass the information of number of RBs, coding efficiency and TPC for
1798 * the Pusch transmission for which PHR has been reported.
1801 * - Compute power per RB using the PHR report
1802 * - ue_transmit_pwr = ue_max_pwr - PHR
1803 * - if isDeltaMcs = TRUE
1804 * - ue_transmit_pwr -
1805 * [10log(phr_num_rb) + 10log(2^ (1.25 * phr_coding_effeciency) -1)
1806 * + phr_tpc(if absolute TPC)] = pwrPerRB
1808 * - ue_transmit_pwr - [10log(phr_num_rb) + phr_tpc(if absolute TPC)]
1810 * (Use the number of RBs and efficiency used by UE which caused the PHR
1812 * - Adjust PHR according to last allocation (take into account
1813 * number of RBs granted in the last allocation)
1814 * - Update the PHR report in the control block
1815 * - Set isPhrAvail = TRUE
1816 * - Do group power control related processing if applicable
1818 * @param[in] RgSchCellCb *cell
1819 * @param[in] RgSchUeCb *ue
1820 * @param[in] uint8_t phr
1821 * @param[in] RgSchCmnAllocRecord allocInfo
1822 * @param[in] uint8_t maxUePwr
1825 Void rgSCHPwrUpdPhr(RgSchCellCb *cell,RgSchUeCb *ue,uint8_t phr,RgSchCmnAllocRecord *allocInfo,S8 maxUePwr )
1827 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1830 RgSchCmnUlCell *cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
1832 uePwr->phVal = rgSCHPwrGetPhValFromPhr(phr);
1834 if (maxUePwr == RG_SCH_CMN_PWR_USE_CFG_MAX_PWR)
1836 maxUePwr = uePwr->maxUePwr;
1838 rbPwr = rgSCHPwrRbToPwr(cell,allocInfo->numRb);
1839 effPwr = rgSCHPwrGetCqiPwrForUe(cell, ue, allocInfo->cqi);
1840 uePwr->pwrPerRb = maxUePwr - uePwr->phVal - rbPwr - effPwr;
1841 /*if (!uePwr->isAccumulated)
1843 uePwr->pwrPerRb -= rgSCHPwrGetDeltaFrmAbsTpc(allocInfo->tpc);
1846 /* Let headroom reflect remaining power according to last
1847 * allocated number of RBs. Intermediate TPCs not yet
1848 * taken care of (for accumulated case, it is anyway
1849 * not applicable for absolute commands). */
1850 uePwr->phVal -= (rgSCHPwrRbToPwr(cell, cellUl->sbSize)) - rbPwr;
1851 uePwr->phVal = RGSCH_MAX(-23, uePwr->phVal);
1852 uePwr->isPhrAvail = TRUE;
1854 rgSCHPwrOnPuschPwrUpd(cell, ue);
1856 DU_LOG("\nDEBUG --> SCH : Output: Reported PHR[%d] cqi[%u] allocRb[%u] uePwr->pwrPerRb[%d]",
1865 * @brief Handles UL CQI indication
1869 * Function : rgSCHPwrUlCqiInd
1871 * Invoking Module Processing:
1872 * - This shall be invoked when uplink CQI indication
1873 * is receiving from PHY for a UE.
1876 * - Update remPuschPwr.
1877 * - Possibly schedule for group power control.
1879 * @param[in] RgSchCellCb *cell
1880 * @param[in] RgSchUeCb *ue
1881 * @param[in] uint8_t numRb
1884 Void rgSCHPwrUlCqiInd(RgSchCellCb *cell,RgSchUeCb *ue)
1886 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
1887 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1893 * For absolute power cmd case, we could look at the time
1894 * at which CQI was received, determine if there was a
1895 * PUSCH TPC cmd for that time (this could come from
1896 * group power control too), and (if this
1897 * CQI report is indeed based on the the PUSCH tx)
1898 * then factor in that cmd here. Not doing
1902 /* See how much power needs to be adjusted based on cqi
1904 uePwr->remPuschPwr =
1906 rgSCHPwrGetDelta2FrmCqi(ueUl->validUlCqi, uePwr->trgCqi, ue, cell);
1908 rgSCHPwrGetDelta2FrmCqi(ueUl->crntUlCqi[0], uePwr->trgCqi, ue, cell);
1911 rgSCHPwrOnPuschPwrUpd(cell, ue);
1913 if(uePwr->maxPwrDeltaByPhr < 0)
1915 tmp = ueUl->validUlCqi;
1916 tmp = tmp + uePwr->maxPwrDeltaByPhr;
1919 ueUl->validUlCqi = 1;
1923 ueUl->validUlCqi = tmp;
1932 * @brief Updates the stored last number of RBs allocated
1936 * Function : rgSCHPwrRecordRbAlloc
1938 * Invoking Module Processing:
1939 * - This shall be invoked when uplink allocation is made for
1941 * - Note: If outstanding TPCs are considered at the time
1942 * of PHR report, the last numRb would also be known
1943 * and then this API would not be needed.
1946 * - Adjust PHR according to now allocated number of RBs
1947 * - Store the number of RBs
1949 * @param[in] RgSchCellCb *cell
1950 * @param[in] RgSchUeCb *ue
1951 * @param[in] uint8_t numRb
1954 Void rgSCHPwrRecordRbAlloc(RgSchCellCb *cell,RgSchUeCb *ue,uint8_t numRb)
1956 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1960 if (uePwr->isPhrAvail)
1962 uePwr->phVal += rgSCHPwrRbToPwr(cell,numRb) - rgSCHPwrRbToPwr(cell,uePwr->numRb);
1963 uePwr->phVal = RGSCH_MIN(40, uePwr->phVal);
1965 uePwr->numRb = numRb;
1970 * @brief Handles power related configuration for a cell
1974 * Function : rgSCHPwrCellCfg
1976 * Invoking Module Processing:
1977 * - This shall be invoked during cell config
1982 * - Update TPC-RNTI information for the cell for Pucch and Pusch.
1983 * - For each TPC-Pucch-RNTI,
1984 * - Call rgSCHAddRntiToPucchRntiLst()
1985 * - For each TPC-Pusch-RNTI,
1986 * - Call rgSCHAddRntiToPuschRntiLst()
1989 * @param[in] RgSchCellCb *cell
1990 * @param[in] RgrCellCfg *cfg
1995 S16 rgSCHPwrCellCfg(RgSchCellCb *cell,RgrCellCfg *cfg)
1997 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
1999 CmLteRnti startRnti;
2003 /* Right now, all UEs have fixed maximum power capability. So
2004 * we store cell wide pMax as minimum of configured pMax and
2006 cellPwr->pMax = RGSCH_MIN(cfg->pMax, RG_SCH_PWR_UE_MAX_PWR);
2008 /* trgUlCqi already validated by common */
2009 cellPwr->trgUlCqi = cfg->trgUlCqi.trgCqi;
2011 /* Validate number of TPC RNTIs */
2012 if ((cfg->pwrCfg.pucchPwrFmt3.size + cfg->pwrCfg.pucchPwrFmt3a.size
2013 > RG_SCH_CMN_MAX_NUM_TPC_PUCCH_RNTI)
2014 || (cfg->pwrCfg.puschPwrFmt3.size + cfg->pwrCfg.puschPwrFmt3a.size
2015 > RG_SCH_CMN_MAX_NUM_TPC_PUSCH_RNTI))
2020 /* Now initialise TPC RNTIs */
2022 /* Format 3 Pucch TPC RNTIs */
2024 startRnti = cfg->pwrCfg.pucchPwrFmt3.startTpcRnti;
2025 size = cfg->pwrCfg.pucchPwrFmt3.size;
2026 for (rnti = startRnti; (rnti < startRnti + size); ++rnti)
2028 rgSCHPwrAddRntiToPucchRntiLst(cell, rnti, isFmt3a);
2031 /* Format 3A Pucch TPC RNTIs */
2033 startRnti = cfg->pwrCfg.pucchPwrFmt3a.startTpcRnti;
2034 size = cfg->pwrCfg.pucchPwrFmt3a.size;
2035 for (rnti = startRnti; (rnti < startRnti + size); ++rnti)
2037 rgSCHPwrAddRntiToPucchRntiLst(cell, rnti, isFmt3a);
2040 /* Format 3 Pusch TPC RNTIs */
2042 startRnti = cfg->pwrCfg.puschPwrFmt3.startTpcRnti;
2043 size = cfg->pwrCfg.puschPwrFmt3.size;
2044 for (rnti = startRnti; (rnti < startRnti + size); ++rnti)
2046 rgSCHPwrAddRntiToPuschRntiLst(cell, rnti, isFmt3a);
2049 /* Format 3A Pusch TPC RNTIs */
2051 startRnti = cfg->pwrCfg.puschPwrFmt3a.startTpcRnti;
2052 size = cfg->pwrCfg.puschPwrFmt3a.size;
2053 for (rnti = startRnti; (rnti < startRnti + size); ++rnti)
2055 rgSCHPwrAddRntiToPuschRntiLst(cell, rnti, isFmt3a);
2062 * @brief Handles power related re-configuration for a cell
2066 * Function : rgSCHPwrCellRecfg
2071 * @param[in] RgSchCellCb *cell
2072 * @param[in] RgrCellRecfg *recfg
2076 S16 rgSCHPwrCellRecfg(RgSchCellCb *cell,RgrCellRecfg *recfg)
2081 /* Not doing anything for power reconfig, so such structure
2087 * @brief Frees power related data structures in cell
2091 * Function : rgSCHPwrCellDel
2096 * @param[in] RgSchCellCb *cell
2099 Void rgSCHPwrCellDel(RgSchCellCb *cell)
2103 /* There is no allocated memory, so do nothing */
2110 * @brief Configures ULPC CB for a SCELL being added
2114 * Function : rgSCHPwrUeSCellCfg
2116 * @param[in] RgSchCellCb *cell
2117 * @param[in] RgSchUeCb *ue
2118 * @param[in] RgrUeCfg *cfg
2123 S16 rgSCHPwrUeSCellCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeSecCellCfg *sCellInfoCfg)
2125 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2126 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2127 RgSchCmnUeUlPwrCb *uePwrPCell = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2128 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
2130 RgSchCmnUlCell *cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
2133 uePwr->maxUePwr = cellPwr->pMax;
2134 uePwr->trgCqi = cellPwr->trgUlCqi; /* Overriding with UE's happens later */
2137 uePwr->maxPwrPerRb = uePwr->maxUePwr - rgSchPwrRbToPwrTbl[cellUl->sbSize];
2139 uePwr->isPhrAvail = FALSE;
2141 uePwr->maxUlRbs = RGSCH_MAX_DL_BW;
2143 uePwr->puschTpc = 1;
2144 uePwr->remPuschPwr = 0;
2146 /* Rest of the vars update and group power control related
2147 * config happens in the function below */
2148 uePwr->isAccumulated = sCellInfoCfg->ueSCellUlDedPwrCfg.isAccumulated;
2149 uePwr->deltaMcsEnbld = sCellInfoCfg->ueSCellUlDedPwrCfg.isDeltaMCSEnabled;
2151 uePwr->trgCqi = uePwrPCell->trgCqi;
2153 if (ueUl->maxUlCqi < uePwr->trgCqi)
2155 uePwr->trgCqi = ueUl->maxUlCqi;
2157 uePwr->p0UePusch = sCellInfoCfg->ueSCellUlDedPwrCfg.p0UePusch;
2164 * @brief Handles power related configuration for a UE
2168 * Function : rgSCHPwrUeCfg
2171 * - If Pusch group power configuration exists && accumulation enabled,
2172 * - Fetch the TPC-Pusch-RNTI control block for the configured
2173 * TPC-Pusch-RNTI. Call rgSCHGetRntiFrmPuschRntiLst(). If it does not
2174 * exist, return RFAILED.
2175 * - Add Ue to the ueLst of TPC-Pusch-RNTI control block.
2176 * - Update tpcPuschRntiCb pointer in UE.
2177 * - Update the puschIdx value.
2178 * - If Pucch group power configuration exists && accumulation enabled,
2179 * - Fetch the TPC-Pucch-RNTI control block for the configured
2180 * TPC-Pucch-RNTI. Call rgSCHGetRntiFrmPucchRntiLst(). If it does not
2181 * exist, return RFAILED.
2182 * - Add Ue to the ueLst of TPC-Pucch-RNTI control block.
2183 * - Update tpcPucchRntiCb pointer in UE.
2184 * - Update the pucchIdx value.
2185 * - Update isAccumulated and isDeltaMcs variables.
2186 * - maxUlRbs = configured maximum UL bandwidth value per UE.
2187 * - trgUlCqi = configured value, if any, else cell-wide default trg CQI value.
2188 * - If format type is format 3A, update remaining power to +1
2189 * - Update TPC-RNTI information for the cell for Pucch and Pusch.
2192 * @param[in] RgSchCellCb *cell
2193 * @param[in] RgSchUeCb *ue
2194 * @param[in] RgrUeCfg *cfg
2199 S16 rgSCHPwrUeCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeCfg *cfg)
2202 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2203 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2205 RgSchCmnUlCell *cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
2207 uePwr->maxUePwr = cellPwr->pMax;
2208 uePwr->trgCqi = cellPwr->trgUlCqi; /* Overriding with UE's happens later */
2211 uePwr->maxPwrPerRb = uePwr->maxUePwr - rgSchPwrRbToPwrTbl[cellUl->sbSize];
2213 rgSCHPwrUeResetPucch(cell, ue);
2214 rgSCHPwrUeResetPusch(cell, ue);
2216 /* Rest of the vars update and group power control related
2217 * config happens in the function below */
2218 ret = rgSCHPwrApplyUePwrCfg(cell, ue, &cfg->ueUlPwrCfg);
2224 * @brief Handles power related re-configuration for a UE
2228 * Function : rgSCHPwrUeRecfg
2230 * Invoking Module Processing:
2231 * - This shall be invoked by SCH_GOM at UE re-configuration.
2234 * - If change in TPC-RNTI, update the pointer and the TPC RNTI Cb appropriately.
2235 * - If accumulation disabled, remove the UE from TPC-RNTI lists of UE, if
2237 * - If group power configuration disabled, remove the UE from TPC-RNTI lists of UE, if
2240 * @param[in] RgSchCellCb *cell
2241 * @param[in] RgSchUeCb *ue
2242 * @param[in] RgrUeRecfg *recfg
2248 S16 rgSCHPwrUeRecfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeRecfg *recfg)
2251 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2252 RgrUeUlPwrCfg *pwrCfg = &recfg->ueUlPwrRecfg;
2254 if (pwrCfg->p0UePucch != uePwr->p0UePucch)
2256 rgSCHPwrUeResetPucch(cell, ue);
2258 if ((pwrCfg->isAccumulated != uePwr->isAccumulated)
2259 || (pwrCfg->p0UePusch != uePwr->p0UePusch))
2261 rgSCHPwrUeResetPusch(cell, ue);
2263 ret = rgSCHPwrApplyUePwrCfg(cell, ue, &recfg->ueUlPwrRecfg);
2268 /***********************************************************
2270 * Func : rgSCHPwrApplyUePwrCfg
2272 * Desc : Applies power config for UE. Meants to be
2273 * used during both power config and reconfig.
2281 **********************************************************/
2282 static S16 rgSCHPwrApplyUePwrCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeUlPwrCfg *pwrCfg)
2285 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
2286 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2287 RgSchCmnTpcRntiCb *pucchRntiCb = NULLP;
2288 RgSchCmnTpcRntiCb *puschRntiCb = NULLP;
2289 uint8_t pucchIdx = 0;
2290 uint8_t puschIdx = 0;
2292 /* Validate Pucch group power control config */
2293 if (pwrCfg->uePucchPwr.pres)
2296 rgSCHPwrGetPucchRntiCb(cell, pwrCfg->uePucchPwr.tpcRnti);
2297 if (pucchRntiCb == NULLP)
2301 pucchIdx = pwrCfg->uePucchPwr.idx;
2302 ret = rgSCHPwrChkPucchTpcRntiIdx(pucchRntiCb, pucchIdx);
2309 /* Validate Pusch group power control config */
2310 if (pwrCfg->uePuschPwr.pres)
2313 rgSCHPwrGetPuschRntiCb(cell, pwrCfg->uePuschPwr.tpcRnti);
2314 if (puschRntiCb == NULLP)
2318 puschIdx = pwrCfg->uePuschPwr.idx;
2319 ret = rgSCHPwrChkPuschTpcRntiIdx(puschRntiCb, puschIdx);
2326 /* Apply Pucch group power control config */
2329 if (uePwr->tpcPucchRntiCb != pucchRntiCb) /* This part for recfg */
2331 if (uePwr->tpcPucchRntiCb)
2333 rgSCHPwrDelUeFrmPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb, ue);
2335 uePwr->tpcPucchRntiCb = pucchRntiCb;
2336 rgSCHPwrAddUeToPucchTpcRntiCb(cell, pucchRntiCb, ue);
2338 uePwr->pucchIdx = pucchIdx;
2340 DU_LOG("\nDEBUG --> SCH : <GRP_PWR>PucchRntiCb cfgdUes(%ld %lu %lu) UEID:%d",
2341 pucchRntiCb->cfgdUes.count,((uint32_t)pucchRntiCb->cfgdUes.first),
2342 ((uint32_t)pucchRntiCb->cfgdUes.last),ue->ueId);
2343 DU_LOG("\nDEBUG --> SCH : UEID:%d isFmt3a(%u) ueNode(%ld)",
2344 ue->ueId,pucchRntiCb->isFmt3a,
2345 pucchRntiCb->schdLnk.node);
2346 DU_LOG("\nDEBUG --> SCH : toBeSchdUes(%ld %lu %lu) tpcRnti(%u)",
2347 pucchRntiCb->toBeSchdUes.count,
2348 ((uint32_t)pucchRntiCb->toBeSchdUes.first),
2349 ((uint32_t)pucchRntiCb->toBeSchdUes.last),
2350 pucchRntiCb->tpcRnti);
2352 DU_LOG("\nDEBUG --> SCH : <GRP_PWR>PucchRntiCb cfgdUes(%d %lu %lu) UEID:%d",
2353 pucchRntiCb->cfgdUes.count,((uint64_t)pucchRntiCb->cfgdUes.first),
2354 ((uint64_t)pucchRntiCb->cfgdUes.last),ue->ueId);
2355 DU_LOG("\nDEBUG --> SCH : UEID:%d isFmt3a(%u) ueNode(%ld)",
2356 ue->ueId,pucchRntiCb->isFmt3a,
2357 pucchRntiCb->schdLnk.node);
2358 DU_LOG("\nDEBUG --> SCH : toBeSchdUes(%d %lu %lu) tpcRnti(%u)",
2359 pucchRntiCb->toBeSchdUes.count,
2360 ((uint64_t)pucchRntiCb->toBeSchdUes.first),
2361 ((uint64_t)pucchRntiCb->toBeSchdUes.last),
2362 pucchRntiCb->tpcRnti);
2367 /* Apply Pusch group power control config */
2370 if (uePwr->tpcPuschRntiCb != puschRntiCb) /* This part for recfg */
2372 if (uePwr->tpcPuschRntiCb)
2374 rgSCHPwrDelUeFrmPuschTpcRntiCb(cell, uePwr->tpcPuschRntiCb, ue);
2376 uePwr->tpcPuschRntiCb = puschRntiCb;
2377 rgSCHPwrAddUeToPuschTpcRntiCb(puschRntiCb, ue);
2379 uePwr->puschIdx = puschIdx;
2383 uePwr->isAccumulated = pwrCfg->isAccumulated;
2384 uePwr->deltaMcsEnbld = pwrCfg->isDeltaMCSEnabled;
2387 uePwr->trgCqi = pwrCfg->trgCqi;
2389 if (ueUl->maxUlCqi < uePwr->trgCqi)
2391 uePwr->trgCqi = ueUl->maxUlCqi;
2393 uePwr->p0UePusch = pwrCfg->p0UePusch;
2394 uePwr->p0UePucch = pwrCfg->p0UePucch;
2401 * @brief Deletes power related information for UE
2405 * Function : rgSCHPwrUeDel
2407 * Invoking Module Processing:
2408 * - This shall be invoked by at the time of UE deletion.
2411 * - if (ue->tpcPucchRntiCb)
2412 * - delete UE from tpcPucchRntiCb->ueLst
2413 * - ue->tpcPucchRntiCb = NULLP
2414 * - If in (ue->tpcPucchRntiCb->toBeSchdLst)
2415 * - remove from the list.
2416 * - if (ue->tpcPuschRntiCb)
2417 * - delete UE from tpcPuschRntiCb->ueLst
2418 * - ue->tpcPuschRntiCb = NULLP
2419 * - If in (ue->tpcPuschRntiCb->toBeSchdLst)
2420 * - remove from the list.
2422 * @param[in] RgSchCellCb *cell
2423 * @param[in] RgSchUeCb *ue
2426 Void rgSCHPwrUeDel(RgSchCellCb *cell,RgSchUeCb *ue)
2428 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2430 if (uePwr->tpcPucchRntiCb)
2432 rgSCHPwrDelUeFrmPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb, ue);
2433 uePwr->tpcPucchRntiCb = NULLP;
2435 if (uePwr->tpcPuschRntiCb)
2437 rgSCHPwrDelUeFrmPuschTpcRntiCb(cell, uePwr->tpcPuschRntiCb, ue);
2438 uePwr->tpcPuschRntiCb = NULLP;
2444 * @brief Resets UE's power state
2448 * Function : rgSCHPwrUeReset
2450 * Invoking Module Processing:
2451 * - This shall be invoked by at the time PDCCH order.
2454 * - Reset PUSCH power state
2455 * - Reset PUCCH power state
2457 * @param[in] RgSchCellCb *cell
2458 * @param[in] RgSchUeCb *ue
2461 Void rgSCHPwrUeReset(RgSchCellCb *cell,RgSchUeCb *ue)
2464 rgSCHPwrUeResetPucch(cell, ue);
2465 rgSCHPwrUeResetPusch(cell, ue);
2469 /***********************************************************
2471 * Func : rgSCHPwrUeResetPucch
2473 * Desc : This function is called to reset UE
2474 * to initial PUCCH power state.
2482 **********************************************************/
2483 static Void rgSCHPwrUeResetPucch(RgSchCellCb *cell,RgSchUeCb *ue)
2485 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2487 uePwr->pucchTpc = 1;
2488 uePwr->remPucchPwr = 0;
2489 if (uePwr->tpcPucchRntiCb)
2491 rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb, ue);
2494 /* Stack Crash problem for TRACE5 changes. Added the line below */
2499 /***********************************************************
2501 * Func : rgSCHPwrUeResetPusch
2503 * Desc : This function is called to reset UE
2504 * to initial PUSCH power state.
2512 **********************************************************/
2513 static Void rgSCHPwrUeResetPusch(RgSchCellCb *cell,RgSchUeCb *ue)
2515 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2517 uePwr->isPhrAvail = FALSE;
2519 uePwr->maxUlRbs = RGSCH_MAX_DL_BW;
2521 uePwr->puschTpc = 1;
2522 uePwr->remPuschPwr = 0;
2523 if (uePwr->tpcPuschRntiCb)
2525 rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb(cell, uePwr->tpcPuschRntiCb, ue);
2530 /***********************************************************
2532 * Func : rgSCHPwrOnPuschPwrUpd
2534 * Desc : This function is called whenever 'remPuschPwr'
2543 **********************************************************/
2544 static Void rgSCHPwrOnPuschPwrUpd(RgSchCellCb *cell,RgSchUeCb *ue)
2546 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2547 RgSchCmnTpcRntiCb *cb;
2550 if ((cb = uePwr->tpcPuschRntiCb) == NULLP)
2555 /* Not checking for uwPwr->isPhrAvail as uePwr->phVal
2556 * is set to a large value initially */
2560 if ((uePwr->phVal != 0) && (uePwr->remPuschPwr != 0))
2568 rgSCHPwrAddSchdUeToPuschTpcRntiCb(cell, cb, ue);
2572 rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb(cell, cb, ue);
2579 /***********************************************************
2581 * Func : rgSCHPwrAddRntiToPucchRntiLst
2584 * Desc : Adds RNTI to Pucch Rnti list and updates requisite
2589 * Notes: Assumed that array bounds are checked
2590 * in caller before adding.
2594 **********************************************************/
2595 static Void rgSCHPwrAddRntiToPucchRntiLst(RgSchCellCb *cell,CmLteRnti rnti,Bool isFmt3a)
2597 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2599 rgSCHPwrInitTpcRntiCb(&cellPwr->tpcPucchRntiLst[cellPwr->tpcPucchRntiCnt++],
2604 /***********************************************************
2606 * Func : rgSCHPwrAddRntiToPuschRntiLst
2609 * Desc : Adds RNTI to Pusch Rnti list and updates requisite
2614 * Notes: Assumed that array bounds are checked
2615 * in caller before adding.
2619 **********************************************************/
2620 static Void rgSCHPwrAddRntiToPuschRntiLst(RgSchCellCb *cell,CmLteRnti rnti,Bool isFmt3a)
2622 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2624 rgSCHPwrInitTpcRntiCb(&cellPwr->tpcPuschRntiLst[cellPwr->tpcPuschRntiCnt++],
2629 /***********************************************************
2631 * Func : rgSCHPwrInitTpcRntiCb
2634 * Desc : Initialises a TPC RNTI CB
2642 **********************************************************/
2643 static Void rgSCHPwrInitTpcRntiCb(RgSchCmnTpcRntiCb *cb,CmLteRnti rnti,Bool isFmt3a)
2646 memset(cb, 0, sizeof(*cb));
2648 cb->isFmt3a = isFmt3a;
2649 /* Not initialising lists as memset 0 takes care of it */
2650 /* cb->schdLnk.node is set when this rnti is to be scheduled */
2654 /***********************************************************
2656 * Func : rgSCHPwrGetPucchRntiCb
2659 * Desc : Gets TPC RNTI control block from Pucch rnti list
2661 * Ret : RgSchCmnTpcRntiCb * - Success
2668 **********************************************************/
2669 static RgSchCmnTpcRntiCb* rgSCHPwrGetPucchRntiCb(RgSchCellCb *cell,CmLteRnti tpcRnti)
2671 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2674 if (!cellPwr->tpcPucchRntiCnt)
2678 for (idx = 0; idx < cellPwr->tpcPucchRntiCnt; ++idx)
2680 if (cellPwr->tpcPucchRntiLst[idx].tpcRnti == tpcRnti)
2682 return (&cellPwr->tpcPucchRntiLst[idx]);
2688 /***********************************************************
2690 * Func : rgSCHPwrGetPuschRntiCb
2693 * Desc : Gets TPC RNTI control block from Pusch rnti list
2695 * Ret : RgSchCmnTpcRntiCb * - Success
2702 **********************************************************/
2703 static RgSchCmnTpcRntiCb* rgSCHPwrGetPuschRntiCb(RgSchCellCb *cell,CmLteRnti tpcRnti)
2705 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2708 if (!cellPwr->tpcPuschRntiCnt)
2712 for (idx = 0; idx < cellPwr->tpcPuschRntiCnt; ++idx)
2714 if (cellPwr->tpcPuschRntiLst[idx].tpcRnti == tpcRnti)
2716 return (&cellPwr->tpcPuschRntiLst[idx]);
2723 /***********************************************************
2725 * Func : rgSCHPwrAddUeToPucchTpcRntiCb
2728 * Desc : Add UE to cfgd list of UEs in rnti cb
2736 **********************************************************/
2737 static Void rgSCHPwrAddUeToPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2739 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2742 cmLListAdd2Tail(&cb->cfgdUes, &uePwr->pucchGrpLnk);
2743 uePwr->pucchGrpLnk.node = (PTR)ue;
2747 /***********************************************************
2749 * Func : rgSCHPwrDelUeFrmPucchTpcRntiCb
2752 * Desc : Remove UE from Pucch TPC RNTI CB
2760 **********************************************************/
2761 static Void rgSCHPwrDelUeFrmPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2763 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2765 rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb(cell, cb, ue);
2766 cmLListDelFrm(&cb->cfgdUes, &uePwr->pucchGrpLnk);
2767 uePwr->pucchGrpLnk.node = NULLP;
2771 /***********************************************************
2773 * Func : rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb
2776 * Desc : Remove UE from to-be-scheduled list of UEs
2785 **********************************************************/
2786 static Void rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2788 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2790 if (uePwr->schdPucchGrpLnk.node == NULLP)
2794 rgSCHPwrRmvSchdUeOnlyFrmPucchTpcRntiCb(cell, cb, ue);
2795 if (!cb->toBeSchdUes.count)
2797 rgSCHPwrRmvSchdPucchTpcRntiCb(cell, cb);
2802 /***********************************************************
2804 * Func : rgSCHPwrRmvSchdUeOnlyFrmPucchTpcRntiCb
2806 * Desc : Remove UE from to-be-scheduled list of UEs
2807 * in Pucch RNTI CB. Do not both about
2808 * possibly removing Pucch RNTI CB from
2809 * the cell wide to-be-scheduled list.
2817 **********************************************************/
2818 static Void rgSCHPwrRmvSchdUeOnlyFrmPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2820 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2822 if (uePwr->schdPucchGrpLnk.node != NULLP)
2824 cmLListDelFrm(&cb->toBeSchdUes, &uePwr->schdPucchGrpLnk);
2825 uePwr->schdPucchGrpLnk.node = NULLP;
2830 /***********************************************************
2832 * Func : rgSCHPwrRmvSchdPucchTpcRntiCb
2834 * Desc : Remove Pucch TPC RNTI CB from to-be-scheduled
2843 **********************************************************/
2844 static Void rgSCHPwrRmvSchdPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb)
2846 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2848 if (cb->schdLnk.node == NULLP)
2852 cmLListDelFrm(&cellPwr->pucchGrpPwr, &cb->schdLnk);
2853 cb->schdLnk.node = NULLP;
2857 /***********************************************************
2859 * Func : rgSCHPwrAddSchdUeToPucchTpcRntiCb
2861 * Desc : Add UE to to-be-scheduled list of UEs
2870 **********************************************************/
2871 static Void rgSCHPwrAddSchdUeToPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2873 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2875 if (uePwr->schdPucchGrpLnk.node != NULLP)
2877 /* UE is already in the list */
2880 cmLListAdd2Tail(&cb->toBeSchdUes, &uePwr->schdPucchGrpLnk);
2881 uePwr->schdPucchGrpLnk.node = (PTR)ue;
2882 if (cb->toBeSchdUes.count == 1)
2884 /* This is first UE, so queue up this TPC RNTI
2886 rgSCHPwrAddSchdPucchTpcRntiCb(cell, cb);
2891 /***********************************************************
2893 * Func : rgSCHPwrAddSchdPucchTpcRntiCb
2895 * Desc : Add Pucch TPC RNTI CB from to-be-scheduled
2904 **********************************************************/
2905 static Void rgSCHPwrAddSchdPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb)
2907 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2909 cmLListAdd2Tail(&cellPwr->pucchGrpPwr, &cb->schdLnk);
2910 cb->schdLnk.node = (PTR)cb;
2915 /***********************************************************
2917 * Func : rgSCHPwrAddUeToPuschTpcRntiCb
2920 * Desc : Add UE to cfgd list of UEs in rnti cb
2928 **********************************************************/
2929 static Void rgSCHPwrAddUeToPuschTpcRntiCb(RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2931 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2933 cmLListAdd2Tail(&cb->cfgdUes, &uePwr->puschGrpLnk);
2934 uePwr->puschGrpLnk.node = (PTR)ue;
2938 /***********************************************************
2940 * Func : rgSCHPwrAddSchdUeToPuschTpcRntiCb
2942 * Desc : Add UE to to-be-scheduled list of UEs
2951 **********************************************************/
2952 static Void rgSCHPwrAddSchdUeToPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2954 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2956 if (uePwr->schdPuschGrpLnk.node != NULLP)
2958 /* UE is already in the list */
2961 cmLListAdd2Tail(&cb->toBeSchdUes, &uePwr->schdPuschGrpLnk);
2962 uePwr->schdPuschGrpLnk.node = (PTR)ue;
2963 if (cb->toBeSchdUes.count == 1)
2965 /* This is first UE, so queue up this TPC RNTI
2967 rgSCHPwrAddSchdPuschTpcRntiCb(cell, cb);
2972 /***********************************************************
2974 * Func : rgSCHPwrDelUeFrmPuschTpcRntiCb
2977 * Desc : Add UE to cfgd list of UEs in rnti cb
2985 **********************************************************/
2986 static Void rgSCHPwrDelUeFrmPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2988 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2990 rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb(cell, cb, ue);
2991 cmLListDelFrm(&cb->cfgdUes, &uePwr->puschGrpLnk);
2992 uePwr->puschGrpLnk.node = NULLP;
2996 /***********************************************************
2998 * Func : rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb
3000 * Desc : Remove UE from to-be-scheduled list of UEs
3009 **********************************************************/
3010 static Void rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
3012 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
3014 if (uePwr->schdPuschGrpLnk.node == NULLP)
3018 rgSCHPwrRmvSchdUeOnlyFrmPuschTpcRntiCb(cell, cb, ue);
3019 if (!cb->toBeSchdUes.count)
3021 rgSCHPwrRmvSchdPuschTpcRntiCb(cell, cb);
3026 /***********************************************************
3028 * Func : rgSCHPwrRmvSchdUeOnlyFrmPuschTpcRntiCb
3030 * Desc : Remove UE from to-be-scheduled list of UEs
3031 * in Pusch RNTI CB. Do not both about
3032 * possibly removing Pusch RNTI CB from
3033 * the cell wide to-be-scheduled list.
3041 **********************************************************/
3042 static Void rgSCHPwrRmvSchdUeOnlyFrmPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
3044 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
3046 if (uePwr->schdPuschGrpLnk.node != NULLP)
3048 cmLListDelFrm(&cb->toBeSchdUes, &uePwr->schdPuschGrpLnk);
3049 uePwr->schdPuschGrpLnk.node = NULLP;
3054 /***********************************************************
3056 * Func : rgSCHPwrAddSchdPuschTpcRntiCb
3058 * Desc : Add Pusch TPC RNTI CB from to-be-scheduled
3067 **********************************************************/
3068 static Void rgSCHPwrAddSchdPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb)
3070 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
3072 cmLListAdd2Tail(&cellPwr->puschGrpPwr, &cb->schdLnk);
3073 cb->schdLnk.node = (PTR)cb;
3077 /***********************************************************
3079 * Func : rgSCHPwrRmvSchdPuschTpcRntiCb
3081 * Desc : Remove Pusch TPC RNTI CB from to-be-scheduled
3090 **********************************************************/
3091 static Void rgSCHPwrRmvSchdPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb)
3093 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
3095 if (cb->schdLnk.node == NULLP)
3099 cmLListDelFrm(&cellPwr->puschGrpPwr, &cb->schdLnk);
3100 cb->schdLnk.node = NULLP;
3104 /***********************************************************
3106 * Func : rgSCHPwrChkPucchTpcRntiIdx
3108 * Desc : Validate that the given index is OK to
3109 * be assigned to a new UE for the Pucch TPC
3118 **********************************************************/
3119 static S16 rgSCHPwrChkPucchTpcRntiIdx(RgSchCmnTpcRntiCb *cb,uint8_t idx)
3122 if (rgSCHPwrChkTpcRntiIdx(cb, idx) != ROK)
3126 if (rgSCHPwrChkUniqPucchTpcRntiIdx(cb, idx) != ROK)
3133 /***********************************************************
3135 * Func : rgSCHPwrChkPuschTpcRntiIdx
3137 * Desc : Validate that the given index is OK to
3138 * be assigned to a new UE for the Pusch TPC
3147 **********************************************************/
3148 static S16 rgSCHPwrChkPuschTpcRntiIdx(RgSchCmnTpcRntiCb *cb,uint8_t idx)
3151 if (rgSCHPwrChkTpcRntiIdx(cb, idx) != ROK)
3155 if (rgSCHPwrChkUniqPuschTpcRntiIdx(cb, idx) != ROK)
3162 /***********************************************************
3164 * Func : rgSCHPwrChkUniqPucchTpcRntiIdx
3166 * Desc : Validate index against format type of TPC RNTI
3174 **********************************************************/
3175 static S16 rgSCHPwrChkUniqPucchTpcRntiIdx(RgSchCmnTpcRntiCb *cb,uint8_t idx)
3179 for (lnk = cb->cfgdUes.first; lnk; lnk = lnk->next)
3181 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
3182 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
3183 if (uePwr->pucchIdx == idx)
3191 /***********************************************************
3193 * Func : rgSCHPwrChkUniqPuschTpcRntiIdx
3195 * Desc : Validate index against format type of TPC RNTI
3203 **********************************************************/
3204 static S16 rgSCHPwrChkUniqPuschTpcRntiIdx(RgSchCmnTpcRntiCb *cb,uint8_t idx)
3208 for (lnk = cb->cfgdUes.first; lnk; lnk = lnk->next)
3210 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
3211 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
3212 if (uePwr->puschIdx == idx)
3220 /***********************************************************
3222 * Func : rgSCHPwrChkTpcRntiIdx
3224 * Desc : Validate index against format type of TPC RNTI.
3232 **********************************************************/
3233 static S16 rgSCHPwrChkTpcRntiIdx(RgSchCmnTpcRntiCb *cb,uint8_t idx)
3237 if (idx >= TFU_MAX_1BIT_TPC)
3244 if (idx >= TFU_MAX_2BIT_TPC)
3251 /* Warning Fix: Commenting out as not used */
3253 /***********************************************************
3255 * Func : rgSCHPwrGetPCMaxValFromPCMax
3257 * Desc : Returns the power headroom in dB
3258 * corresponding to a power headroom
3267 **********************************************************/
3268 static S8 rgSCHPwrGetPCMaxValFromPCMax(uint8_t pCMax)
3270 return ((pCMax & 63) - 30);
3275 /***********************************************************
3277 * Func : rgSCHPwrGetPhValFromPhr
3279 * Desc : Returns the power headroom in dB
3280 * corresponding to a power headroom
3289 **********************************************************/
3290 static S8 rgSCHPwrGetPhValFromPhr(uint8_t phr)
3292 return ((phr & 63) - 23);
3297 /**********************************************************************
3300 **********************************************************************/