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"
55 #include "rl_interface.h"
56 #include "rl_common.h"
59 /* Current specs have 23 dBm as max tx power capability for UEs */
60 #define RG_SCH_PWR_UE_MAX_PWR 23
62 #define RG_SCH_REF_PCMAX 0xFF
64 #define RG_SCH_CMN_GET_UL_UE(_ue,_cell) (&(((RgSchCmnUe *)((_ue->cellInfo[_ue->cellIdToCellIdxMap\
65 [RG_SCH_CELLINDEX(_cell)]])->sch))->ul))
66 #define RG_SCH_PWR_GETUEPWR(_ue, _cell) &(((RgSchCmnUe *)((_ue->cellInfo[_ue->cellIdToCellIdxMap\
67 [RG_SCH_CELLINDEX(_cell)]])->sch))->ul.ulPwrCb)
68 #define RG_SCH_PWR_GETCELLPWR(cell) &((RgSchCmnCell *)((cell)->sc.sch))->ul.ulPwrCb
71 typedef S8 RgSchCmnUlPwrCqiToPwrTbl[RG_SCH_CMN_UL_NUM_CQI];
73 static RgSchCmnUlPwrCqiToPwrTbl rgSchPwrCqiToPwrTbl;
75 /* This table maps a given number of RBs (given by array index)
76 * to the power in dB that these many RBs map to. */
77 const uint8_t rgSchPwrRbToPwrTbl[111] = { 0, /* First entry is dummy */
78 0, 3, 4, 6, 7, 7, 8, 9, 9, 10,
79 10, 10, 11, 11, 11, 12, 12, 12, 12, 13,
80 13, 13, 13, 13, 14, 14, 14, 14, 14, 14,
81 15, 15, 15, 15, 15, 15, 15, 15, 16, 16,
82 16, 16, 16, 16, 16, 16, 16, 16, 17, 17,
83 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
84 17, 18, 18, 18, 18, 18, 18, 18, 18, 18,
85 18, 18, 18, 18, 18, 18, 18, 19, 19, 19,
86 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
87 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
88 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
92 /* This table maps power (in dB) to number of RBs */
93 /* The array size comes from max power in rgSchPwrRbToPwrTbl */
94 const uint8_t rgSchPwrToRbTbl[20+1] = {
95 1, 1, 2, 2, 3, 4, 5, 6, 7, 9, 11,
96 13, 17, 21, 26, 33, 41, 52, 65, 82, 103
101 static S8 rgSCHPwrGetCqiPwr ARGS((
104 static S8 rgSCHPwrGetCqiPwrForUe ARGS((
109 static S8 rgSCHPwrCalcEfficncyPwr ARGS((
112 static S8 rgSCHPwrGetDelta2FrmCqi ARGS((
118 static Void rgSCHPwrGetPuschTpc ARGS((
125 static uint8_t rgSCHPwrGetMaxRb ARGS((
129 static uint8_t rgSCHPwrRbToPwr ARGS((
133 static Void rgSCHPwrSchedPucchRnti ARGS((
135 RgSchCmnTpcRntiCb *cb,
140 static Void rgSCHPwrPuschCntrl ARGS((
144 static Void rgSCHPwrPucchCntrl ARGS((
148 static Void rgSCHPwrSchedPuschRnti ARGS((
150 RgSchCmnTpcRntiCb *cb,
155 static Void rgSCHPwrGetPucchFmt3TpcForUe ARGS((
160 static Void rgSCHPwrGetPucchFmt3aTpcForUe ARGS((
165 static Void rgSCHPwrGetPuschFmt3TpcForUe ARGS((
170 static Void rgSCHPwrGetPuschFmt3aTpcForUe ARGS((
175 static Void rgSCHPwrGetAcc1bitTpc ARGS((
180 static Void rgSCHPwrGetAcc2bitTpc ARGS((
185 static Void rgSCHPwrGetAbsTpc ARGS((
190 static Void rgSCHPwrOnPucchGrpPwrForUe ARGS((
195 static Void rgSCHPwrOnPuschGrpPwrForUe ARGS((
200 static Bool rgSCHPwrIsDlUeSched ARGS((
205 static Bool rgSCHPwrIsUlUeSched ARGS((
210 static Void rgSCHPwrOnSchedPucchTpc ARGS((
215 static Void rgSCHPwrOnSchedPuschTpc ARGS((
219 static S16 rgSCHPwrApplyUePwrCfg ARGS((
222 RgrUeUlPwrCfg *pwrCfg
224 static Void rgSCHPwrUeResetPucch ARGS((
228 static Void rgSCHPwrUeResetPusch ARGS((
232 static Void rgSCHPwrOnPuschPwrUpd ARGS((
236 static Void rgSCHPwrAddRntiToPucchRntiLst ARGS((
241 static Void rgSCHPwrAddRntiToPuschRntiLst ARGS((
246 static Void rgSCHPwrInitTpcRntiCb ARGS((
247 RgSchCmnTpcRntiCb *cb,
251 static RgSchCmnTpcRntiCb* rgSCHPwrGetPucchRntiCb ARGS((
255 static RgSchCmnTpcRntiCb* rgSCHPwrGetPuschRntiCb ARGS((
259 static Void rgSCHPwrAddUeToPucchTpcRntiCb ARGS((
261 RgSchCmnTpcRntiCb *cb,
264 static Void rgSCHPwrDelUeFrmPucchTpcRntiCb ARGS((
266 RgSchCmnTpcRntiCb *cb,
269 static Void rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb ARGS((
271 RgSchCmnTpcRntiCb *cb,
274 static Void rgSCHPwrRmvSchdUeOnlyFrmPucchTpcRntiCb ARGS((
276 RgSchCmnTpcRntiCb *cb,
279 static Void rgSCHPwrRmvSchdPucchTpcRntiCb ARGS((
281 RgSchCmnTpcRntiCb *cb
283 static Void rgSCHPwrAddSchdUeToPucchTpcRntiCb ARGS((
285 RgSchCmnTpcRntiCb *cb,
288 static Void rgSCHPwrAddSchdPucchTpcRntiCb ARGS((
290 RgSchCmnTpcRntiCb *cb
292 static Void rgSCHPwrAddUeToPuschTpcRntiCb ARGS((
293 RgSchCmnTpcRntiCb *cb,
296 static Void rgSCHPwrAddSchdUeToPuschTpcRntiCb ARGS((
298 RgSchCmnTpcRntiCb *cb,
301 static Void rgSCHPwrDelUeFrmPuschTpcRntiCb ARGS((
303 RgSchCmnTpcRntiCb *cb,
306 static Void rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb ARGS((
308 RgSchCmnTpcRntiCb *cb,
311 static Void rgSCHPwrRmvSchdUeOnlyFrmPuschTpcRntiCb ARGS((
313 RgSchCmnTpcRntiCb *cb,
316 static Void rgSCHPwrAddSchdPuschTpcRntiCb ARGS((
318 RgSchCmnTpcRntiCb *cb
320 static Void rgSCHPwrRmvSchdPuschTpcRntiCb ARGS((
322 RgSchCmnTpcRntiCb *cb
324 static S16 rgSCHPwrChkPucchTpcRntiIdx ARGS((
325 RgSchCmnTpcRntiCb *cb,
328 static S16 rgSCHPwrChkPuschTpcRntiIdx ARGS((
329 RgSchCmnTpcRntiCb *cb,
332 static S16 rgSCHPwrChkUniqPucchTpcRntiIdx ARGS((
333 RgSchCmnTpcRntiCb *cb,
336 static S16 rgSCHPwrChkUniqPuschTpcRntiIdx ARGS((
337 RgSchCmnTpcRntiCb *cb,
340 static S16 rgSCHPwrChkTpcRntiIdx ARGS((
341 RgSchCmnTpcRntiCb *cb,
344 static S8 rgSCHPwrGetPhValFromPhr ARGS((
347 static S8 rgSCHPwrGetPCMaxValFromPCMax ARGS((
355 * @brief Does power related initialisation (not cell specific).
360 * Function : rgSCHPwrInit
363 * - This shall precompute coding efficiency to power
364 * mappings (assuming beta of 1).
372 rgSchPwrCqiToPwrTbl[0] = 0; /* This should never be used anyway */
373 for (idx = 1; idx < RG_SCH_CMN_UL_NUM_CQI; ++idx)
375 rgSchPwrCqiToPwrTbl[idx] = rgSCHPwrCalcEfficncyPwr(rgSchCmnUlCqiTbl[idx].eff);
380 /***********************************************************
382 * Func : rgSCHPwrGetCqiPwr
384 * Desc : Returns power corresponding to coding efficiency
385 * when beta pusch is assumed 1.
393 **********************************************************/
394 static S8 rgSCHPwrGetCqiPwr(uint8_t cqi)
397 return (rgSchPwrCqiToPwrTbl[cqi]);
398 } /* rgSCHPwrGetCqiPwr */
400 /***********************************************************
402 * Func : rgSCHPwrGetCqiPwrForUe
404 * Desc : If MCS control is enabled for UE, returns
405 * power corresponding to CQI, else 0.
413 **********************************************************/
414 static S8 rgSCHPwrGetCqiPwrForUe(RgSchCellCb *cell,RgSchUeCb *ue,uint8_t cqi)
416 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
418 if (!uePwr->deltaMcsEnbld)
422 return (rgSCHPwrGetCqiPwr(cqi));
423 } /* rgSCHPwrGetCqiPwrForUe */
425 /***********************************************************
427 * Func : rgSCHPwrCalcEfficncyPwr
429 * Desc : Computes power corresponding to a coding
434 * Notes: Assumes beta pusch to be 1
438 **********************************************************/
439 static S8 rgSCHPwrCalcEfficncyPwr(uint32_t eff)
441 F64 ks = 1.25; /* or F64 */
442 F64 tmp = cmPow(2, ks*eff/1024) - 1;
446 return ((S8)(10 * cmLog10(tmp)));
447 } /* rgSCHPwrCalcEfficncyPwr */
451 * @brief Returns TPC to be sent in UL allocation
455 * Function : rgSCHPwrPuschTpcForUe
457 * Invoking Module Processing:
458 * - After allocation for UE, this function shall
459 * be invoked to retrieve TPC.
460 * - This assumes that rgSCHPwrGetMaxUlRb() was
461 * invoked prior to final allocation for UE.
464 * - Just return TPC that was determined
466 * - After this, do necessary updates.
468 * @param[in] RgSchCellCb *cell
469 * @param[in] RgSchUeCb *ue
472 uint8_t rgSCHPwrPuschTpcForUe(RgSchCellCb *cell,RgSchUeCb *ue)
474 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue,cell);
478 rgSCHPwrOnSchedPuschTpc(cell, ue);
479 return (uePwr->puschTpc);
483 * @brief Handles Pusch power control for DCI format 0
487 * Function : rgSCHPwrGetMaxUlRb
489 * Invoking Module Processing:
490 * - This shall be invoked to determine maximum
491 * number of UL RBs for scheduling.
492 * - This is expected to be invoked every time
493 * priority to attempt at UE allocation. Later
494 * TPC retrieval depends on it.
497 * - Returns maximum allowed UL RBs to be granted
498 * after invoking Pusch power control.
500 * @param[in] RgSchCellCb *cell
501 * @param[in] RgSchUeCb *ue
504 uint8_t rgSCHPwrGetMaxUlRb(RgSchCellCb *cell,RgSchUeCb *ue)
506 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
508 rgSCHPwrPuschCntrl(cell, ue); /* This stores tpc, delta and maxRb
510 return (uePwr->maxUlRbs);
514 * @brief Handles Pusch power control for DCI format 0
518 * Function : rgSCHPwrPuschCntrl
520 * Invoking Module Processing:
521 * - This shall be invoked to determine TPC
522 * and maximum number of UL RBs for scheduling
523 * (through DCI format 0).
526 * - 'remPuschPwr' is the final delta power that the UE
527 * should apply to get to target CQI.
528 * - The available headroom (availPwr) is determined.
529 * - Power command is given by considering remPuschPwr and
531 * - After factoring in the power command into availPwr, the
532 * maximum number of RBs that can be supported is determined
533 * assuming that UE is going to use transmission efficiency
534 * corresponding to current CQI.
535 * - The results determined in this function are stored
536 * in the UE power control block.
537 * - [Not doing anything of power control of msg3
538 * retransmissions now]
540 * @param[in] RgSchCellCb *cell
541 * @param[in] RgSchUeCb *ue
544 static Void rgSCHPwrPuschCntrl(RgSchCellCb *cell,RgSchUeCb *ue)
546 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
547 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
548 RgSchCmnUlCell *cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
551 uint8_t cqi = ueUl->validUlCqi;
554 uint8_t cqi = ueUl->crntUlCqi[0];
556 Bool isAcc = uePwr->isAccumulated;
563 if (!uePwr->isPhrAvail)
565 availPwr = 60; /* setting a large value so that availPwr does
566 * not constrain delta */
570 availPwr = uePwr->maxUePwr - uePwr->pwrPerRb;
571 availPwr -= rgSCHPwrGetCqiPwrForUe(cell, ue, cqi);
573 delta = uePwr->remPuschPwr;
574 rgSCHPwrGetPuschTpc(isAcc, delta, availPwr, &tpc, &delta);
577 maxRb = rgSCHPwrGetMaxRb(cell,availPwr);
579 /* Store the results in ue power control block to be used later */
580 if(maxRb < cellUl->sbSize)
582 maxRb = cellUl->sbSize;
584 if(uePwr->maxPwrDeltaByPhr < 0)
586 tmp = ueUl->validUlCqi;
587 tmp = tmp + uePwr->maxPwrDeltaByPhr;
590 ueUl->validUlCqi = 1;
594 ueUl->validUlCqi = tmp;
599 DU_LOG("\nDEBUG --> SCH : UEID:%d Output Max Rb (%d), phVal (%d) AvailPwr (%d) ",
600 ue->ueId, maxRb, uePwr->phVal, availPwr);
601 DU_LOG("\nDEBUG --> SCH : UEID:%d pwrPerRb %d remPuschPwr %d",
605 uePwr->delta = delta;
606 uePwr->maxUlRbs = maxRb;
607 uePwr->puschTpc = tpc;
612 * @brief Returns TPC to be sent in DL allocation
616 * Function : rgSCHPwrPucchTpcForUe
618 * Invoking Module Processing:
619 * - After DL allocation for UE, this function shall
620 * be invoked to obtain TPC.
623 * - Do Pucch power control processing
626 * @param[in] RgSchCellCb *cell
627 * @param[in] RgSchUeCb *ue
630 uint8_t rgSCHPwrPucchTpcForUe(RgSchCellCb *cell,RgSchUeCb *ue)
632 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
634 rgSCHPwrPucchCntrl(cell, ue);
635 return (uePwr->pucchTpc);
638 /***********************************************************
640 * Func : rgSCHPwrGetDelta2FrmCqi
642 * Desc : Get power to be applied to achieve
643 * target CQI (the power returned is
644 * twice is actual power)
652 **********************************************************/
653 static S8 rgSCHPwrGetDelta2FrmCqi(uint8_t crntCqi,uint8_t trgCqi,RgSchUeCb *ue,RgSchCellCb *cell)
655 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
657 if (uePwr->isPhrAvail)
659 //uePwr->maxPwrDeltaByPhr = uePwr->maxPwrPerRb - uePwr->pwrPerRb - uePwr->remPuschPwr;
660 uePwr->maxPwrDeltaByPhr = uePwr->maxPwrPerRb - uePwr->pwrPerRb;
664 uePwr->maxPwrDeltaByPhr = 0;
667 if (uePwr->maxPwrDeltaByPhr < 0 && (trgCqi - crntCqi) *
668 RG_SCH_UL_CQI_DB_STEP_2 > 0)
672 return (RGSCH_MIN(uePwr->maxPwrDeltaByPhr,
673 (trgCqi - crntCqi) * RG_SCH_UL_CQI_DB_STEP_2));
674 } /* rgSCHPwrGetDelta2FrmCqi */
676 /***********************************************************
678 * Func : rgSCHPwrGetPuschTpc
680 * Desc : Based on whether accumulation is enabled or
681 * not, this returns an applicable power delta
682 * to be applied based on the input delta.
690 **********************************************************/
691 static Void rgSCHPwrGetPuschTpc(uint8_t isAcc,S8 delta,S8 availPwr,uint8_t *tpc,S8 *tpcDelta)
694 delta = RGSCH_MIN(delta, availPwr);
696 /* As of now, the functions below possibly cause delta
697 * to be breached by 1 only. So calling these as is. */
700 rgSCHPwrGetAcc2bitTpc(delta, tpc, tpcDelta);
704 rgSCHPwrGetAbsTpc(delta, tpc, tpcDelta);
707 } /* rgSCHPwrGetPuschTpc */
709 /***********************************************************
711 * Func : rgSCHPwrGetMaxRb
713 * Desc : Get the maximum number of RBs that can be
714 * expected to be supported by the passed
723 **********************************************************/
724 static uint8_t rgSCHPwrGetMaxRb(RgSchCellCb *cell,S8 pwr)
726 RgSchCmnUlCell *cellUl;
728 cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
731 /* Give 4 RBS so that UE can report changed power status*/
732 /* [ccpu00119916] Mod -return 0th index of rgSchPwrToRbTbl when pwr <=0
733 * Change the Macros from RGSCH_MAX_DL_BW to RGSCH_MAX_UL_BW*/
734 return (rgSchPwrToRbTbl[0]);
736 if (pwr > rgSchPwrRbToPwrTbl[cellUl->maxUlBwPerUe])
738 return (cellUl->maxUlBwPerUe);
740 return (RGSCH_MIN(cellUl->maxUlBwPerUe,rgSchPwrToRbTbl[(uint8_t)pwr]));
741 } /* rgSCHPwrGetMaxRb */
743 /***********************************************************
745 * Func : rgSCHPwrRbToPwr
747 * Desc : Get the power corresponding to number of RBs
755 **********************************************************/
756 static uint8_t rgSCHPwrRbToPwr(RgSchCellCb *cell,uint8_t numRb)
759 RgSchCmnUlCell *cellUl;
761 #if (ERRCLASS & ERRCLS_DEBUG)
762 cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
763 if (numRb > cellUl->maxUlBwPerUe)
765 numRb = cellUl->maxUlBwPerUe;
768 return (rgSchPwrRbToPwrTbl[numRb]);
769 } /* rgSCHPwrRbToPwr */
773 * @brief Handles Pucch power control for DCI formats 1A/1B/1D/1/2A/2
777 * Function : rgSCHPwrPucchCntrl
780 * - Determine 2 bit TPC to be sent using remPucchPwr.
781 * - Update remPucchPwr appropriately
783 * @param[in] RgSchCellCb *cell
784 * @param[in] RgSchUeCb *ue
787 static Void rgSCHPwrPucchCntrl(RgSchCellCb *cell,RgSchUeCb *ue)
790 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
792 rgSCHPwrGetAcc2bitTpc(uePwr->remPucchPwr, &uePwr->pucchTpc, &delta);
793 rgSCHPwrOnSchedPucchTpc(cell, ue, delta);
798 * @brief Handles group power control for DCI formats 3/3A for Pucch and Pusch
802 * Function : rgSCHPwrGrpCntrlPucch
804 * Invoking Module Processing:
805 * - This shall be invoked to do group power control for
806 * all TPC RNTIs for which it is deemed necessary to
807 * do the same (group power control).
808 * - This function should only be invoked after all UEs
809 * have been scheduled for uplink (re)transmissions
810 * requiring DL DCI format in the passed subframe.
813 * - For Pucch group power control
814 * - For each TPC-Pucch-RNTI in the pucchGrpPwr List and
815 * TPC-Pusch-RNTI in the puschGrpPwr List,
816 * - Request for PDCCH, skip if not available
817 * - Form DCI format 3/3A information depending
818 * on the format type of the TPC-RNTI and add it to the sub-frame.
819 * - For each Ue in ueLst of TPC RNTI Cb
820 * - if (fmtType == 3A)
821 * - if((Ue not scheduled DL dci formats)
822 * && (remPwr >= 2 || remPwr <= -2))
823 * - Determine TPC. Set puschTpc/pucchTpc.
825 * - if (remPwr >= -1 && remPwr <= 1)
826 * - If already added, remove from toBeSchdLst
828 * - Toggle the remainig power value
829 * - else if (fmtType == 3)
830 * - if((Ue not scheduled DL dci formats)
832 * - Determine TPC. Set puschTpc/pucchTpc.
835 * - If already added, remove from toBeSchdLst
836 * - if (!toBeSchdUeCnt)
837 * - Remove the tpcRntiCb frm pucchGrpPwr/puschGrpPwr List
838 * - else, Move the tpcRntiCb to end of the list (not doing
841 * @param[in] RgSchCellCb *cell
842 * @param[in] RgSchDlSf *dlSf
845 Void rgSCHPwrGrpCntrlPucch(RgSchCellCb *cell,RgSchDlSf *dlSf)
847 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
852 lst = &cellPwr->pucchGrpPwr;
854 while (lnk && ((pdcch = rgSCHCmnCmnPdcchAlloc(cell, dlSf)) != NULLP))
856 RgSchCmnTpcRntiCb *cb = (RgSchCmnTpcRntiCb *)lnk->node;
859 rgSCHPwrSchedPucchRnti(cell, cb, pdcch, dlSf, &sched);
862 rgSCHUtlPdcchPut(cell, &dlSf->pdcchInfo, pdcch);
864 /* TPC RNTI would not have been removed if needs to
865 * be scheduled again */
872 * @brief Handles group power control for DCI formats 3/3A for Pusch and Pusch
876 * Function : rgSCHPwrGrpCntrlPusch
878 * Invoking Module Processing:
879 * - This shall be invoked to do group power control for
880 * all TPC RNTIs for which it is deemed necessary to
881 * do the same (group power control).
882 * - This function should only be invoked after all UEs
883 * have been scheduled for uplink (re)transmissions
884 * requiring DCI format 0 in the passed subframe.
887 * - For Pusch group power control
888 * - For each TPC-Pusch-RNTI in the puschGrpPwr List and
889 * - Request for PDCCH, skip if not available
890 * - Form DCI format 3/3A information depending
891 * on the format type of the TPC-RNTI and add it to the sub-frame.
892 * - For each Ue in ueLst of TPC RNTI Cb
893 * - if (fmtType == 3A)
894 * - if (Ue not scheduled for dci format 0) and
895 * (remPwr >= 2 || remPwr <= -2))
896 * - Determine TPC. Set puschTpc/puschTpc.
898 * - if (remPwr >= -1 && remPwr <= 1)
899 * - If already added, remove from toBeSchdLst
901 * - Toggle the remainig power value
902 * - else if (fmtType == 3)
903 * - if((Ue not scheduled for dci format 0) && (remPwr))
904 * - Determine TPC. Set puschTpc.
907 * - If already added, remove from toBeSchdLst
908 * - if (!toBeSchdUeCnt)
909 * - Remove the tpcRntiCb frm puschGrpPwr/puschGrpPwr List
910 * - else, Move the tpcRntiCb to end of the list (not doing
913 * @param[in] RgSchCellCb *cell
914 * @param[in] RgSchDlSf *sf
917 Void rgSCHPwrGrpCntrlPusch(RgSchCellCb *cell,RgSchDlSf *dlSf,RgSchUlSf *ulSf)
919 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
924 lst = &cellPwr->puschGrpPwr;
926 while (lnk && ((pdcch = rgSCHCmnCmnPdcchAlloc(cell, dlSf)) != NULLP))
928 RgSchCmnTpcRntiCb *cb = (RgSchCmnTpcRntiCb *)lnk->node;
931 rgSCHPwrSchedPuschRnti(cell, cb, pdcch, ulSf, &sched);
934 rgSCHUtlPdcchPut(cell, &dlSf->pdcchInfo, pdcch);
936 /* TPC RNTI would not have been removed if needs to
937 * be scheduled again */
943 /***********************************************************
945 * Func : rgSCHPwrSchedPucchRnti
947 * Desc : Schedule TPC RNTI to be sent out
955 **********************************************************/
956 static Void rgSCHPwrSchedPucchRnti(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchPdcch *pdcch,RgSchDlSf *dlSf,Bool *sched)
965 pdcch->rnti = cb->tpcRnti;
969 /* Go through all UEs for format 3A case */
971 pdcch->dci.dciFormat = TFU_DCI_FORMAT_3A;
972 pdcch->dciNumOfBits = cell->dciSize.size[TFU_DCI_FORMAT_3A];
973 pdcch->dci.u.format3AInfo.isPucch = TRUE;
975 tpcCmds = pdcch->dci.u.format3AInfo.tpcCmd;
976 /* No need to memset zero initially as every TPC is going
977 * to be filled up for every configured UE */
978 for (atleastOne = FALSE, lnk = lst->first; lnk; lnk = lnk->next)
980 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
981 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
983 if ( ue->isDrxEnabled == TRUE &&
984 !RG_SCH_DRX_DL_IS_UE_ACTIVE(ue->drxCb))
986 /* UE is in its DRX time. So we cannot give command
992 if (rgSCHPwrIsDlUeSched(cell, ue, dlSf))
994 /* UE already scheduled in downlink with PDCCH
995 * carrying PUCCH pwr cmd. So don't care about
996 * giving command to this UE. */
999 rgSCHPwrGetPucchFmt3aTpcForUe(ue, &tpc, &delta);
1000 tpcCmds[uePwr->pucchIdx] = tpc;
1002 rgSCHPwrOnPucchGrpPwrForUe(cell, ue, delta);
1007 /* Go through to-be-scheduled UEs for format 3 case */
1008 lst = &cb->toBeSchdUes;
1009 pdcch->dci.dciFormat = TFU_DCI_FORMAT_3;
1010 pdcch->dciNumOfBits = cell->dciSize.size[TFU_DCI_FORMAT_3];
1011 tpcCmds = pdcch->dci.u.format3Info.tpcCmd;
1012 pdcch->dci.u.format3Info.isPucch = TRUE;
1014 /* Fill TPC 1 (corresponding to no power change) initially */
1015 memset(tpcCmds, 1, sizeof(pdcch->dci.u.format3Info.tpcCmd));
1017 for (atleastOne = FALSE, lnk = lst->first; lnk; lnk = lnk->next)
1019 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
1020 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1022 if ( ue->isDrxEnabled == TRUE &&
1023 !RG_SCH_DRX_DL_IS_UE_ACTIVE(ue->drxCb))
1025 /* UE is in its DRX time. So we cannot give command
1031 if (rgSCHPwrIsDlUeSched(cell, ue, dlSf))
1033 /* UE already scheduled in downlink with PDCCH
1034 * carrying PUCCH pwr cmd. So don't care about
1035 * giving command to this UE. */
1038 rgSCHPwrGetPucchFmt3TpcForUe(ue, &tpc, &delta);
1039 tpcCmds[uePwr->pucchIdx] = tpc;
1041 rgSCHPwrOnPucchGrpPwrForUe(cell, ue, delta);
1045 *sched = atleastOne;
1047 /* Check if no more UEs in TPC RNTI, and then remove
1048 * this TPC RNTI from scheduled list */
1049 if (cb->toBeSchdUes.count == 0)
1051 rgSCHPwrRmvSchdPucchTpcRntiCb(cell, cb);
1055 } /* rgSCHPwrSchedPucchRnti */
1057 /***********************************************************
1059 * Func : rgSCHPwrSchedPuschRnti
1061 * Desc : Schedule TPC RNTI to be sent out
1069 **********************************************************/
1070 static Void rgSCHPwrSchedPuschRnti(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchPdcch *pdcch,RgSchUlSf *ulSf,Bool *sched)
1079 pdcch->rnti = cb->tpcRnti;
1083 /* Go through all UEs for format 3A case */
1085 pdcch->dci.dciFormat = TFU_DCI_FORMAT_3A;
1086 pdcch->dciNumOfBits = cell->dciSize.size[TFU_DCI_FORMAT_3A];
1087 pdcch->dci.u.format3AInfo.isPucch = FALSE;
1088 tpcCmds = pdcch->dci.u.format3AInfo.tpcCmd;
1089 /* No need to memset zero initially as every TPC is going
1090 * to be filled up for every configured UE */
1091 for (atleastOne = FALSE, lnk = lst->first; lnk; lnk = lnk->next)
1093 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
1094 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1095 if (rgSCHPwrIsUlUeSched(cell, ue, ulSf))
1097 /* UE already scheduled in uplink with DCI
1098 * format 0. So don't care about giving
1099 * command to this UE. */
1103 if ( ue->isDrxEnabled == TRUE &&
1104 !RG_SCH_DRX_DL_IS_UE_ACTIVE(ue->drxCb))
1106 /* UE is in its DRX time. So we cannot give command
1112 rgSCHPwrGetPuschFmt3aTpcForUe(ue, &tpc, &delta);
1113 tpcCmds[uePwr->puschIdx] = tpc;
1115 rgSCHPwrOnPuschGrpPwrForUe(cell, ue, delta);
1120 /* Go through to-be-scheduled UEs for format 3 case */
1121 lst = &cb->toBeSchdUes;
1122 pdcch->dci.dciFormat = TFU_DCI_FORMAT_3;
1123 pdcch->dciNumOfBits = cell->dciSize.size[TFU_DCI_FORMAT_3];
1124 pdcch->dci.u.format3Info.isPucch = FALSE;
1125 tpcCmds = pdcch->dci.u.format3Info.tpcCmd;
1127 /* Fill TPC 1 (corresponding to no power change) initially */
1128 memset(tpcCmds, 1, sizeof(pdcch->dci.u.format3Info.tpcCmd));
1130 for (atleastOne = FALSE, lnk = lst->first; lnk; lnk = lnk->next)
1132 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
1133 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1134 if (rgSCHPwrIsUlUeSched(cell, ue, ulSf))
1136 /* UE already scheduled in uplink with DCI
1137 * format 0. So don't care about giving
1138 * command to this UE. */
1142 if ( ue->isDrxEnabled == TRUE &&
1143 !RG_SCH_DRX_DL_IS_UE_ACTIVE(ue->drxCb))
1145 /* UE is in its DRX time. So we cannot give command
1151 rgSCHPwrGetPuschFmt3TpcForUe(ue, &tpc, &delta);
1152 tpcCmds[uePwr->puschIdx] = tpc;
1154 rgSCHPwrOnPuschGrpPwrForUe(cell, ue, delta);
1158 *sched = atleastOne;
1160 /* Check if no more UEs in TPC RNTI, and then remove
1161 * this TPC RNTI from scheduled list */
1162 if (cb->toBeSchdUes.count == 0)
1164 rgSCHPwrRmvSchdPuschTpcRntiCb(cell, cb);
1168 } /* rgSCHPwrSchedPuschRnti */
1170 /***********************************************************
1172 * Func : rgSCHPwrGetPucchFmt3TpcForUe
1174 * Desc : Gets 2 bit TPC cmd for PUCCH
1182 **********************************************************/
1183 static Void rgSCHPwrGetPucchFmt3TpcForUe(RgSchUeCb *ue,uint8_t *tpc,S8 *delta)
1185 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1187 rgSCHPwrGetAcc2bitTpc(uePwr->remPucchPwr, tpc, delta);
1189 } /* rgSCHPwrGetPucchFmt3TpcForUe */
1191 /***********************************************************
1193 * Func : rgSCHPwrGetPucchFmt3aTpcForUe
1195 * Desc : Gets 1 bit TPC cmd for PUCCH
1203 **********************************************************/
1204 static Void rgSCHPwrGetPucchFmt3aTpcForUe(RgSchUeCb *ue,uint8_t *tpc,S8 *delta)
1206 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1208 rgSCHPwrGetAcc1bitTpc(uePwr->remPucchPwr, tpc, delta);
1210 } /* rgSCHPwrGetPucchFmt3aTpcForUe */
1212 /***********************************************************
1214 * Func : rgSCHPwrGetPuschFmt3TpcForUe
1216 * Desc : Gets 2 bit TPC cmd for PUCCH
1224 **********************************************************/
1225 static Void rgSCHPwrGetPuschFmt3TpcForUe(RgSchUeCb *ue,uint8_t *tpc,S8 *delta)
1227 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1228 S8 adj = RGSCH_MIN(uePwr->remPuschPwr, uePwr->phVal);
1230 rgSCHPwrGetAcc2bitTpc(adj, tpc, delta);
1232 } /* rgSCHPwrGetPuschFmt3TpcForUe */
1234 /***********************************************************
1236 * Func : rgSCHPwrGetPuschFmt3aTpcForUe
1238 * Desc : Gets 1 bit TPC cmd for PUCCH
1246 **********************************************************/
1247 static Void rgSCHPwrGetPuschFmt3aTpcForUe(RgSchUeCb *ue,uint8_t *tpc,S8 *delta)
1249 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1251 /* Don't attempt to look at headroom now, power
1252 * adjustment is small anyway */
1253 rgSCHPwrGetAcc1bitTpc(uePwr->remPuschPwr, tpc, delta);
1255 } /* rgSCHPwrGetPuschFmt3aTpcForUe */
1257 /***********************************************************
1259 * Func : rgSCHPwrGetAcc1bitTpc
1261 * Desc : Gets 1 bit TPC cmd
1269 **********************************************************/
1270 static Void rgSCHPwrGetAcc1bitTpc(S8 remPwr,uint8_t *tpc,S8 *delta)
1288 } /* rgSCHPwrGetAcc1bitTpc */
1290 /***********************************************************
1292 * Func : rgSCHPwrGetAcc2bitTpc
1294 * Desc : Allocate PDCCH for group power control
1302 **********************************************************/
1303 static Void rgSCHPwrGetAcc2bitTpc(S8 remPwr,uint8_t *tpc,S8 *delta)
1312 uint8_t tpcs[3] = {1, 2, 2};
1313 uint8_t deltas[3] = {0, 1, 1};
1319 else if (remPwr >= 3)
1326 *tpc = tpcs[(uint8_t)remPwr];
1327 *delta = deltas[(uint8_t)remPwr];
1330 } /* rgSCHPwrGetAcc2bitTpc */
1332 /***********************************************************
1334 * Func : rgSCHPwrGetAbsTpc
1336 * Desc : Allocate PDCCH for group power control
1344 **********************************************************/
1345 static Void rgSCHPwrGetAbsTpc(S8 remPwr,uint8_t *tpc,S8 *delta)
1359 else if (remPwr < 1)
1364 else if (remPwr < 4)
1375 } /* rgSCHPwrGetAbsTpc */
1377 /***********************************************************
1379 * Func : rgSCHPwrOnPucchGrpPwrForUe
1381 * Desc : Processing on sending TPC for UE through group power
1382 * control. Apart from updating remPwr, this only takes
1383 * care of possibly removing UE from scheduled
1385 * It does not take care of possibly removing TPC RNTI
1386 * from scheduled list in cell. This is done
1387 * in the caller after TPC for all UEs has been
1388 * determined. (This is where it differs
1389 * from the usual OnSendingPu[cs]ch TPC]
1397 **********************************************************/
1398 static Void rgSCHPwrOnPucchGrpPwrForUe(RgSchCellCb *cell,RgSchUeCb *ue,S8 delta)
1400 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1405 uePwr->remPucchPwr -= delta;
1407 /* UE was already scheduled for PUCCH group power
1408 * control which is why we came here. Don't
1409 * again check for this. */
1411 /* UE was scheduled for pucch grp pwr, sent TPC may
1412 * possibly cause it to be removed. */
1413 if (!uePwr->remPucchPwr)
1419 rgSCHPwrRmvSchdUeOnlyFrmPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb, ue);
1420 /* Not removing TPC RNTI from scheduled list,
1421 * this will happen in the caller once this
1422 * function is called for every UE scheduled. */
1427 /***********************************************************
1429 * Func : rgSCHPwrOnPuschGrpPwrForUe
1431 * Desc : Processing on sending TPC for UE through group power
1432 * control. Apart from updating remPwr, this only takes
1433 * care of possibly removing UE from scheduled
1435 * It does not take care of possibly removing TPC RNTI
1436 * from scheduled list in cell. This is done
1437 * in the caller after TPC for all UEs has been
1438 * determined. (This is where it differs
1439 * from the usual OnSendingPu[cs]ch TPC]
1447 **********************************************************/
1448 static Void rgSCHPwrOnPuschGrpPwrForUe(RgSchCellCb *cell,RgSchUeCb *ue,S8 delta)
1450 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
1455 uePwr->delta = delta;
1456 uePwr->remPuschPwr -= delta;
1457 if (uePwr->isPhrAvail)
1459 uePwr->phVal -= uePwr->delta;
1460 uePwr->phVal = RGSCH_MAX(-23, uePwr->phVal);
1463 /* UE was already scheduled for PUSCH group power
1464 * control which is why we came here. Don't
1465 * again check for this. */
1467 /* UE was scheduled for pusch grp pwr, sent TPC may
1468 * possibly cause it to be removed. */
1470 if (!uePwr->remPuschPwr)
1477 rgSCHPwrRmvSchdUeOnlyFrmPuschTpcRntiCb(cell, uePwr->tpcPuschRntiCb, ue);
1478 /* Not removing TPC RNTI from scheduled list,
1479 * this will happen in the caller once this
1480 * function is called for every UE scheduled. */
1485 /***********************************************************
1487 * Func : rgSCHPwrIsDlUeSched
1489 * Desc : Check if UE is scheduled in the passed DL SF
1497 **********************************************************/
1498 static Bool rgSCHPwrIsDlUeSched(RgSchCellCb *cell,RgSchUeCb *ue,RgSchDlSf *sf)
1500 RgSchDlHqEnt *hqEnt = RG_SCH_CMN_GET_UE_HQE(ue, cell);
1501 RgSchDlHqProcCb *proc = rgSCHDhmLastSchedHqProc(hqEnt);
1509 * The following subframe check is assumed enough, since
1510 * scheduled procs stay for a short time (until feedback
1511 * arrives), which typically is expected to have a
1512 * turnaround time of less than 8 subframes. So
1513 * we are probably never going to come across cases
1514 * where a process stays in the list for more than
1515 * 10 subframes, which would have otherwise caused
1516 * the check to succeed for a possibly older process.
1518 if ((proc->tbInfo[0].timingInfo.slot == sf->sfNum) ||
1519 (proc->tbInfo[1].timingInfo.slot == sf->sfNum))
1522 * Later, if a proc can be scheduled without having an
1523 * associated PDCCH, need to also check if PDCCH exists.
1524 * This is because for power, what matters is whether
1525 * TPC is going out for UE at this time or not, at least
1526 * that is what this function was introduced for.
1527 * Checking for PDCCH would have to be in common proc
1528 * the way things are now.
1536 } /* rgSCHPwrIsDlUeSched */
1538 /***********************************************************
1540 * Func : rgSCHPwrIsUlUeSched
1542 * Desc : Check if UE is scheduled in the passed UL SF
1550 **********************************************************/
1551 static Bool rgSCHPwrIsUlUeSched(RgSchCellCb *cell,RgSchUeCb *ue,RgSchUlSf *sf)
1553 RgSchCmnUlCell *cmnCell = RG_SCH_CMN_GET_UL_CELL(cell);
1554 RgSchUlHqProcCb *proc = rgSCHUhmGetUlHqProc(cell, ue, cmnCell->schdHqProcIdx);
1558 #if (ERRCLASS & ERRCLS_DEBUG)
1573 } /* rgSCHPwrIsUlUeSched */
1576 * @brief Handles Pucch power delta indication recieved from PHY
1580 * Function : rgSCHPwrPucchDeltaInd
1582 * Invoking Module Processing:
1583 * - This shall be invoked on reception of Pucch power
1584 * delta indication from PHY.
1587 * - Update the remPucchPwr
1588 * ue->remPucchPwr = pwrDelta
1589 * - If (ue->tpcPucchRntiCb)
1590 * - If (fmtType = 3A)
1591 * - if (remPucchPwr >= 2 || remPucchPwr <= -2 )
1592 * - if (tpcPucchRntiCb is not in the pucchGrpPwr List)
1593 * - Add tpcPucchRntiCb to the pucchGrpPwr list.
1594 * - If not added, add to toBeSchdLst
1596 * - If already added, remove from toBeSchdLst
1597 * - else If (fmtType == 3)
1598 * - if (remPucchPwr)
1599 * - if (tpcPucchRntiCb is not in the pucchGrpPwr List)
1600 * - Add tpcPucchRntiCb to the pucchGrpPwr list.
1601 * - If not added, add to toBeSchdLst
1603 * - If already added, remove from toBeSchdLst
1605 * @param[in] RgSchCellCb *cell
1606 * @param[in] RgSchUeCb *ue
1607 * @param[in] uint8_t pwrDelta
1610 Void rgSCHPwrPucchDeltaInd(RgSchCellCb *cell,RgSchUeCb *ue,S8 pwrDelta)
1612 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1613 RgSchCmnTpcRntiCb *cb;
1616 uePwr->remPucchPwr = pwrDelta;
1618 if ((cb = uePwr->tpcPucchRntiCb) == NULLP)
1625 if (0 != uePwr->remPucchPwr)
1633 rgSCHPwrAddSchdUeToPucchTpcRntiCb(cell, cb, ue);
1637 rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb(cell, cb, ue);
1644 * @brief Does processing after TPC for Pucch has been sent
1648 * Function : rgSCHPwrOnSchedPucchTpc
1650 * Invoking Module Processing:
1651 * - It shall be invoked after it is determined that PDCCH for UE
1652 * is finalised to go out, and thus TPC for PUCCH is being
1656 * - Update remPucchPwr with the delta
1657 * - Do group power control related processing
1659 * @param[in] RgSchCellCb *cell
1660 * @param[in] RgSchUeCb *ue
1661 * @param[in] S8 delta
1664 static Void rgSCHPwrOnSchedPucchTpc(RgSchCellCb *cell,RgSchUeCb *ue,S8 delta)
1666 /* Similar to rgSCHPwrPucchDeltaInd.. not reusing
1667 * that since we use the fact that UE could only have
1668 * improved its remPwr as part of power control. */
1669 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1672 uePwr->remPucchPwr -= delta;
1674 if (uePwr->schdPucchGrpLnk.node == NULLP)
1679 /* UE was scheduled for TPC, sent TPC may
1680 * possibly cause it to be removed. */
1682 if (!uePwr->remPucchPwr)
1689 rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb, ue);
1690 if (uePwr->tpcPucchRntiCb->toBeSchdUes.count == 0)
1692 rgSCHPwrRmvSchdPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb);
1700 * @brief Does processing after TPC for Pusch has been sent
1704 * Function : rgSCHPwrOnSchedPuschTpc
1708 * - Update remPuschPwr with the delta
1709 * - Do group power related processing if applicable
1711 * @param[in] RgSchCellCb *cell
1712 * @param[in] RgSchUeCb *ue
1715 static Void rgSCHPwrOnSchedPuschTpc(RgSchCellCb *cell,RgSchUeCb *ue)
1717 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1720 /* Don't do anything for the case of absolute TPC commands */
1721 if (!uePwr->isAccumulated)
1726 uePwr->remPuschPwr -= uePwr->delta;
1727 if (uePwr->isPhrAvail)
1729 uePwr->phVal -= uePwr->delta;
1730 uePwr->phVal = RGSCH_MAX(-23, uePwr->phVal);
1733 if (uePwr->schdPuschGrpLnk.node == NULLP)
1738 /* UE was scheduled for pusch TPC, sent TPC may
1739 * possibly cause it to be removed. */
1741 if (!uePwr->remPuschPwr)
1748 rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb(cell, uePwr->tpcPuschRntiCb, ue);
1755 * @brief Handles PHR updation for the UE
1759 * Function : rgSCHPwrUpdExtPhr
1760 * @param[in] RgSchCellCb *cell
1761 * @param[in] RgSchUeCb *ue
1762 * @param[in] RgInfExtPhrCEInfo *extPhr
1763 * @param[in] RgSchCmnAllocRecord allocInfo
1766 Void rgSCHPwrUpdExtPhr(RgSchCellCb *cell,RgSchUeCb *ue,RgInfExtPhrCEInfo *extPhr,RgSchCmnAllocRecord *allocInfo)
1769 RgInfExtPhrSCellInfo *servCellPhr;
1772 for (idx = 0; idx < extPhr->numServCells; idx++)
1774 servCellPhr = &extPhr->servCellPhr[idx];
1776 if (RG_SCH_REF_PCMAX == servCellPhr->pCmax)
1778 pCMax = RG_SCH_CMN_PWR_USE_CFG_MAX_PWR;
1782 pCMax = rgSCHPwrGetPCMaxValFromPCMax(servCellPhr->pCmax);
1784 rgSCHPwrUpdPhr(ue->cellInfo[servCellPhr->sCellIdx]->cell,
1785 ue, servCellPhr->phr, allocInfo, pCMax);
1791 * @brief Handles PHR updation for the UE
1795 * Function : rgSCHPwrUpdPhr
1797 * Invoking Module Processing:
1798 * - This shall be invoked on reception of PHR from MAC to SCH. It shall
1799 * pass the information of number of RBs, coding efficiency and TPC for
1800 * the Pusch transmission for which PHR has been reported.
1803 * - Compute power per RB using the PHR report
1804 * - ue_transmit_pwr = ue_max_pwr - PHR
1805 * - if isDeltaMcs = TRUE
1806 * - ue_transmit_pwr -
1807 * [10log(phr_num_rb) + 10log(2^ (1.25 * phr_coding_effeciency) -1)
1808 * + phr_tpc(if absolute TPC)] = pwrPerRB
1810 * - ue_transmit_pwr - [10log(phr_num_rb) + phr_tpc(if absolute TPC)]
1812 * (Use the number of RBs and efficiency used by UE which caused the PHR
1814 * - Adjust PHR according to last allocation (take into account
1815 * number of RBs granted in the last allocation)
1816 * - Update the PHR report in the control block
1817 * - Set isPhrAvail = TRUE
1818 * - Do group power control related processing if applicable
1820 * @param[in] RgSchCellCb *cell
1821 * @param[in] RgSchUeCb *ue
1822 * @param[in] uint8_t phr
1823 * @param[in] RgSchCmnAllocRecord allocInfo
1824 * @param[in] uint8_t maxUePwr
1827 Void rgSCHPwrUpdPhr(RgSchCellCb *cell,RgSchUeCb *ue,uint8_t phr,RgSchCmnAllocRecord *allocInfo,S8 maxUePwr )
1829 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1832 RgSchCmnUlCell *cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
1834 uePwr->phVal = rgSCHPwrGetPhValFromPhr(phr);
1836 if (maxUePwr == RG_SCH_CMN_PWR_USE_CFG_MAX_PWR)
1838 maxUePwr = uePwr->maxUePwr;
1840 rbPwr = rgSCHPwrRbToPwr(cell,allocInfo->numRb);
1841 effPwr = rgSCHPwrGetCqiPwrForUe(cell, ue, allocInfo->cqi);
1842 uePwr->pwrPerRb = maxUePwr - uePwr->phVal - rbPwr - effPwr;
1843 /*if (!uePwr->isAccumulated)
1845 uePwr->pwrPerRb -= rgSCHPwrGetDeltaFrmAbsTpc(allocInfo->tpc);
1848 /* Let headroom reflect remaining power according to last
1849 * allocated number of RBs. Intermediate TPCs not yet
1850 * taken care of (for accumulated case, it is anyway
1851 * not applicable for absolute commands). */
1852 uePwr->phVal -= (rgSCHPwrRbToPwr(cell, cellUl->sbSize)) - rbPwr;
1853 uePwr->phVal = RGSCH_MAX(-23, uePwr->phVal);
1854 uePwr->isPhrAvail = TRUE;
1856 rgSCHPwrOnPuschPwrUpd(cell, ue);
1858 DU_LOG("\nDEBUG --> SCH : Output: Reported PHR[%d] cqi[%u] allocRb[%u] uePwr->pwrPerRb[%d]",
1867 * @brief Handles UL CQI indication
1871 * Function : rgSCHPwrUlCqiInd
1873 * Invoking Module Processing:
1874 * - This shall be invoked when uplink CQI indication
1875 * is receiving from PHY for a UE.
1878 * - Update remPuschPwr.
1879 * - Possibly schedule for group power control.
1881 * @param[in] RgSchCellCb *cell
1882 * @param[in] RgSchUeCb *ue
1883 * @param[in] uint8_t numRb
1886 Void rgSCHPwrUlCqiInd(RgSchCellCb *cell,RgSchUeCb *ue)
1888 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
1889 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1895 * For absolute power cmd case, we could look at the time
1896 * at which CQI was received, determine if there was a
1897 * PUSCH TPC cmd for that time (this could come from
1898 * group power control too), and (if this
1899 * CQI report is indeed based on the the PUSCH tx)
1900 * then factor in that cmd here. Not doing
1904 /* See how much power needs to be adjusted based on cqi
1906 uePwr->remPuschPwr =
1908 rgSCHPwrGetDelta2FrmCqi(ueUl->validUlCqi, uePwr->trgCqi, ue, cell);
1910 rgSCHPwrGetDelta2FrmCqi(ueUl->crntUlCqi[0], uePwr->trgCqi, ue, cell);
1913 rgSCHPwrOnPuschPwrUpd(cell, ue);
1915 if(uePwr->maxPwrDeltaByPhr < 0)
1917 tmp = ueUl->validUlCqi;
1918 tmp = tmp + uePwr->maxPwrDeltaByPhr;
1921 ueUl->validUlCqi = 1;
1925 ueUl->validUlCqi = tmp;
1934 * @brief Updates the stored last number of RBs allocated
1938 * Function : rgSCHPwrRecordRbAlloc
1940 * Invoking Module Processing:
1941 * - This shall be invoked when uplink allocation is made for
1943 * - Note: If outstanding TPCs are considered at the time
1944 * of PHR report, the last numRb would also be known
1945 * and then this API would not be needed.
1948 * - Adjust PHR according to now allocated number of RBs
1949 * - Store the number of RBs
1951 * @param[in] RgSchCellCb *cell
1952 * @param[in] RgSchUeCb *ue
1953 * @param[in] uint8_t numRb
1956 Void rgSCHPwrRecordRbAlloc(RgSchCellCb *cell,RgSchUeCb *ue,uint8_t numRb)
1958 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
1962 if (uePwr->isPhrAvail)
1964 uePwr->phVal += rgSCHPwrRbToPwr(cell,numRb) - rgSCHPwrRbToPwr(cell,uePwr->numRb);
1965 uePwr->phVal = RGSCH_MIN(40, uePwr->phVal);
1967 uePwr->numRb = numRb;
1972 * @brief Handles power related configuration for a cell
1976 * Function : rgSCHPwrCellCfg
1978 * Invoking Module Processing:
1979 * - This shall be invoked during cell config
1984 * - Update TPC-RNTI information for the cell for Pucch and Pusch.
1985 * - For each TPC-Pucch-RNTI,
1986 * - Call rgSCHAddRntiToPucchRntiLst()
1987 * - For each TPC-Pusch-RNTI,
1988 * - Call rgSCHAddRntiToPuschRntiLst()
1991 * @param[in] RgSchCellCb *cell
1992 * @param[in] RgrCellCfg *cfg
1997 S16 rgSCHPwrCellCfg(RgSchCellCb *cell,RgrCellCfg *cfg)
1999 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2001 CmLteRnti startRnti;
2005 /* Right now, all UEs have fixed maximum power capability. So
2006 * we store cell wide pMax as minimum of configured pMax and
2008 cellPwr->pMax = RGSCH_MIN(cfg->pMax, RG_SCH_PWR_UE_MAX_PWR);
2010 /* trgUlCqi already validated by common */
2011 cellPwr->trgUlCqi = cfg->trgUlCqi.trgCqi;
2013 /* Validate number of TPC RNTIs */
2014 if ((cfg->pwrCfg.pucchPwrFmt3.size + cfg->pwrCfg.pucchPwrFmt3a.size
2015 > RG_SCH_CMN_MAX_NUM_TPC_PUCCH_RNTI)
2016 || (cfg->pwrCfg.puschPwrFmt3.size + cfg->pwrCfg.puschPwrFmt3a.size
2017 > RG_SCH_CMN_MAX_NUM_TPC_PUSCH_RNTI))
2022 /* Now initialise TPC RNTIs */
2024 /* Format 3 Pucch TPC RNTIs */
2026 startRnti = cfg->pwrCfg.pucchPwrFmt3.startTpcRnti;
2027 size = cfg->pwrCfg.pucchPwrFmt3.size;
2028 for (rnti = startRnti; (rnti < startRnti + size); ++rnti)
2030 rgSCHPwrAddRntiToPucchRntiLst(cell, rnti, isFmt3a);
2033 /* Format 3A Pucch TPC RNTIs */
2035 startRnti = cfg->pwrCfg.pucchPwrFmt3a.startTpcRnti;
2036 size = cfg->pwrCfg.pucchPwrFmt3a.size;
2037 for (rnti = startRnti; (rnti < startRnti + size); ++rnti)
2039 rgSCHPwrAddRntiToPucchRntiLst(cell, rnti, isFmt3a);
2042 /* Format 3 Pusch TPC RNTIs */
2044 startRnti = cfg->pwrCfg.puschPwrFmt3.startTpcRnti;
2045 size = cfg->pwrCfg.puschPwrFmt3.size;
2046 for (rnti = startRnti; (rnti < startRnti + size); ++rnti)
2048 rgSCHPwrAddRntiToPuschRntiLst(cell, rnti, isFmt3a);
2051 /* Format 3A Pusch TPC RNTIs */
2053 startRnti = cfg->pwrCfg.puschPwrFmt3a.startTpcRnti;
2054 size = cfg->pwrCfg.puschPwrFmt3a.size;
2055 for (rnti = startRnti; (rnti < startRnti + size); ++rnti)
2057 rgSCHPwrAddRntiToPuschRntiLst(cell, rnti, isFmt3a);
2064 * @brief Handles power related re-configuration for a cell
2068 * Function : rgSCHPwrCellRecfg
2073 * @param[in] RgSchCellCb *cell
2074 * @param[in] RgrCellRecfg *recfg
2078 S16 rgSCHPwrCellRecfg(RgSchCellCb *cell,RgrCellRecfg *recfg)
2083 /* Not doing anything for power reconfig, so such structure
2089 * @brief Frees power related data structures in cell
2093 * Function : rgSCHPwrCellDel
2098 * @param[in] RgSchCellCb *cell
2101 Void rgSCHPwrCellDel(RgSchCellCb *cell)
2105 /* There is no allocated memory, so do nothing */
2112 * @brief Configures ULPC CB for a SCELL being added
2116 * Function : rgSCHPwrUeSCellCfg
2118 * @param[in] RgSchCellCb *cell
2119 * @param[in] RgSchUeCb *ue
2120 * @param[in] RgrUeCfg *cfg
2125 S16 rgSCHPwrUeSCellCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeSecCellCfg *sCellInfoCfg)
2127 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2128 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2129 RgSchCmnUeUlPwrCb *uePwrPCell = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2130 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
2132 RgSchCmnUlCell *cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
2135 uePwr->maxUePwr = cellPwr->pMax;
2136 uePwr->trgCqi = cellPwr->trgUlCqi; /* Overriding with UE's happens later */
2139 uePwr->maxPwrPerRb = uePwr->maxUePwr - rgSchPwrRbToPwrTbl[cellUl->sbSize];
2141 uePwr->isPhrAvail = FALSE;
2143 uePwr->maxUlRbs = RGSCH_MAX_DL_BW;
2145 uePwr->puschTpc = 1;
2146 uePwr->remPuschPwr = 0;
2148 /* Rest of the vars update and group power control related
2149 * config happens in the function below */
2150 uePwr->isAccumulated = sCellInfoCfg->ueSCellUlDedPwrCfg.isAccumulated;
2151 uePwr->deltaMcsEnbld = sCellInfoCfg->ueSCellUlDedPwrCfg.isDeltaMCSEnabled;
2153 uePwr->trgCqi = uePwrPCell->trgCqi;
2155 if (ueUl->maxUlCqi < uePwr->trgCqi)
2157 uePwr->trgCqi = ueUl->maxUlCqi;
2159 uePwr->p0UePusch = sCellInfoCfg->ueSCellUlDedPwrCfg.p0UePusch;
2166 * @brief Handles power related configuration for a UE
2170 * Function : rgSCHPwrUeCfg
2173 * - If Pusch group power configuration exists && accumulation enabled,
2174 * - Fetch the TPC-Pusch-RNTI control block for the configured
2175 * TPC-Pusch-RNTI. Call rgSCHGetRntiFrmPuschRntiLst(). If it does not
2176 * exist, return RFAILED.
2177 * - Add Ue to the ueLst of TPC-Pusch-RNTI control block.
2178 * - Update tpcPuschRntiCb pointer in UE.
2179 * - Update the puschIdx value.
2180 * - If Pucch group power configuration exists && accumulation enabled,
2181 * - Fetch the TPC-Pucch-RNTI control block for the configured
2182 * TPC-Pucch-RNTI. Call rgSCHGetRntiFrmPucchRntiLst(). If it does not
2183 * exist, return RFAILED.
2184 * - Add Ue to the ueLst of TPC-Pucch-RNTI control block.
2185 * - Update tpcPucchRntiCb pointer in UE.
2186 * - Update the pucchIdx value.
2187 * - Update isAccumulated and isDeltaMcs variables.
2188 * - maxUlRbs = configured maximum UL bandwidth value per UE.
2189 * - trgUlCqi = configured value, if any, else cell-wide default trg CQI value.
2190 * - If format type is format 3A, update remaining power to +1
2191 * - Update TPC-RNTI information for the cell for Pucch and Pusch.
2194 * @param[in] RgSchCellCb *cell
2195 * @param[in] RgSchUeCb *ue
2196 * @param[in] RgrUeCfg *cfg
2201 S16 rgSCHPwrUeCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeCfg *cfg)
2204 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2205 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2207 RgSchCmnUlCell *cellUl = RG_SCH_CMN_GET_UL_CELL(cell);
2209 uePwr->maxUePwr = cellPwr->pMax;
2210 uePwr->trgCqi = cellPwr->trgUlCqi; /* Overriding with UE's happens later */
2213 uePwr->maxPwrPerRb = uePwr->maxUePwr - rgSchPwrRbToPwrTbl[cellUl->sbSize];
2215 rgSCHPwrUeResetPucch(cell, ue);
2216 rgSCHPwrUeResetPusch(cell, ue);
2218 /* Rest of the vars update and group power control related
2219 * config happens in the function below */
2220 ret = rgSCHPwrApplyUePwrCfg(cell, ue, &cfg->ueUlPwrCfg);
2226 * @brief Handles power related re-configuration for a UE
2230 * Function : rgSCHPwrUeRecfg
2232 * Invoking Module Processing:
2233 * - This shall be invoked by SCH_GOM at UE re-configuration.
2236 * - If change in TPC-RNTI, update the pointer and the TPC RNTI Cb appropriately.
2237 * - If accumulation disabled, remove the UE from TPC-RNTI lists of UE, if
2239 * - If group power configuration disabled, remove the UE from TPC-RNTI lists of UE, if
2242 * @param[in] RgSchCellCb *cell
2243 * @param[in] RgSchUeCb *ue
2244 * @param[in] RgrUeRecfg *recfg
2250 S16 rgSCHPwrUeRecfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeRecfg *recfg)
2253 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2254 RgrUeUlPwrCfg *pwrCfg = &recfg->ueUlPwrRecfg;
2256 if (pwrCfg->p0UePucch != uePwr->p0UePucch)
2258 rgSCHPwrUeResetPucch(cell, ue);
2260 if ((pwrCfg->isAccumulated != uePwr->isAccumulated)
2261 || (pwrCfg->p0UePusch != uePwr->p0UePusch))
2263 rgSCHPwrUeResetPusch(cell, ue);
2265 ret = rgSCHPwrApplyUePwrCfg(cell, ue, &recfg->ueUlPwrRecfg);
2270 /***********************************************************
2272 * Func : rgSCHPwrApplyUePwrCfg
2274 * Desc : Applies power config for UE. Meants to be
2275 * used during both power config and reconfig.
2283 **********************************************************/
2284 static S16 rgSCHPwrApplyUePwrCfg(RgSchCellCb *cell,RgSchUeCb *ue,RgrUeUlPwrCfg *pwrCfg)
2287 RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
2288 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2289 RgSchCmnTpcRntiCb *pucchRntiCb = NULLP;
2290 RgSchCmnTpcRntiCb *puschRntiCb = NULLP;
2291 uint8_t pucchIdx = 0;
2292 uint8_t puschIdx = 0;
2294 /* Validate Pucch group power control config */
2295 if (pwrCfg->uePucchPwr.pres)
2298 rgSCHPwrGetPucchRntiCb(cell, pwrCfg->uePucchPwr.tpcRnti);
2299 if (pucchRntiCb == NULLP)
2303 pucchIdx = pwrCfg->uePucchPwr.idx;
2304 ret = rgSCHPwrChkPucchTpcRntiIdx(pucchRntiCb, pucchIdx);
2311 /* Validate Pusch group power control config */
2312 if (pwrCfg->uePuschPwr.pres)
2315 rgSCHPwrGetPuschRntiCb(cell, pwrCfg->uePuschPwr.tpcRnti);
2316 if (puschRntiCb == NULLP)
2320 puschIdx = pwrCfg->uePuschPwr.idx;
2321 ret = rgSCHPwrChkPuschTpcRntiIdx(puschRntiCb, puschIdx);
2328 /* Apply Pucch group power control config */
2331 if (uePwr->tpcPucchRntiCb != pucchRntiCb) /* This part for recfg */
2333 if (uePwr->tpcPucchRntiCb)
2335 rgSCHPwrDelUeFrmPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb, ue);
2337 uePwr->tpcPucchRntiCb = pucchRntiCb;
2338 rgSCHPwrAddUeToPucchTpcRntiCb(cell, pucchRntiCb, ue);
2340 uePwr->pucchIdx = pucchIdx;
2342 DU_LOG("\nDEBUG --> SCH : <GRP_PWR>PucchRntiCb cfgdUes(%ld %lu %lu) UEID:%d",
2343 pucchRntiCb->cfgdUes.count,((uint32_t)pucchRntiCb->cfgdUes.first),
2344 ((uint32_t)pucchRntiCb->cfgdUes.last),ue->ueId);
2345 DU_LOG("\nDEBUG --> SCH : UEID:%d isFmt3a(%u) ueNode(%ld)",
2346 ue->ueId,pucchRntiCb->isFmt3a,
2347 pucchRntiCb->schdLnk.node);
2348 DU_LOG("\nDEBUG --> SCH : toBeSchdUes(%ld %lu %lu) tpcRnti(%u)",
2349 pucchRntiCb->toBeSchdUes.count,
2350 ((uint32_t)pucchRntiCb->toBeSchdUes.first),
2351 ((uint32_t)pucchRntiCb->toBeSchdUes.last),
2352 pucchRntiCb->tpcRnti);
2354 DU_LOG("\nDEBUG --> SCH : <GRP_PWR>PucchRntiCb cfgdUes(%d %lu %lu) UEID:%d",
2355 pucchRntiCb->cfgdUes.count,((uint64_t)pucchRntiCb->cfgdUes.first),
2356 ((uint64_t)pucchRntiCb->cfgdUes.last),ue->ueId);
2357 DU_LOG("\nDEBUG --> SCH : UEID:%d isFmt3a(%u) ueNode(%ld)",
2358 ue->ueId,pucchRntiCb->isFmt3a,
2359 pucchRntiCb->schdLnk.node);
2360 DU_LOG("\nDEBUG --> SCH : toBeSchdUes(%d %lu %lu) tpcRnti(%u)",
2361 pucchRntiCb->toBeSchdUes.count,
2362 ((uint64_t)pucchRntiCb->toBeSchdUes.first),
2363 ((uint64_t)pucchRntiCb->toBeSchdUes.last),
2364 pucchRntiCb->tpcRnti);
2369 /* Apply Pusch group power control config */
2372 if (uePwr->tpcPuschRntiCb != puschRntiCb) /* This part for recfg */
2374 if (uePwr->tpcPuschRntiCb)
2376 rgSCHPwrDelUeFrmPuschTpcRntiCb(cell, uePwr->tpcPuschRntiCb, ue);
2378 uePwr->tpcPuschRntiCb = puschRntiCb;
2379 rgSCHPwrAddUeToPuschTpcRntiCb(puschRntiCb, ue);
2381 uePwr->puschIdx = puschIdx;
2385 uePwr->isAccumulated = pwrCfg->isAccumulated;
2386 uePwr->deltaMcsEnbld = pwrCfg->isDeltaMCSEnabled;
2389 uePwr->trgCqi = pwrCfg->trgCqi;
2391 if (ueUl->maxUlCqi < uePwr->trgCqi)
2393 uePwr->trgCqi = ueUl->maxUlCqi;
2395 uePwr->p0UePusch = pwrCfg->p0UePusch;
2396 uePwr->p0UePucch = pwrCfg->p0UePucch;
2403 * @brief Deletes power related information for UE
2407 * Function : rgSCHPwrUeDel
2409 * Invoking Module Processing:
2410 * - This shall be invoked by at the time of UE deletion.
2413 * - if (ue->tpcPucchRntiCb)
2414 * - delete UE from tpcPucchRntiCb->ueLst
2415 * - ue->tpcPucchRntiCb = NULLP
2416 * - If in (ue->tpcPucchRntiCb->toBeSchdLst)
2417 * - remove from the list.
2418 * - if (ue->tpcPuschRntiCb)
2419 * - delete UE from tpcPuschRntiCb->ueLst
2420 * - ue->tpcPuschRntiCb = NULLP
2421 * - If in (ue->tpcPuschRntiCb->toBeSchdLst)
2422 * - remove from the list.
2424 * @param[in] RgSchCellCb *cell
2425 * @param[in] RgSchUeCb *ue
2428 Void rgSCHPwrUeDel(RgSchCellCb *cell,RgSchUeCb *ue)
2430 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2432 if (uePwr->tpcPucchRntiCb)
2434 rgSCHPwrDelUeFrmPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb, ue);
2435 uePwr->tpcPucchRntiCb = NULLP;
2437 if (uePwr->tpcPuschRntiCb)
2439 rgSCHPwrDelUeFrmPuschTpcRntiCb(cell, uePwr->tpcPuschRntiCb, ue);
2440 uePwr->tpcPuschRntiCb = NULLP;
2446 * @brief Resets UE's power state
2450 * Function : rgSCHPwrUeReset
2452 * Invoking Module Processing:
2453 * - This shall be invoked by at the time PDCCH order.
2456 * - Reset PUSCH power state
2457 * - Reset PUCCH power state
2459 * @param[in] RgSchCellCb *cell
2460 * @param[in] RgSchUeCb *ue
2463 Void rgSCHPwrUeReset(RgSchCellCb *cell,RgSchUeCb *ue)
2466 rgSCHPwrUeResetPucch(cell, ue);
2467 rgSCHPwrUeResetPusch(cell, ue);
2471 /***********************************************************
2473 * Func : rgSCHPwrUeResetPucch
2475 * Desc : This function is called to reset UE
2476 * to initial PUCCH power state.
2484 **********************************************************/
2485 static Void rgSCHPwrUeResetPucch(RgSchCellCb *cell,RgSchUeCb *ue)
2487 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2489 uePwr->pucchTpc = 1;
2490 uePwr->remPucchPwr = 0;
2491 if (uePwr->tpcPucchRntiCb)
2493 rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb(cell, uePwr->tpcPucchRntiCb, ue);
2496 /* Stack Crash problem for TRACE5 changes. Added the line below */
2501 /***********************************************************
2503 * Func : rgSCHPwrUeResetPusch
2505 * Desc : This function is called to reset UE
2506 * to initial PUSCH power state.
2514 **********************************************************/
2515 static Void rgSCHPwrUeResetPusch(RgSchCellCb *cell,RgSchUeCb *ue)
2517 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2519 uePwr->isPhrAvail = FALSE;
2521 uePwr->maxUlRbs = RGSCH_MAX_DL_BW;
2523 uePwr->puschTpc = 1;
2524 uePwr->remPuschPwr = 0;
2525 if (uePwr->tpcPuschRntiCb)
2527 rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb(cell, uePwr->tpcPuschRntiCb, ue);
2532 /***********************************************************
2534 * Func : rgSCHPwrOnPuschPwrUpd
2536 * Desc : This function is called whenever 'remPuschPwr'
2545 **********************************************************/
2546 static Void rgSCHPwrOnPuschPwrUpd(RgSchCellCb *cell,RgSchUeCb *ue)
2548 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, cell);
2549 RgSchCmnTpcRntiCb *cb;
2552 if ((cb = uePwr->tpcPuschRntiCb) == NULLP)
2557 /* Not checking for uwPwr->isPhrAvail as uePwr->phVal
2558 * is set to a large value initially */
2562 if ((uePwr->phVal != 0) && (uePwr->remPuschPwr != 0))
2570 rgSCHPwrAddSchdUeToPuschTpcRntiCb(cell, cb, ue);
2574 rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb(cell, cb, ue);
2581 /***********************************************************
2583 * Func : rgSCHPwrAddRntiToPucchRntiLst
2586 * Desc : Adds RNTI to Pucch Rnti list and updates requisite
2591 * Notes: Assumed that array bounds are checked
2592 * in caller before adding.
2596 **********************************************************/
2597 static Void rgSCHPwrAddRntiToPucchRntiLst(RgSchCellCb *cell,CmLteRnti rnti,Bool isFmt3a)
2599 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2601 rgSCHPwrInitTpcRntiCb(&cellPwr->tpcPucchRntiLst[cellPwr->tpcPucchRntiCnt++],
2606 /***********************************************************
2608 * Func : rgSCHPwrAddRntiToPuschRntiLst
2611 * Desc : Adds RNTI to Pusch Rnti list and updates requisite
2616 * Notes: Assumed that array bounds are checked
2617 * in caller before adding.
2621 **********************************************************/
2622 static Void rgSCHPwrAddRntiToPuschRntiLst(RgSchCellCb *cell,CmLteRnti rnti,Bool isFmt3a)
2624 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2626 rgSCHPwrInitTpcRntiCb(&cellPwr->tpcPuschRntiLst[cellPwr->tpcPuschRntiCnt++],
2631 /***********************************************************
2633 * Func : rgSCHPwrInitTpcRntiCb
2636 * Desc : Initialises a TPC RNTI CB
2644 **********************************************************/
2645 static Void rgSCHPwrInitTpcRntiCb(RgSchCmnTpcRntiCb *cb,CmLteRnti rnti,Bool isFmt3a)
2648 memset(cb, 0, sizeof(*cb));
2650 cb->isFmt3a = isFmt3a;
2651 /* Not initialising lists as memset 0 takes care of it */
2652 /* cb->schdLnk.node is set when this rnti is to be scheduled */
2656 /***********************************************************
2658 * Func : rgSCHPwrGetPucchRntiCb
2661 * Desc : Gets TPC RNTI control block from Pucch rnti list
2663 * Ret : RgSchCmnTpcRntiCb * - Success
2670 **********************************************************/
2671 static RgSchCmnTpcRntiCb* rgSCHPwrGetPucchRntiCb(RgSchCellCb *cell,CmLteRnti tpcRnti)
2673 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2676 if (!cellPwr->tpcPucchRntiCnt)
2680 for (idx = 0; idx < cellPwr->tpcPucchRntiCnt; ++idx)
2682 if (cellPwr->tpcPucchRntiLst[idx].tpcRnti == tpcRnti)
2684 return (&cellPwr->tpcPucchRntiLst[idx]);
2690 /***********************************************************
2692 * Func : rgSCHPwrGetPuschRntiCb
2695 * Desc : Gets TPC RNTI control block from Pusch rnti list
2697 * Ret : RgSchCmnTpcRntiCb * - Success
2704 **********************************************************/
2705 static RgSchCmnTpcRntiCb* rgSCHPwrGetPuschRntiCb(RgSchCellCb *cell,CmLteRnti tpcRnti)
2707 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2710 if (!cellPwr->tpcPuschRntiCnt)
2714 for (idx = 0; idx < cellPwr->tpcPuschRntiCnt; ++idx)
2716 if (cellPwr->tpcPuschRntiLst[idx].tpcRnti == tpcRnti)
2718 return (&cellPwr->tpcPuschRntiLst[idx]);
2725 /***********************************************************
2727 * Func : rgSCHPwrAddUeToPucchTpcRntiCb
2730 * Desc : Add UE to cfgd list of UEs in rnti cb
2738 **********************************************************/
2739 static Void rgSCHPwrAddUeToPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2741 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2744 cmLListAdd2Tail(&cb->cfgdUes, &uePwr->pucchGrpLnk);
2745 uePwr->pucchGrpLnk.node = (PTR)ue;
2749 /***********************************************************
2751 * Func : rgSCHPwrDelUeFrmPucchTpcRntiCb
2754 * Desc : Remove UE from Pucch TPC RNTI CB
2762 **********************************************************/
2763 static Void rgSCHPwrDelUeFrmPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2765 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2767 rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb(cell, cb, ue);
2768 cmLListDelFrm(&cb->cfgdUes, &uePwr->pucchGrpLnk);
2769 uePwr->pucchGrpLnk.node = NULLP;
2773 /***********************************************************
2775 * Func : rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb
2778 * Desc : Remove UE from to-be-scheduled list of UEs
2787 **********************************************************/
2788 static Void rgSCHPwrRmvSchdUeFrmPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2790 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2792 if (uePwr->schdPucchGrpLnk.node == NULLP)
2796 rgSCHPwrRmvSchdUeOnlyFrmPucchTpcRntiCb(cell, cb, ue);
2797 if (!cb->toBeSchdUes.count)
2799 rgSCHPwrRmvSchdPucchTpcRntiCb(cell, cb);
2804 /***********************************************************
2806 * Func : rgSCHPwrRmvSchdUeOnlyFrmPucchTpcRntiCb
2808 * Desc : Remove UE from to-be-scheduled list of UEs
2809 * in Pucch RNTI CB. Do not both about
2810 * possibly removing Pucch RNTI CB from
2811 * the cell wide to-be-scheduled list.
2819 **********************************************************/
2820 static Void rgSCHPwrRmvSchdUeOnlyFrmPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2822 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2824 if (uePwr->schdPucchGrpLnk.node != NULLP)
2826 cmLListDelFrm(&cb->toBeSchdUes, &uePwr->schdPucchGrpLnk);
2827 uePwr->schdPucchGrpLnk.node = NULLP;
2832 /***********************************************************
2834 * Func : rgSCHPwrRmvSchdPucchTpcRntiCb
2836 * Desc : Remove Pucch TPC RNTI CB from to-be-scheduled
2845 **********************************************************/
2846 static Void rgSCHPwrRmvSchdPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb)
2848 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2850 if (cb->schdLnk.node == NULLP)
2854 cmLListDelFrm(&cellPwr->pucchGrpPwr, &cb->schdLnk);
2855 cb->schdLnk.node = NULLP;
2859 /***********************************************************
2861 * Func : rgSCHPwrAddSchdUeToPucchTpcRntiCb
2863 * Desc : Add UE to to-be-scheduled list of UEs
2872 **********************************************************/
2873 static Void rgSCHPwrAddSchdUeToPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2875 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2877 if (uePwr->schdPucchGrpLnk.node != NULLP)
2879 /* UE is already in the list */
2882 cmLListAdd2Tail(&cb->toBeSchdUes, &uePwr->schdPucchGrpLnk);
2883 uePwr->schdPucchGrpLnk.node = (PTR)ue;
2884 if (cb->toBeSchdUes.count == 1)
2886 /* This is first UE, so queue up this TPC RNTI
2888 rgSCHPwrAddSchdPucchTpcRntiCb(cell, cb);
2893 /***********************************************************
2895 * Func : rgSCHPwrAddSchdPucchTpcRntiCb
2897 * Desc : Add Pucch TPC RNTI CB from to-be-scheduled
2906 **********************************************************/
2907 static Void rgSCHPwrAddSchdPucchTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb)
2909 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
2911 cmLListAdd2Tail(&cellPwr->pucchGrpPwr, &cb->schdLnk);
2912 cb->schdLnk.node = (PTR)cb;
2917 /***********************************************************
2919 * Func : rgSCHPwrAddUeToPuschTpcRntiCb
2922 * Desc : Add UE to cfgd list of UEs in rnti cb
2930 **********************************************************/
2931 static Void rgSCHPwrAddUeToPuschTpcRntiCb(RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2933 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2935 cmLListAdd2Tail(&cb->cfgdUes, &uePwr->puschGrpLnk);
2936 uePwr->puschGrpLnk.node = (PTR)ue;
2940 /***********************************************************
2942 * Func : rgSCHPwrAddSchdUeToPuschTpcRntiCb
2944 * Desc : Add UE to to-be-scheduled list of UEs
2953 **********************************************************/
2954 static Void rgSCHPwrAddSchdUeToPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2956 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2958 if (uePwr->schdPuschGrpLnk.node != NULLP)
2960 /* UE is already in the list */
2963 cmLListAdd2Tail(&cb->toBeSchdUes, &uePwr->schdPuschGrpLnk);
2964 uePwr->schdPuschGrpLnk.node = (PTR)ue;
2965 if (cb->toBeSchdUes.count == 1)
2967 /* This is first UE, so queue up this TPC RNTI
2969 rgSCHPwrAddSchdPuschTpcRntiCb(cell, cb);
2974 /***********************************************************
2976 * Func : rgSCHPwrDelUeFrmPuschTpcRntiCb
2979 * Desc : Add UE to cfgd list of UEs in rnti cb
2987 **********************************************************/
2988 static Void rgSCHPwrDelUeFrmPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
2990 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
2992 rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb(cell, cb, ue);
2993 cmLListDelFrm(&cb->cfgdUes, &uePwr->puschGrpLnk);
2994 uePwr->puschGrpLnk.node = NULLP;
2998 /***********************************************************
3000 * Func : rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb
3002 * Desc : Remove UE from to-be-scheduled list of UEs
3011 **********************************************************/
3012 static Void rgSCHPwrRmvSchdUeFrmPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
3014 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
3016 if (uePwr->schdPuschGrpLnk.node == NULLP)
3020 rgSCHPwrRmvSchdUeOnlyFrmPuschTpcRntiCb(cell, cb, ue);
3021 if (!cb->toBeSchdUes.count)
3023 rgSCHPwrRmvSchdPuschTpcRntiCb(cell, cb);
3028 /***********************************************************
3030 * Func : rgSCHPwrRmvSchdUeOnlyFrmPuschTpcRntiCb
3032 * Desc : Remove UE from to-be-scheduled list of UEs
3033 * in Pusch RNTI CB. Do not both about
3034 * possibly removing Pusch RNTI CB from
3035 * the cell wide to-be-scheduled list.
3043 **********************************************************/
3044 static Void rgSCHPwrRmvSchdUeOnlyFrmPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb,RgSchUeCb *ue)
3046 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
3048 if (uePwr->schdPuschGrpLnk.node != NULLP)
3050 cmLListDelFrm(&cb->toBeSchdUes, &uePwr->schdPuschGrpLnk);
3051 uePwr->schdPuschGrpLnk.node = NULLP;
3056 /***********************************************************
3058 * Func : rgSCHPwrAddSchdPuschTpcRntiCb
3060 * Desc : Add Pusch TPC RNTI CB from to-be-scheduled
3069 **********************************************************/
3070 static Void rgSCHPwrAddSchdPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb)
3072 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
3074 cmLListAdd2Tail(&cellPwr->puschGrpPwr, &cb->schdLnk);
3075 cb->schdLnk.node = (PTR)cb;
3079 /***********************************************************
3081 * Func : rgSCHPwrRmvSchdPuschTpcRntiCb
3083 * Desc : Remove Pusch TPC RNTI CB from to-be-scheduled
3092 **********************************************************/
3093 static Void rgSCHPwrRmvSchdPuschTpcRntiCb(RgSchCellCb *cell,RgSchCmnTpcRntiCb *cb)
3095 RgSchCmnUlPwrCb *cellPwr = RG_SCH_PWR_GETCELLPWR(cell);
3097 if (cb->schdLnk.node == NULLP)
3101 cmLListDelFrm(&cellPwr->puschGrpPwr, &cb->schdLnk);
3102 cb->schdLnk.node = NULLP;
3106 /***********************************************************
3108 * Func : rgSCHPwrChkPucchTpcRntiIdx
3110 * Desc : Validate that the given index is OK to
3111 * be assigned to a new UE for the Pucch TPC
3120 **********************************************************/
3121 static S16 rgSCHPwrChkPucchTpcRntiIdx(RgSchCmnTpcRntiCb *cb,uint8_t idx)
3124 if (rgSCHPwrChkTpcRntiIdx(cb, idx) != ROK)
3128 if (rgSCHPwrChkUniqPucchTpcRntiIdx(cb, idx) != ROK)
3135 /***********************************************************
3137 * Func : rgSCHPwrChkPuschTpcRntiIdx
3139 * Desc : Validate that the given index is OK to
3140 * be assigned to a new UE for the Pusch TPC
3149 **********************************************************/
3150 static S16 rgSCHPwrChkPuschTpcRntiIdx(RgSchCmnTpcRntiCb *cb,uint8_t idx)
3153 if (rgSCHPwrChkTpcRntiIdx(cb, idx) != ROK)
3157 if (rgSCHPwrChkUniqPuschTpcRntiIdx(cb, idx) != ROK)
3164 /***********************************************************
3166 * Func : rgSCHPwrChkUniqPucchTpcRntiIdx
3168 * Desc : Validate index against format type of TPC RNTI
3176 **********************************************************/
3177 static S16 rgSCHPwrChkUniqPucchTpcRntiIdx(RgSchCmnTpcRntiCb *cb,uint8_t idx)
3181 for (lnk = cb->cfgdUes.first; lnk; lnk = lnk->next)
3183 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
3184 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
3185 if (uePwr->pucchIdx == idx)
3193 /***********************************************************
3195 * Func : rgSCHPwrChkUniqPuschTpcRntiIdx
3197 * Desc : Validate index against format type of TPC RNTI
3205 **********************************************************/
3206 static S16 rgSCHPwrChkUniqPuschTpcRntiIdx(RgSchCmnTpcRntiCb *cb,uint8_t idx)
3210 for (lnk = cb->cfgdUes.first; lnk; lnk = lnk->next)
3212 RgSchUeCb *ue = (RgSchUeCb *)lnk->node;
3213 RgSchCmnUeUlPwrCb *uePwr = RG_SCH_PWR_GETUEPWR(ue, ue->cell);
3214 if (uePwr->puschIdx == idx)
3222 /***********************************************************
3224 * Func : rgSCHPwrChkTpcRntiIdx
3226 * Desc : Validate index against format type of TPC RNTI.
3234 **********************************************************/
3235 static S16 rgSCHPwrChkTpcRntiIdx(RgSchCmnTpcRntiCb *cb,uint8_t idx)
3239 if (idx >= TFU_MAX_1BIT_TPC)
3246 if (idx >= TFU_MAX_2BIT_TPC)
3253 /* Warning Fix: Commenting out as not used */
3255 /***********************************************************
3257 * Func : rgSCHPwrGetPCMaxValFromPCMax
3259 * Desc : Returns the power headroom in dB
3260 * corresponding to a power headroom
3269 **********************************************************/
3270 static S8 rgSCHPwrGetPCMaxValFromPCMax(uint8_t pCMax)
3272 return ((pCMax & 63) - 30);
3277 /***********************************************************
3279 * Func : rgSCHPwrGetPhValFromPhr
3281 * Desc : Returns the power headroom in dB
3282 * corresponding to a power headroom
3291 **********************************************************/
3292 static S8 rgSCHPwrGetPhValFromPhr(uint8_t phr)
3294 return ((phr & 63) - 23);
3299 /**********************************************************************
3302 **********************************************************************/