diff options
Diffstat (limited to 'src/usr/htmgt/htmgt_memthrottles.C')
-rw-r--r-- | src/usr/htmgt/htmgt_memthrottles.C | 509 |
1 files changed, 509 insertions, 0 deletions
diff --git a/src/usr/htmgt/htmgt_memthrottles.C b/src/usr/htmgt/htmgt_memthrottles.C new file mode 100644 index 000000000..3684c71d7 --- /dev/null +++ b/src/usr/htmgt/htmgt_memthrottles.C @@ -0,0 +1,509 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/htmgt/htmgt_memthrottles.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#include "htmgt_memthrottles.H" +#include "htmgt_utility.H" +#include <htmgt/htmgt_reasoncodes.H> +#include <errl/errlmanager.H> +#include <targeting/common/commontargeting.H> +#include <targeting/common/utilFilter.H> +#include <targeting/common/attributes.H> +#include <targeting/common/targetservice.H> +#include <fapi.H> +#include <fapiPlatHwpInvoker.H> +#include <mss_bulk_pwr_throttles.H> +#include <mss_util_to_throttle.H> + + +using namespace TARGETING; + + + +//for unit testing +//#define TRACUCOMP(args...) TMGT_INF(args) +#define TRACUCOMP(args...) + +namespace HTMGT +{ + +/** + * Helper function to run the hardware procedure to calculate the + * throttle attributes for the Over Temp condition. + * flow = htmgtCalcMemThrottle_OT + * + * @param[in] i_mbas - list of functional MBAs + * @param[in] i_utilization - Minimum utilization value required + * @param[in] i_nSafeModeMBA - the safe mode MBA throttle numerator + */ +void memPowerThrottleOT(TargetHandleList & i_mbas, + const uint32_t i_nSafeModeMBA, + const uint8_t i_utilization) +{ + TargetHandleList::iterator mba; + bool useSafeMode = false; + bool throttleError = false; + uint32_t nUtilBased = 0; + uint32_t mbaHuid = 0; + Target* sys = NULL; + + TMGT_INF(ENTER_MRK" memPowerThrottleOT"); + + targetService().getTopLevelTarget(sys); + assert(sys != NULL); + + for (mba=i_mbas.begin(); mba!=i_mbas.end(); ++mba) + { + mbaHuid = (*mba)->getAttr<ATTR_HUID>(); + useSafeMode = true; + nUtilBased = 0; + + if (i_utilization != 0) + { + //Run a hardware procedure to calculate the lowest + //possible throttle setting based on the minimum + //utilization percentage. + errlHndl_t err = NULL; + const fapi::Target fapiTarget(fapi::TARGET_TYPE_MBA_CHIPLET, + const_cast<Target*>(*mba)); + + //Set this so the procedure can use it + (*mba)->setAttr<ATTR_MSS_DATABUS_UTIL_PER_MBA>(i_utilization); + + FAPI_INVOKE_HWP(err, mss_util_to_throttle, fapiTarget); + + if (err) + { + //Ignore the error and just use safe + //mode as the lowest throttle + TMGT_ERR("memPowerThrottleOT: Failed call to " + "mss_util_to_throttle on MBA 0x%X", + mbaHuid); + + delete err; + err = NULL; + } + else + { + //get the procedure output + nUtilBased = (*mba)->getAttr<ATTR_MSS_UTIL_N_PER_MBA>(); + + if (0 != nUtilBased) + { + useSafeMode = false; + } + else + { + TMGT_ERR("memPowerThrottleOT: mss_util_to_throttle" + " calculated a numerator of 0, MBA 0x%X", + mbaHuid); + + if (!throttleError) + { + throttleError = true; + + /** + * @errortype + * @reasoncode HTMGT_RC_OT_THROTTLE_INVALID_N + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid HTMGT_MOD_MEMTHROTTLE + * @userdata1 MBA HUID + * @devdesc Overtemp Throttle HW procedure + * calculated an invalid numerator + * value. + */ + err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HTMGT_MOD_MEMTHROTTLE, + HTMGT_RC_OT_THROTTLE_INVALID_N, + mbaHuid, 0, true); + err->collectTrace(HTMGT_COMP_NAME); + errlCommit(err, HTMGT_COMP_ID); + } + } + } + } + + + if (useSafeMode) + { + nUtilBased = i_nSafeModeMBA; + + TMGT_INF("memPowerThrottleOT: MBA 0x%X must use safemode" + " numerator", mbaHuid); + } + + TMGT_INF("memPowerThrottleOT: MBA 0x%X: N Util OT = 0x%X", + mbaHuid, nUtilBased); + + (*mba)->setAttr<ATTR_OT_MIN_N_PER_MBA>(nUtilBased); + } + + +} + + + + + +/** + * Helper function to run the mss_bulk_pwr_throttles and + * mss_util_to_throttle to calculate memory throttling + * numerator values. + * + * @param[in] i_mba - the MBA + * @param[in] i_wattTarget - the power target for the MBA + * @param[in] i_utilization - the utilization desired + * @param[out] o_useSafeMode - will be set to true if safe mode + * values should be used + * @param[out] o_nMBA - set to the N_PER_MBA numerator value + * (don't use if safemode=true) + * @param[out] o_nChip - set to the N_PER_CHIP numerator value + * (don't use if safemode=true) + */ +void doMBAThrottleCalc(TargetHandle_t i_mba, + const uint32_t i_wattTarget, + const uint8_t i_utilization, + bool & o_useSafeMode, + uint32_t & o_nMBA, + uint32_t & o_nChip) +{ + errlHndl_t err = NULL; + + o_useSafeMode = false; + o_nMBA = 0; + o_nChip = 0; + + //Set the values the procedures need + i_mba->setAttr<ATTR_MSS_MEM_WATT_TARGET>(i_wattTarget); + i_mba->setAttr<ATTR_MSS_DATABUS_UTIL_PER_MBA>(i_utilization); + + const fapi::Target fapiTarget(fapi::TARGET_TYPE_MBA_CHIPLET, + i_mba); + + FAPI_INVOKE_HWP(err, mss_bulk_pwr_throttles, fapiTarget); + + if (err) + { + TMGT_ERR("doMBAThrottleCalc: Failed call to mss_bulk_pwr_throttles" + " on MBA 0x%X", + i_mba->getAttr<ATTR_HUID>()); + } + else + { + //Get the procedure outputs + o_nMBA = i_mba->getAttr<ATTR_MSS_MEM_THROTTLE_NUMERATOR_PER_MBA>(); + o_nChip = i_mba->getAttr<ATTR_MSS_MEM_THROTTLE_NUMERATOR_PER_CHIP>(); + + //Make sure neither are 0 + if ((0 == o_nMBA) || (0 == o_nChip)) + { + TMGT_ERR("doMBAThrottleCalc: mss_bulk_pwr_throttles calculated a" + " numerator value of 0: nMBA = %d, nChip = %d, MBA 0x%X", + o_nMBA, o_nChip, i_mba->getAttr<ATTR_HUID>()); + + /*@ + * @errortype + * @reasoncode HTMGT_RC_THROTTLE_INVALID_N + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid HTMGT_MOD_MEMTHROTTLE + * @userdata1 MBA HUID + * @userdata2[0:31] MBA numerator + * @userdata2[32:63] Chip numerator + * @devdesc Throttle HW procedure calculated + * an invalid numerator value. + */ + uint64_t data = ((uint64_t)o_nMBA << 32) | o_nChip; + err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HTMGT_MOD_MEMTHROTTLE, + HTMGT_RC_THROTTLE_INVALID_N, + i_mba->getAttr<ATTR_HUID>(), + data, true); + } + else if (i_utilization != 0) + { + //Make sure the calculated throttles meet the min + //utilization, if provided. + + FAPI_INVOKE_HWP(err, mss_util_to_throttle, fapiTarget); + + if (err) + { + TMGT_ERR("doMBAThrottleCalc: Failed call to " + "mss_util_to_throttle on MBA 0x%X", + i_mba->getAttr<ATTR_HUID>()); + } + else + { + //Get the value the procedure wrote + uint32_t nUtilMBA = i_mba->getAttr<ATTR_MSS_UTIL_N_PER_MBA>(); + + TRACUCOMP("doMBAThrottleCalc: mss_util_to_throttle" + " calculated N = %d", + nUtilMBA); + + //If mss_bulk_pwr_throttles calculated a value + //that doesn't meet the minimum requested utilization, + //then we have a problem. + if (nUtilMBA > o_nMBA) + { + TMGT_ERR("doMBAThrottleCalc: MSS_UTIL_N_PER_MBA 0x%X " + "> MSS_MEM_THROTTLE_N_PER_MBA 0x%X on MBA 0x%X", + nUtilMBA, o_nMBA, + i_mba->getAttr<ATTR_HUID>()); + + /*@ + * @errortype + * @reasoncode HTMGT_RC_THROTTLE_UTIL_ERROR + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid HTMGT_MOD_MEMTHROTTLE + * @userdata1 MBA HUID + * @userdata2[0:31] util based N + * @userdata2[32:63] calculated N + * @devdesc Throttle numerator calculated + * doesn't meet min utilization + */ + uint64_t data = ((uint64_t)nUtilMBA << 32) | o_nMBA; + err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HTMGT_MOD_MEMTHROTTLE, + HTMGT_RC_THROTTLE_UTIL_ERROR, + i_mba->getAttr<ATTR_HUID>(), + data, true); + } + } + } + } + + if (err) + { + err->collectTrace(HTMGT_COMP_NAME); + errlCommit(err, HTMGT_COMP_ID); + o_useSafeMode = true; + } + +} + + +/** + * Helper function to run the hardware procedures to calculate the + * throttle attributes used for redundant power. + * flow = htmgtCalcMemThrottle_redundantPwr + * + * @param[in] i_mbas - the list of functional MBAs + * @param[in] i_nSafeModeMBA - the safe mode MBA throttle numerator + * @param[in] i_nSafeModeChip - the safe mode MBA throttle numerator + * @param[in] i_utilization - Minimum utilization value required + * @param[in] i_efficiency - the regulator efficiency + */ +void memPowerThrottleRedPower(TargetHandleList & i_mbas, + const uint32_t i_nSafeModeMBA, + const uint32_t i_nSafeModeChip, + const uint8_t i_utilization, + const uint8_t i_efficiency) +{ + Target* sys = NULL; + TargetHandleList::iterator mba; + uint16_t power = 0; + uint32_t wattTarget = 0; + uint32_t nChip = 0; + uint32_t nMBA = 0; + bool useSafeMode = false; + + targetService().getTopLevelTarget(sys); + assert(sys != NULL); + + //Get the max N+1 power allocated to memory + power = sys->getAttr<ATTR_OPEN_POWER_N_PLUS_ONE_MAX_MEM_POWER_WATTS>(); + power *= 100; //centiWatts + + //Account for the regulator efficiency, if supplied + if (i_efficiency != 0) + { + power *= i_efficiency; + } + + //Find the Watt target for each MBA + if (i_mbas.size()) + { + wattTarget = power / i_mbas.size(); + } + + TMGT_INF("memPowerThrottleRedPower: power = %d, wattTarget = %d", + power, wattTarget); + + for (mba=i_mbas.begin(); mba!=i_mbas.end(); ++mba) + { + useSafeMode = false; + nMBA = nChip = 0; + + //Run the calculations + doMBAThrottleCalc(*mba, wattTarget, i_utilization, + useSafeMode, nMBA, nChip); + + if (useSafeMode) + { + nMBA = i_nSafeModeMBA; + nChip = i_nSafeModeChip; + TMGT_INF("memPowerThrottleRedPower: MBA 0x%X using safemode " + "numerator", + (*mba)->getAttr<ATTR_HUID>()); + } + + //Set the attributes we'll send to OCC later + TMGT_INF("memPowerThrottleRedPower: MBA 0x%X: N_PER_MBA = 0x%X, " + "N_PER_CHIP = 0x%X", + (*mba)->getAttr<ATTR_HUID>(), nMBA, nChip); + + (*mba)->setAttr<ATTR_N_PLUS_ONE_N_PER_MBA>(nMBA); + (*mba)->setAttr<ATTR_N_PLUS_ONE_N_PER_CHIP>(nChip); + + } + + +} + + + +/** + * Helper function to run the hardware procedures to calculate the + * throttle attributes used for oversubscription. + * flow = htmgtCalcMemThrottle_oversub + * + * @param[in] i_mbas - the list of functional MBAs + * @param[in] i_nSafeModeMBA - the safe mode MBA throttle numerator + * @param[in] i_nSafeModeChip - the safe mode MBA throttle numerator + * @param[in] i_utilization - Minimum utilization value required + * @param[in] i_efficiency - the regulator efficiency + */ +void memPowerThrottleOverSub(TargetHandleList & i_mbas, + const uint32_t i_nSafeModeMBA, + const uint32_t i_nSafeModeChip, + const uint8_t i_utilization, + const uint8_t i_efficiency) +{ + Target* sys = NULL; + TargetHandleList::iterator mba; + uint16_t power = 0; + uint32_t wattTarget = 0; + uint32_t nChip = 0; + uint32_t nMBA = 0; + bool useSafeMode = false; + + targetService().getTopLevelTarget(sys); + assert(sys != NULL); + + //Get the max power allocated to memory + power = sys->getAttr<ATTR_OPEN_POWER_N_MAX_MEM_POWER_WATTS>(); + power *= 100; //centiWatts + + //Account for the regulator efficiency, if supplied + if (i_efficiency != 0) + { + power *= i_efficiency; + } + + //Find the Watt target for each MBA + if (i_mbas.size()) + { + wattTarget = power / i_mbas.size(); + } + + TMGT_INF("memPowerThrottleOverSub: power = %d, wattTarget = %d", + power, wattTarget); + + for (mba=i_mbas.begin(); mba!=i_mbas.end(); ++mba) + { + useSafeMode = false; + nMBA = nChip = 0; + + //Run the calculations + doMBAThrottleCalc(*mba, wattTarget, i_utilization, + useSafeMode, nMBA, nChip); + + if (useSafeMode) + { + nMBA = i_nSafeModeMBA; + nChip = i_nSafeModeChip; + TMGT_INF("memPowerThrottleOverSub: MBA 0x%X using safemode " + "numerator", + (*mba)->getAttr<ATTR_HUID>()); + } + + //Set the attributes we'll send to OCC later + TMGT_INF("memPowerThrottleOverSub: MBA 0x%X: N_PER_MBA = 0x%X, " + "N_PER_CHIP = 0x%X", + (*mba)->getAttr<ATTR_HUID>(), nMBA, nChip); + + (*mba)->setAttr<ATTR_OVERSUB_N_PER_MBA>(nMBA); + (*mba)->setAttr<ATTR_OVERSUB_N_PER_CHIP>(nChip); + + } + +} + + + +void calcMemThrottles() +{ + Target* sys = NULL; + TargetHandleList mbas; + + targetService().getTopLevelTarget(sys); + assert(sys != NULL); + + uint32_t nSafeModeMBA = + sys->getAttr<ATTR_MRW_SAFEMODE_MEM_THROTTLE_NUMERATOR_PER_MBA>(); + + uint32_t nSafeModeChip = + sys->getAttr<ATTR_MRW_SAFEMODE_MEM_THROTTLE_NUMERATOR_PER_CHIP>(); + + uint8_t utilization = + sys->getAttr<ATTR_OPEN_POWER_MIN_MEM_UTILIZATION_THROTTLING>(); + + uint8_t efficiency = + sys->getAttr<ATTR_OPEN_POWER_REGULATOR_EFFICIENCY_FACTOR>(); + + TMGT_INF("calcMemThrottles: Using nSafeModeMBA=0x%X, nSafeModeChip=0x%X", + nSafeModeMBA, nSafeModeChip); + + TMGT_INF("calcMemThrottles: Using utilization=0x%X, efficiency=0x%X", + utilization, efficiency); + + + //Get all functional MBAs + getAllChiplets(mbas, TYPE_MBA, true); + + //Calculate Throttle settings for Over Temperature + memPowerThrottleOT(mbas, nSafeModeMBA, utilization); + + //Calculate Throttle settings for Redundant Power + memPowerThrottleRedPower(mbas, nSafeModeMBA, nSafeModeChip, + utilization, efficiency); + + //Calculate Throttle settings for Oversubscription + memPowerThrottleOverSub(mbas, nSafeModeMBA, nSafeModeChip, + utilization, efficiency); + +} +} // End namespace |