diff options
author | Luke Mulkey <lwmulkey@us.ibm.com> | 2017-10-11 14:02:56 -0500 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2018-05-17 11:35:06 -0400 |
commit | 1fd1cc97eb824b7853e652379ba8698c519512e2 (patch) | |
tree | 45650b979e378eeac216cd006ada1633771d6aa4 | |
parent | 01be61c03770d4f837febb9debdfb7318d0b6f3c (diff) | |
download | talos-hostboot-1fd1cc97eb824b7853e652379ba8698c519512e2.tar.gz talos-hostboot-1fd1cc97eb824b7853e652379ba8698c519512e2.zip |
P9C Memory Throttle Updates (new HWPs and new ISDIMM Power Curve support)
Change-Id: Icfbe39161641324bddc5f880948d03f5ee2cce5a
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/57005
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: HWSV CI <hwsv-ci+hostboot@us.ibm.com>
Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com>
Reviewed-by: STEPHEN GLANCY <sglancy@us.ibm.com>
Reviewed-by: Louis Stermole <stermole@us.ibm.com>
Reviewed-by: ANDRE A. MARIN <aamarin@us.ibm.com>
Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com>
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/57277
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
16 files changed, 1066 insertions, 394 deletions
diff --git a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_bulk_pwr_throttles.C b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_bulk_pwr_throttles.C index ceb3779bf..6ba0a8e37 100644 --- a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_bulk_pwr_throttles.C +++ b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_bulk_pwr_throttles.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -27,7 +27,7 @@ /// @file p9c_mss_bulk_pwr_throttles.C /// @brief Sets the throttle attributes based on a power limit for the dimms on the channel pair /// -/// *HWP HWP Owner: Luke Mulkey <lwmulkey@us.ibm.com> +/// *HWP HWP Owner: Andre Marin <aamaring@us.ibm.com> /// *HWP HWP Backup: Mike Pardeik <pardeik@us.ibm.com> /// *HWP Team: Memory /// *HWP Level: 2 @@ -67,310 +67,380 @@ #include <p9c_mss_bulk_pwr_throttles.H> #include <generic/memory/lib/utils/c_str.H> #include <dimmConsts.H> +#include <generic/memory/lib/utils/find.H> +#include <generic/memory/lib/utils/count_dimm.H> //------------------------------------------------------------------------------ // Includes //------------------------------------------------------------------------------ #include <fapi2.H> +using fapi2::TARGET_TYPE_MEMBUF_CHIP; +using fapi2::TARGET_TYPE_MBA; +using fapi2::FAPI2_RC_SUCCESS; + +constexpr uint32_t DRAM_UTIL_LIMIT_BOTH_MBA_WITH_DIMMS = 5625; // units c% +constexpr uint8_t IDLE_UTIL = 0; // in percent +constexpr double UTIL_FLOOR = 1; // in percent, utilization floor + extern "C" { - /// @brief mss_bulk_pwr_throttles(): This function determines the throttle values power limit for the dimms on the channel pair - /// @param[in] const fapi2::Target<fapi2::TARGET_TYPE_MBA> & i_target_mba: MBA Target<fapi2::TARGET_TYPE_MBA> passed in + /// @brief This function determines the throttle values power limit for the dimms on the channel pair + /// @param[in] i_target_mba: MBA Target /// @return fapi2::ReturnCode fapi2::ReturnCode p9c_mss_bulk_pwr_throttles(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba) { - FAPI_INF("*** Running mss_bulk_pwr_throttles ***"); - float l_idle_util = 0; // in percent - float l_min_util = 1; // in percent - // These are the constants to use for ISDIMM power/throttle support - // Note that these are hardcoded and ISDIMMs will not use power curves - // No Throttling if available power is >= ISDIMM_MAX_DIMM_POWER - // Throttle when ISDIMM_MIN_DIMM_POWER <= available power <= ATTR_MSS_MEM_WATT_TARGET - // Throttle value will be maximum throttle * ISDIMM_MEMORY_THROTTLE_PERCENT - constexpr uint32_t ISDIMM_MAX_DIMM_POWER = 1200; // cW, max ISDIMM power for no throttling - constexpr uint32_t ISDIMM_MIN_DIMM_POWER = 800; // cW, min ISDIMM power for throttling - constexpr uint8_t ISDIMM_MEMORY_THROTTLE_PERCENT = - 65; // percent, throttle impact when limit is between min and max power. A value of 0 would be for no throttle impact. + FAPI_INF("*** Running mss_bulk_pwr_throttles on %s ***", mss::c_str(i_target_mba)); + uint32_t l_channel_pair_watt_target = 0; + double l_utilization = 0; + double l_channel_power_slope = 0; + double l_channel_power_intercept = 0; + uint32_t l_channel_pair_power = 0; + constexpr bool l_utilization_is_a_min_value = false; //.set to false - uint32_t l_total_power_slope_array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; - uint32_t l_total_power_int_array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; - uint8_t l_dimm_ranks_array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; + // If MBA has no DIMMs, return as there is nothing to do + if (mss::count_dimm(i_target_mba) == 0) + { + FAPI_INF("++++ NO DIMM on %s ++++", mss::c_str(i_target_mba)); + return fapi2::FAPI2_RC_SUCCESS; + } + + // get input attributes + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_MEM_WATT_TARGET, + i_target_mba, l_channel_pair_watt_target)); + + FAPI_INF("[%s Available Channel Pair Power (Watt Target) %d cW]", mss::c_str(i_target_mba), l_channel_pair_watt_target); + + // call p9c_mss_bulk_pwr_channel_power to get the channel pair power slope and intercept values to use + FAPI_TRY(p9c_mss_bulk_pwr_channel_pair_power_curve(i_target_mba, l_channel_power_slope, l_channel_power_intercept)); + + // calculate the utilization needed to be under power limit + if ((l_channel_pair_watt_target > l_channel_power_intercept) && (l_channel_power_slope > 0)) + { + l_utilization = (l_channel_pair_watt_target - l_channel_power_intercept) / l_channel_power_slope * PERCENT_CONVERSION; + } + + // call p9c_mss_bulk_pwr_util_to_throttle_power to get the memory throttle and channel pair power attributes defined + FAPI_TRY(p9c_mss_bulk_pwr_util_to_throttle_power(i_target_mba, l_utilization, l_channel_power_slope, + l_channel_power_intercept, l_utilization_is_a_min_value)); + + // Get channel pair power attribute value just defined from above call to p9c_mss_bulk_pwr_util_to_throttle_power + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_CHANNEL_PAIR_MAXPOWER, + i_target_mba, l_channel_pair_power)); + + // Check to see if there is not enough available power (units are in cW) + // Return a bad RC if power is over the limit + FAPI_ASSERT((l_channel_pair_power <= l_channel_pair_watt_target), + fapi2::CEN_MSS_NOT_ENOUGH_AVAILABLE_DIMM_POWER(). + set_PAIR_POWER(l_channel_pair_power). + set_PAIR_WATT_TARGET(l_channel_pair_watt_target). + set_MEM_MBA(i_target_mba), + "%s Not enough available memory power [Channel Pair Power %d/%d cW]", mss::c_str(i_target_mba), l_channel_pair_power, + l_channel_pair_watt_target); + + FAPI_INF("*** mss_bulk_pwr_throttles COMPLETE on %s ***", mss::c_str(i_target_mba)); + + fapi_try_exit: + return fapi2::current_err; + } + + /// + /// @brief This function determines the channel pair power slope and intercept values to use + /// to calculate the channel pair power (ie. power of dimms attached to channel pair) + /// @param[in] i_target_mba: MBA Target + /// @param[out] o_channel_power_slope channel pair power slope + /// @param[out] o_channel_power_intercept channel pair power intercept + /// @return fapi2::ReturnCode + /// + fapi2::ReturnCode p9c_mss_bulk_pwr_channel_pair_power_curve(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba, + double& o_channel_power_slope, + double& o_channel_power_intercept + ) + { + FAPI_INF("*** Running p9c_mss_bulk_pwr_channel_pair_power_curve on %s ***", mss::c_str(i_target_mba)); + + // add up the power from all dimms for this MBA (across both channels) + // for IDLE (utilization=0) and maximum utilization + double l_max_util = 0; + double l_channel_pair_power_idle = 0; + double l_channel_pair_power_max = 0; uint8_t l_port = 0; uint8_t l_dimm = 0; - float l_dimm_power_array_idle[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; - float l_dimm_power_array_max[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; - float l_channel_power_array_idle[MAX_PORTS_PER_MBA] = {0}; - float l_max_util = 0; - float l_channel_power_array_max[MAX_PORTS_PER_MBA] = {0}; + double l_channel_power_array_idle[MAX_PORTS_PER_MBA] = {0}; + double l_channel_power_array_max[MAX_PORTS_PER_MBA] = {0}; + double l_dimm_power_array_idle[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; + double l_dimm_power_array_max[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; + uint8_t l_dimm_ranks_array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; + uint32_t l_total_power_slope_array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; + uint32_t l_total_power_int_array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; uint8_t l_power_curve_percent_uplift = 0; uint8_t l_power_curve_percent_uplift_idle = 0; uint32_t l_max_dram_databus_util = 0; - uint8_t l_num_mba_with_dimms = 0; - uint8_t l_custom_dimm = 0; uint32_t l_throttle_d = 0; - float l_channel_pair_power_idle = 0; - float l_channel_pair_power_max = 0; - uint32_t l_channel_pair_watt_target = 0; - float l_utilization = 0; - uint32_t l_number_of_dimms = 0; - float l_channel_power_slope = 0; - float l_channel_power_intercept = 0; - uint32_t l_throttle_n_per_mba = 0; - uint32_t l_throttle_n_per_chip = 0; - uint32_t l_channel_pair_power = 0; - uint32_t l_runtime_throttle_n_per_mba = 0; - uint32_t l_runtime_throttle_n_per_chip = 0; - uint8_t l_dram_gen = 0; + + // If MBA has no DIMMs, return as there is nothing to do + if (mss::count_dimm(i_target_mba) == 0) + { + FAPI_INF("++++ NO DIMM on %s ++++", mss::c_str(i_target_mba)); + return fapi2::FAPI2_RC_SUCCESS; + } // get input attributes - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_CUSTOM_DIMM, i_target_mba, l_custom_dimm)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_MAX_DRAM_DATABUS_UTIL, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_max_dram_databus_util)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_NUM_RANKS_PER_DIMM, + i_target_mba, l_dimm_ranks_array)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_TOTAL_POWER_SLOPE, + i_target_mba, l_total_power_slope_array)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_TOTAL_POWER_INT, + i_target_mba, l_total_power_int_array)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_DIMM_POWER_CURVE_PERCENT_UPLIFT, + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_power_curve_percent_uplift)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_DIMM_POWER_CURVE_PERCENT_UPLIFT_IDLE, + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_power_curve_percent_uplift_idle)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_MEM_M_DRAM_CLOCKS, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_throttle_d)); - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_MEM_WATT_TARGET, - i_target_mba, l_channel_pair_watt_target)); - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_RUNTIME_MEM_THROTTLE_NUMERATOR_PER_MBA, - i_target_mba, l_runtime_throttle_n_per_mba)); - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_RUNTIME_MEM_THROTTLE_NUMERATOR_PER_CHIP, - i_target_mba, l_runtime_throttle_n_per_chip)); - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DRAM_GEN, - i_target_mba, l_dram_gen)); - // other attributes for custom dimms to get - if (l_custom_dimm == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES) + // If throttling is disabled, set max util to MAX_UTIL + if (l_throttle_d == 0) { - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_DIMM_POWER_CURVE_PERCENT_UPLIFT, - fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_power_curve_percent_uplift)); - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_DIMM_POWER_CURVE_PERCENT_UPLIFT_IDLE, - fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_power_curve_percent_uplift_idle)); - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_TOTAL_POWER_SLOPE, - i_target_mba, l_total_power_slope_array)); - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_TOTAL_POWER_INT, - i_target_mba, l_total_power_int_array)); - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_NUM_RANKS_PER_DIMM, - i_target_mba, l_dimm_ranks_array)); + FAPI_INF("%s Memory Throttling is Disabled with M=0", mss::c_str(i_target_mba)); + l_max_dram_databus_util = MAX_UTIL; } // Maximum theoretical data bus utilization (percent of max) (for ceiling) // Comes from MRW value in c% - convert to % - l_max_util = (float) l_max_dram_databus_util / 100; + // We don't need to limit this because this function is only determining the channel pair power slope and interecpt + l_max_util = (static_cast<double>(convert_to_percent(l_max_dram_databus_util))); - // determine the dimm power - // For custom dimms, use the VPD power curve data - if (l_custom_dimm == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES) + for (l_port = 0; l_port < MAX_PORTS_PER_MBA; l_port++) { - // get number of mba's with dimms - // Get Centaur target for the given MBA - const auto l_target_chip = i_target_mba.getParent<fapi2::TARGET_TYPE_MEMBUF_CHIP>(); - // Get MBA targets from the parent chip centaur - const auto l_target_mba_array = l_target_chip.getChildren<fapi2::TARGET_TYPE_MBA>(); - l_num_mba_with_dimms = 0; - - for (const auto& l_mba : l_target_mba_array) - { - const auto l_target_dimm_array = l_mba.getChildren<fapi2::TARGET_TYPE_DIMM>(); + l_channel_power_array_idle[l_port] = 0; + l_channel_power_array_max[l_port] = 0; - if (l_target_dimm_array.size() > 0) - { - l_num_mba_with_dimms++; - } - } - - // add up the power from all dimms for this MBA (across both channels) - // for IDLE (utilization=0) and maximum utilization - l_channel_pair_power_idle = 0; - l_channel_pair_power_max = 0; - - for (l_port = 0; l_port < MAX_PORTS_PER_MBA; l_port++) + for (l_dimm = 0; l_dimm < MAX_DIMM_PER_PORT; l_dimm++) { - l_channel_power_array_idle[l_port] = 0; - l_channel_power_array_max[l_port] = 0; + // default dimm power is zero (used for dimms that are not physically present) + l_dimm_power_array_idle[l_port][l_dimm] = 0; + l_dimm_power_array_max[l_port][l_dimm] = 0; - for (l_dimm = 0; l_dimm < MAX_DIMM_PER_PORT; l_dimm++) + // See if there are any ranks present on the dimm (configured or deconfigured) + if ((l_dimm_ranks_array[l_port][l_dimm] > 0) && (l_total_power_slope_array[l_port][l_dimm] > 0) + && (l_total_power_int_array[l_port][l_dimm] > 0)) { - // default dimm power is zero (used for dimms that are not physically present) - l_dimm_power_array_idle[l_port][l_dimm] = 0; - l_dimm_power_array_max[l_port][l_dimm] = 0; - - // See if there are any ranks present on the dimm (configured or deconfigured) - if (l_dimm_ranks_array[l_port][l_dimm] > 0) - { - l_dimm_power_array_idle[l_port][l_dimm] = l_dimm_power_array_idle[l_port][l_dimm] + - (l_idle_util / 100 * l_total_power_slope_array[l_port][l_dimm]) + l_total_power_int_array[l_port][l_dimm]; - l_dimm_power_array_max[l_port][l_dimm] = l_dimm_power_array_max[l_port][l_dimm] + (l_max_util / 100 * - l_total_power_slope_array[l_port][l_dimm]) + l_total_power_int_array[l_port][l_dimm]; - } - + l_dimm_power_array_idle[l_port][l_dimm] = l_dimm_power_array_idle[l_port][l_dimm] + + (convert_to_percent(IDLE_UTIL) * l_total_power_slope_array[l_port][l_dimm]) + l_total_power_int_array[l_port][l_dimm]; + l_dimm_power_array_max[l_port][l_dimm] = l_dimm_power_array_max[l_port][l_dimm] + (convert_to_percent(l_max_util) * + l_total_power_slope_array[l_port][l_dimm]) + l_total_power_int_array[l_port][l_dimm]; // Include any system uplift here too - if (l_dimm_power_array_idle[l_port][l_dimm] > 0) - { - l_dimm_power_array_idle[l_port][l_dimm] = - l_dimm_power_array_idle[l_port][l_dimm] * - (1 + (float)l_power_curve_percent_uplift_idle / 100); - } - - if (l_dimm_power_array_max[l_port][l_dimm] > 0) - { - l_dimm_power_array_max[l_port][l_dimm] = - l_dimm_power_array_max[l_port][l_dimm] * - (1 + (float)l_power_curve_percent_uplift / 100); - } - - // calculate channel power by adding up the power of each dimm - l_channel_power_array_idle[l_port] = l_channel_power_array_idle[l_port] + l_dimm_power_array_idle[l_port][l_dimm]; - l_channel_power_array_max[l_port] = l_channel_power_array_max[l_port] + l_dimm_power_array_max[l_port][l_dimm]; - FAPI_DBG("[P%d:D%d][CH Util %4.2f/%4.2f][Slope:Int %d:%d][UpliftPercent idle/max %d/%d)][Power min/max %4.2f/%4.2f cW]", - l_port, l_dimm, l_idle_util, l_max_util, l_total_power_slope_array[l_port][l_dimm], + l_dimm_power_array_idle[l_port][l_dimm] = + l_dimm_power_array_idle[l_port][l_dimm] * + (1 + (static_cast<double>(l_power_curve_percent_uplift_idle)) / 100); + l_dimm_power_array_max[l_port][l_dimm] = + l_dimm_power_array_max[l_port][l_dimm] * + (1 + (static_cast<double>(l_power_curve_percent_uplift)) / 100); + FAPI_DBG("%s [P%d:D%d][IDLE/MAX CH Util %d/%4.2lf][Slope:Int %d:%d][UpliftPercent IDLE/MAX %d/%d)][IDLE/MAX Power %4.2lf/%4.2lf cW]", + mss::c_str(i_target_mba), l_port, l_dimm, IDLE_UTIL, l_max_util, l_total_power_slope_array[l_port][l_dimm], l_total_power_int_array[l_port][l_dimm], l_power_curve_percent_uplift_idle, l_power_curve_percent_uplift, l_dimm_power_array_idle[l_port][l_dimm], l_dimm_power_array_max[l_port][l_dimm]); } - FAPI_DBG("[P%d][CH Util %4.2f/%4.2f][Power %4.2f/%4.2f cW]", l_port, l_min_util, l_max_util, - l_channel_power_array_idle[l_port], l_channel_power_array_max[l_port]); - l_channel_pair_power_idle = l_channel_pair_power_idle + l_channel_power_array_idle[l_port]; - l_channel_pair_power_max = l_channel_pair_power_max + l_channel_power_array_max[l_port]; + // calculate channel power by adding up the power of each dimm + l_channel_power_array_idle[l_port] += l_dimm_power_array_idle[l_port][l_dimm]; + l_channel_power_array_max[l_port] += l_dimm_power_array_max[l_port][l_dimm]; } - // calculate the slope/intercept values from power values just calculated above - l_channel_power_slope = (l_channel_pair_power_max - l_channel_pair_power_idle) / ( (l_max_util / 100) - - (l_idle_util / 100) ); - l_channel_power_intercept = l_channel_pair_power_idle; + FAPI_DBG("%s [P%d][IDLE/MAX CH Util %d/%4.2lf][IDLE/MAX Power %4.2lf/%4.2lf cW]", + mss::c_str(i_target_mba), l_port, IDLE_UTIL, l_max_util, + l_channel_power_array_idle[l_port], l_channel_power_array_max[l_port]); + l_channel_pair_power_idle += l_channel_power_array_idle[l_port]; + l_channel_pair_power_max += l_channel_power_array_max[l_port]; + } - // calculate the utilization needed to be under power limit - l_utilization = 0; + // calculate the slope/intercept values from power values just calculated above + o_channel_power_slope = (l_channel_pair_power_max - l_channel_pair_power_idle) / ( convert_to_percent(l_max_util) - + convert_to_percent(IDLE_UTIL) ); + o_channel_power_intercept = l_channel_pair_power_idle; - if (l_channel_pair_watt_target > l_channel_power_intercept) - { - l_utilization = (l_channel_pair_watt_target - l_channel_power_intercept) / l_channel_power_slope * 100; + FAPI_INF("%s [Channel Pair Power IDLE/MAX %4.2lf/%4.2lf cW][Slope/Intercept %4.2lf/%4.2lf cW]", + mss::c_str(i_target_mba), l_channel_pair_power_idle, l_channel_pair_power_max, o_channel_power_slope, + o_channel_power_intercept); - if (l_utilization > l_max_util) - { - l_utilization = l_max_util; - } - } - // Calculate the NperChip and NperMBA Throttles - l_throttle_n_per_chip = int((l_utilization / 100 * l_throttle_d / 4) * l_num_mba_with_dimms); + FAPI_INF("*** p9c_mss_bulk_pwr_channel_pair_power_curve COMPLETE on %s ***", mss::c_str(i_target_mba)); - if (l_throttle_n_per_chip > (l_max_util / 100 * l_throttle_d / 4) ) - { - l_throttle_n_per_mba = int((l_max_util / 100 * l_throttle_d / 4)); - } - else - { - l_throttle_n_per_mba = l_throttle_n_per_chip; - } + fapi_try_exit: + return fapi2::current_err; + } - // Calculate the channel power at the utilization determined - l_channel_pair_power = int(l_utilization / 100 * l_channel_power_slope + l_channel_power_intercept); - FAPI_DBG("[Channel Pair Power min/max %4.2f/%4.2f cW][Slope/Intercept %4.2f/%4.2f cW][Utilization Percent %4.2f, Power %d cW]", - l_channel_pair_power_idle, l_channel_pair_power_max, l_channel_power_slope, l_channel_power_intercept, l_utilization, - l_channel_pair_power); + /// + /// @brief This function determines the memory throttle and channel pair power + /// attribute values for a given dram data bus utilization value + /// @param[in] i_target_mba: MBA Target + /// @param[in] i_utilization Dram data bus utilization value (units %) + /// @param[in] i_channel_power_slope channel pair power slope + /// @param[in] i_channel_power_intercept channel pair power + /// @param[in] i_utilization_is_a_min_value tells us if i_utilization is a min or max target to meet (0=max, 1=min) + /// @return fapi2::ReturnCode + /// + fapi2::ReturnCode p9c_mss_bulk_pwr_util_to_throttle_power(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba, + double i_utilization, + const double i_channel_power_slope, + const double i_channel_power_intercept, + const bool i_utilization_is_a_min_value + ) + { + FAPI_INF("*** Running p9c_mss_bulk_pwr_util_to_throttle_power on %s ***", mss::c_str(i_target_mba)); + FAPI_INF("%s [Input Util %4.2lf percent]", mss::c_str(i_target_mba), i_utilization); + + // Limit max utilization to 100% DMI utilization so we don't end up with memory powers that can never be achieved + // For CDIMMs, limit to 56.25% dram data bus utilization (Note that CDIMMs have both MBAs with DIMMs) + // For ISDIMMs, limit to 56.25% dram data bus utilization if both MBAs have DIMMs + // For ISDIMMs, no limitation if only one MBA has DIMMs (power will be higher than it should be, but this is not a full + // configuration so we should not be stressing any power limitations so ok to over estimate the power) + double l_max_util = 0; + uint8_t l_custom_dimm = 0; + uint32_t l_throttle_d = 0; + uint32_t l_throttle_n_per_mba = 0; + uint32_t l_throttle_n_per_chip = 0; + uint8_t l_num_mba_with_dimms = 0; + uint32_t l_max_dram_databus_util = 0; + uint32_t l_channel_pair_power = 0; + uint8_t l_throttle_multiplier = 0; + double l_max_util_power_calc = 0; + double l_util_power_calc = 0; + double l_utilization_calc_without_throttle_adder = 0; + double l_utilization_calc = 0; + uint8_t l_throttle_adder = 0; + + // If MBA has no DIMMs, return as there is nothing to do + if (mss::count_dimm(i_target_mba) == 0) + { + FAPI_INF("++++ NO DIMM on %s ++++", mss::c_str(i_target_mba)); + return fapi2::FAPI2_RC_SUCCESS; } - // for non custom dimms, use hardcoded values - // If power limit is at or above max power, use unthrottled settings - // If between min and max power, use a static throttle point - // If below min power, return an error - else + // get input attributes + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_MAX_DRAM_DATABUS_UTIL, + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_max_dram_databus_util)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_CUSTOM_DIMM, i_target_mba, l_custom_dimm)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_MEM_M_DRAM_CLOCKS, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), + l_throttle_d)); + + // If throttling is disabled, set max util to MAX_UTIL + if (l_throttle_d == 0) { - // get number of dimms attached to this mba - const auto l_target_dimm_array = i_target_mba.getChildren<fapi2::TARGET_TYPE_DIMM>(); - l_number_of_dimms = l_target_dimm_array.size(); + FAPI_INF("%s Memory Throttling is Disabled with M=0", mss::c_str(i_target_mba)); + l_max_dram_databus_util = MAX_UTIL; + } - // ISDIMMs, set to a value of one since throttles are handled on a per MBA basis - l_num_mba_with_dimms = 1; + // Maximum theoretical data bus utilization (percent of max) (for ceiling) + // Comes from MRW value in c% - convert to % + if (l_max_dram_databus_util > MAX_UTIL) + { + l_max_dram_databus_util = MAX_UTIL; + FAPI_INF("%s [Max Util Limited to %4.2lf centi percent]", mss::c_str(i_target_mba), l_max_dram_databus_util); + } - // MBA Power Limit is higher than dimm power, run unthrottled - if (l_channel_pair_watt_target >= (ISDIMM_MAX_DIMM_POWER * l_number_of_dimms)) - { - l_utilization = l_max_util; - l_channel_pair_power = ISDIMM_MAX_DIMM_POWER * l_number_of_dimms; - } - else if (l_channel_pair_watt_target >= (ISDIMM_MIN_DIMM_POWER * l_number_of_dimms)) + l_max_util = (static_cast<double>(convert_to_percent(l_max_dram_databus_util))); + + // Limit input utilization if needed + if (i_utilization > l_max_util) + { + i_utilization = l_max_util; + FAPI_INF("%s [Input Util Limited to %4.2lf percent]", mss::c_str(i_target_mba), i_utilization); + } + + // get number of mba's with dimms, used below to help determine utilization values for power calculations + // Have to have this section in braces otherwise compile fails + { + const auto& l_target_chip = mss::find_target<TARGET_TYPE_MEMBUF_CHIP>(i_target_mba); + + for (const auto& l_mba : mss::find_targets<TARGET_TYPE_MBA>(l_target_chip)) { - if (ISDIMM_MEMORY_THROTTLE_PERCENT > 99) - { - l_utilization = l_min_util; - } - else + if (mss::count_dimm(l_mba) > 0) { - l_utilization = l_max_util * (1 - (float)ISDIMM_MEMORY_THROTTLE_PERCENT / 100); + l_num_mba_with_dimms++; } - - l_channel_pair_power = ISDIMM_MIN_DIMM_POWER * l_number_of_dimms; - } - else - { - // error case, available power less than allocated minimum dimm power - l_utilization = 0; - l_channel_pair_power = ISDIMM_MIN_DIMM_POWER * l_number_of_dimms; } + } - l_throttle_n_per_mba = int(l_utilization / 100 * l_throttle_d / 4); - l_throttle_n_per_chip = l_throttle_n_per_mba; + // Set the throttle multiplier based on how throttles are used + // CDIMMs use per mba and per chip throttles (for l_throttle_n_per_mba and l_throttle_n_per_chip), set to 2 + // ISDIMMs use per slot and per mba throttles (for l_throttle_n_per_mba and l_throttle_n_per_chip), set to 1 + l_throttle_multiplier = (l_custom_dimm == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES) ? 2 : 1; - FAPI_DBG("[Power/DIMM min/max %d/%d cW][Utilization Percent %4.2f][Number of DIMMs %d]", ISDIMM_MIN_DIMM_POWER, - ISDIMM_MAX_DIMM_POWER, l_utilization, l_number_of_dimms); + FAPI_INF("%s [Number MBAs with DIMMs %d][Throttle Multiplier %d]", mss::c_str(i_target_mba), l_num_mba_with_dimms, + l_throttle_multiplier); - } + // Power calculation for channel pair power + l_max_util_power_calc = l_max_util; - // adjust the throttles to minimum utilization if needed - if (l_utilization < l_min_util) + if (l_num_mba_with_dimms > 1) { - l_throttle_n_per_mba = int(l_min_util / 100 * l_throttle_d / 4); - l_throttle_n_per_chip = l_throttle_n_per_mba * l_num_mba_with_dimms; + l_max_util_power_calc = (l_max_util < (static_cast<double>(convert_to_percent(DRAM_UTIL_LIMIT_BOTH_MBA_WITH_DIMMS)))) ? + l_max_util : ( + static_cast<double>(convert_to_percent(DRAM_UTIL_LIMIT_BOTH_MBA_WITH_DIMMS))); } - // ensure that N throttle values are not zero, if so set to lowest values possible - if ( (l_throttle_n_per_mba == 0) || (l_throttle_n_per_chip == 0)) + FAPI_INF("%s [Max Util for power calculations %4.2lf percent]", mss::c_str(i_target_mba), l_max_util_power_calc); + + // Limit utilization to max utilization + l_util_power_calc = (i_utilization > l_max_util_power_calc) ? l_max_util_power_calc : i_utilization; + FAPI_INF("%s [Util for power calculations %4.2lf percent]", mss::c_str(i_target_mba), l_util_power_calc); + + // call p9c_mss_bulk_pwr_util_to_throttle to get the memory throttle Nmba and Nchip settings for the realistic load for power calculations + FAPI_TRY(p9c_mss_bulk_pwr_util_to_throttle(i_target_mba, l_util_power_calc, l_max_util_power_calc, l_throttle_n_per_mba, + l_throttle_n_per_chip, l_throttle_adder, i_utilization_is_a_min_value)); + + // Calculate out the utilization at the throttle settings determined for power calculations (units %) + // throttling disabled with M=0, use MAX_UTIL + if (l_throttle_d == 0) { - l_throttle_n_per_mba = 1; - l_throttle_n_per_chip = l_throttle_n_per_mba * l_num_mba_with_dimms; + l_util_power_calc = convert_to_percent(MAX_UTIL); } - - // for better custom dimm performance for DDR4, set the per mba throttle to the per chip throttle - // Not planning on doing this for DDR3 - if ( (l_dram_gen == fapi2::ENUM_ATTR_CEN_EFF_DRAM_GEN_DDR4) - && (l_custom_dimm == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES) ) + // throttling enabled, use calculated throttle settings to determine utilization + else { - l_throttle_n_per_mba = l_throttle_n_per_chip; + l_util_power_calc = (static_cast<double>(l_throttle_n_per_chip)) * ADDR_TO_DATA_UTIL_CONVERSION / l_throttle_d / + l_throttle_multiplier * PERCENT_CONVERSION; } - // adjust the throttles to the MRW thermal limit throttles (ie. thermal/power limit less than available power) - if ( (l_throttle_n_per_mba > l_runtime_throttle_n_per_mba) || - (l_throttle_n_per_chip > l_runtime_throttle_n_per_chip) ) + // Calculate out the channel pair power at this new utilization setting + l_channel_pair_power = static_cast<uint32_t>((convert_to_percent(l_util_power_calc)) * i_channel_power_slope + + i_channel_power_intercept); + + FAPI_INF("%s [Throttles for power calculations %d/%d/%d]", + mss::c_str(i_target_mba), l_throttle_n_per_mba, l_throttle_n_per_chip, l_throttle_d); + FAPI_INF("%s [UTIL for power calculations %4.2lf percent][Channel Pair Power %d cW]", + mss::c_str(i_target_mba), l_util_power_calc, l_channel_pair_power); + + // N Throttle determination (throttles that will actually be used in hardware) + // Here we calculate the throttle settings based on the input utilization + // Note that the channel pair power is not based on these since those throttle values could be limited + // call p9c_mss_bulk_pwr_util_to_throttle to get the memory throttle Nmba and Nchip settings for the input utilization + FAPI_TRY(p9c_mss_bulk_pwr_util_to_throttle(i_target_mba, i_utilization, l_max_util, l_throttle_n_per_mba, + l_throttle_n_per_chip, l_throttle_adder, i_utilization_is_a_min_value)); + + // Calculate out the utilization at the throttle settings determined based on input utilization + // throttling disabled with M=0, use MAX_UTIL + if (l_throttle_d == 0) { - FAPI_DBG("Throttles [%d/%d/%d] will be limited by power/thermal limit [%d/%d/%d].", l_throttle_n_per_mba, - l_throttle_n_per_chip, l_throttle_d, l_runtime_throttle_n_per_mba, l_runtime_throttle_n_per_chip, l_throttle_d); - - if (l_throttle_n_per_mba > l_runtime_throttle_n_per_mba) - { - l_throttle_n_per_mba = l_runtime_throttle_n_per_mba; - } - - if (l_throttle_n_per_chip > l_runtime_throttle_n_per_chip) - { - l_throttle_n_per_chip = l_runtime_throttle_n_per_chip; - } - + l_utilization_calc = convert_to_percent(MAX_UTIL); + l_utilization_calc_without_throttle_adder = convert_to_percent(MAX_UTIL); } - - // Calculate out the utilization at the final throttle settings - l_utilization = (float)l_throttle_n_per_chip * 4 / l_throttle_d / l_num_mba_with_dimms * 100; - - // Calculate out the utilization at this new utilization setting for custom dimms - // does not matter for non custom dimms since those do not use power curves - if (l_custom_dimm == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES) + // throttling enabled, use calculated throttle settings to determine utilization + else { - l_channel_pair_power = int(l_utilization / 100 * l_channel_power_slope + l_channel_power_intercept); + l_utilization_calc = (static_cast<double>(l_throttle_n_per_chip)) * ADDR_TO_DATA_UTIL_CONVERSION / l_throttle_d / + l_throttle_multiplier * PERCENT_CONVERSION; + l_utilization_calc_without_throttle_adder = (static_cast<double>(l_throttle_n_per_chip - l_throttle_adder)) * + ADDR_TO_DATA_UTIL_CONVERSION / + l_throttle_d / l_throttle_multiplier * PERCENT_CONVERSION; } - FAPI_INF("[Available Channel Pair Power %d cW][UTIL %4.2f][Channel Pair Power %d cW]", l_channel_pair_watt_target, - l_utilization, l_channel_pair_power); - FAPI_INF("[Throttles %d/%d/%d]", l_throttle_n_per_mba, l_throttle_n_per_chip, l_throttle_d); + FAPI_INF("%s [Final Utilization %4.2lf percent][Final Throttles %d/%d/%d]", + mss::c_str(i_target_mba), l_utilization_calc, l_throttle_n_per_mba, l_throttle_n_per_chip, l_throttle_d); // Update output attributes FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_MEM_THROTTLE_NUMERATOR_PER_MBA, @@ -382,21 +452,142 @@ extern "C" { FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_CHANNEL_PAIR_MAXPOWER, i_target_mba, l_channel_pair_power)); - // Check to see if there is not enough available power at l_min_util or higher - if (l_channel_pair_power > l_channel_pair_watt_target) + // Check for error condition if input utilization was a minimum target value to ensure we have + // throttle values that meet it (ie. throttles have util equal to or greater than min util target) + // Note: this applies when p9c_mss_util_to_throttle calls this function + // The calculated utilization could be much higher than the min target, so this will check for that + // Check should make sure input utilization is equal to or less than calculated util without throttle adder + // and input utilization is equal to or greater than the calculated utilization without throttle adder + + FAPI_ASSERT( !((i_utilization_is_a_min_value == true) && + ((l_utilization_calc < i_utilization) || + (l_utilization_calc_without_throttle_adder > i_utilization))), + fapi2::CEN_MSS_MIN_UTILIZATION_ERROR(). + set_UTIL_CALC(static_cast<uint32_t>(l_utilization_calc * PERCENT_CONVERSION)). + set_UTIL_TARGET(static_cast<uint32_t>(i_utilization * PERCENT_CONVERSION)). + set_MEM_MBA(i_target_mba), + "%s Calculated util [%d:%d centi percent] does not meet input min util target [%d centi percent]", + mss::c_str(i_target_mba), + static_cast<uint32_t>(l_utilization_calc_without_throttle_adder * PERCENT_CONVERSION), + static_cast<uint32_t>(l_utilization_calc * PERCENT_CONVERSION), + static_cast<uint32_t>(i_utilization * PERCENT_CONVERSION) + ); + + FAPI_INF("*** p9c_mss_bulk_pwr_util_to_throttle_power COMPLETE on %s ***", mss::c_str(i_target_mba)); + + fapi_try_exit: + return fapi2::current_err; + } + + + /// + /// @brief This function determines the memory throttle values + /// for a given dram data bus utilization value + /// @param[in] i_target_mba: MBA Target + /// @param[in] i_utilization Input Dram data bus utilization value (units %) + /// @param[in] i_max_util Max Dram data bus utilization value (units %) + /// @param[out] o_throttle_n_per_mba N memory throttle for per mba throttles + /// @param[out] o_throttle_n_per_chip N memory throttle for per mba throttles + /// @param[out] o_throttle_adder N throttle adder to use to meet utilization min or max target + /// @param[in] i_utilization_is_a_min_value tells us if i_utilization is a min or max target to meet (0=max, 1=min) + /// @return fapi2::ReturnCode + /// + fapi2::ReturnCode p9c_mss_bulk_pwr_util_to_throttle(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba, + const double i_utilization, + const double i_max_util, + uint32_t& o_throttle_n_per_mba, + uint32_t& o_throttle_n_per_chip, + uint8_t& o_throttle_adder, + const bool i_utilization_is_a_min_value + ) + { + FAPI_INF("*** Running p9c_mss_bulk_pwr_util_to_throttle on %s ***", mss::c_str(i_target_mba)); + + constexpr uint32_t l_min_n_throttle = 1; + uint32_t l_runtime_throttle_n_per_mba = 0; + uint32_t l_runtime_throttle_n_per_chip = 0; + uint8_t l_custom_dimm = 0; + uint32_t l_throttle_d = 0; + uint8_t l_throttle_multiplier = 0; + double l_utilization_calc = 0; + + // get input attributes + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_CUSTOM_DIMM, i_target_mba, l_custom_dimm)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_MEM_M_DRAM_CLOCKS, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), + l_throttle_d)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_RUNTIME_MEM_THROTTLE_NUMERATOR_PER_MBA, + i_target_mba, l_runtime_throttle_n_per_mba)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_RUNTIME_MEM_THROTTLE_NUMERATOR_PER_CHIP, + i_target_mba, l_runtime_throttle_n_per_chip)); + + // Set the throttle multiplier based on how throttles are used + // CDIMMs use per mba and per chip throttles (for l_throttle_n_per_mba and l_throttle_n_per_chip), set to 2 + // ISDIMMs use per slot and per mba throttles (for l_throttle_n_per_mba and l_throttle_n_per_chip), set to 1 + l_throttle_multiplier = (l_custom_dimm == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES) ? 2 : 1; + + // If input util is a min target, then we need to end up with a utilization equal to or higher than it + // Set the throttle adder based on whether input utilization is a min or a max target + // Account for the case when the calculated utilization will equal the input utilization + if ( ( static_cast<uint32_t>((convert_to_percent(i_utilization)) * l_throttle_d / ADDR_TO_DATA_UTIL_CONVERSION * + PERCENT_CONVERSION) != + ( static_cast<uint32_t>((convert_to_percent(i_utilization)) * l_throttle_d / ADDR_TO_DATA_UTIL_CONVERSION) * + PERCENT_CONVERSION) ) + && (i_utilization_is_a_min_value == true) ) + { + o_throttle_adder = 1; + } + + // Calculate the NperChip and NperMBA Throttles + // Uses N/M Throttling. Equation: (DRAM data bus utilization Percent / 100 ) = ((N * 4) / M) + // The 4 is a constant since dram data bus utilization is 4X the address bus utilization + // adjust the throttles to minimum utilization if needed + l_utilization_calc = (i_utilization < UTIL_FLOOR) ? UTIL_FLOOR : i_utilization; + o_throttle_n_per_chip = static_cast<uint32_t>(((convert_to_percent(l_utilization_calc)) * l_throttle_d / + ADDR_TO_DATA_UTIL_CONVERSION) * l_throttle_multiplier + + o_throttle_adder); + + // For throttling efficiency, have the per mba throttle be at max value as long as it is less than or equal to the per chip throttle + if (o_throttle_n_per_chip > ((convert_to_percent(i_max_util)) * l_throttle_d / ADDR_TO_DATA_UTIL_CONVERSION) ) + { + o_throttle_n_per_mba = static_cast<uint32_t>(((convert_to_percent(i_max_util)) * l_throttle_d / + ADDR_TO_DATA_UTIL_CONVERSION)); + } + else { - FAPI_ASSERT(false, - fapi2::CEN_MSS_NOT_ENOUGH_AVAILABLE_DIMM_POWER(). - set_PAIR_POWER(l_channel_pair_power). - set_PAIR_WATT_TARGET(l_channel_pair_watt_target). - set_MEM_MBA(i_target_mba), - "Not enough available memory power [Channel Pair Power %d/%d cW]", l_channel_pair_power, l_channel_pair_watt_target); + o_throttle_n_per_mba = o_throttle_n_per_chip; } - FAPI_INF("*** mss_bulk_pwr_throttles COMPLETE ***"); + // ensure that N throttle values are not zero, if so set to l_min_n_throttle to prevent hangs + if ( (o_throttle_n_per_mba == 0) || (o_throttle_n_per_chip == 0)) + { + o_throttle_n_per_mba = l_min_n_throttle; + o_throttle_n_per_chip = o_throttle_n_per_mba * l_throttle_multiplier; + } + + // for better custom dimm performance, set the per mba throttle to the per chip throttle + o_throttle_n_per_mba = (l_custom_dimm == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES) ? o_throttle_n_per_chip : + o_throttle_n_per_mba; + + // adjust the throttles to the runtime throttles that are based on thermal/power limits + if ( (o_throttle_n_per_mba > l_runtime_throttle_n_per_mba) || + (o_throttle_n_per_chip > l_runtime_throttle_n_per_chip) ) + { + FAPI_INF("%s Throttles for power calculations [%d/%d/%d] will be limited to runtime throttle values [%d/%d/%d].", + mss::c_str(i_target_mba), o_throttle_n_per_mba, o_throttle_n_per_chip, l_throttle_d, + l_runtime_throttle_n_per_mba, l_runtime_throttle_n_per_chip, l_throttle_d); + o_throttle_n_per_mba = (o_throttle_n_per_mba > l_runtime_throttle_n_per_mba) ? l_runtime_throttle_n_per_mba : + o_throttle_n_per_mba; + o_throttle_n_per_chip = (o_throttle_n_per_chip > l_runtime_throttle_n_per_chip) ? l_runtime_throttle_n_per_chip : + o_throttle_n_per_chip; + } + + FAPI_INF("*** p9c_mss_bulk_pwr_util_to_throttle COMPLETE on %s ***", mss::c_str(i_target_mba)); + fapi_try_exit: return fapi2::current_err; } + + } //end extern C diff --git a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_bulk_pwr_throttles.H b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_bulk_pwr_throttles.H index ed67849b3..20f78b47e 100644 --- a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_bulk_pwr_throttles.H +++ b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_bulk_pwr_throttles.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -26,7 +26,7 @@ /// @file p9c_mss_bulk_pwr_throttles.H /// @brief Sets the throttle attributes based on a power limit for the dimms on the channel pair /// -/// *HWP HWP Owner: Luke Mulkey <lwmulkey@us.ibm.com> +/// *HWP HWP Owner: Andre Marin <aamaring@us.ibm.com> /// *HWP HWP Backup: Mike Pardeik <pardeik@us.ibm.com> /// *HWP Team: Memory /// *HWP Level: 2 @@ -41,18 +41,102 @@ //------------------------------------------------------------------------------ #include <fapi2.H> +// Units c%, set to 100% +constexpr uint32_t MAX_UTIL = 10000; +// Conversion factor to convert from address bus utilization to data bus utilization +constexpr uint8_t ADDR_TO_DATA_UTIL_CONVERSION = 4; +// Conversion factor to convert from centi percent to percent +constexpr uint8_t PERCENT_CONVERSION = 100; + +/// +/// @brief This function will convert a value with units of centi percent to percent +/// @tparam T the type to convert into a percentage +/// @param[in] i_value: uint32_t value in centi percent +/// @return the value in percent +/// +template<typename T> +inline T convert_to_percent(const T i_value) +{ + return (i_value / PERCENT_CONVERSION); +} + typedef fapi2::ReturnCode (*p9c_mss_bulk_pwr_throttles_FP_t) ( const fapi2::Target<fapi2::TARGET_TYPE_MBA>& ); +typedef fapi2::ReturnCode (*p9c_mss_bulk_pwr_channel_pair_power_curve_FP_t) +( + const fapi2::Target<fapi2::TARGET_TYPE_MBA>&, + double, + double +); + +typedef fapi2::ReturnCode (*p9c_mss_bulk_pwr_util_to_throttle_power_FP_t) +( + const fapi2::Target<fapi2::TARGET_TYPE_MBA>&, + double, + const double, + const double, + const bool +); + + extern "C" { - /// @brief mss_bulk_pwr_throttles procedure. Set dimm and channel throttle attributes based on available centaur mba port power - /// @param[in] i_target_mba Reference to centaur mba target + /// @brief Set dimm and channel throttle attributes based on available centaur mba port power + /// @param[in] i_target_mba: MBA Target /// @return ReturnCode fapi2::ReturnCode p9c_mss_bulk_pwr_throttles(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba); + /// + /// @brief This function determines the channel pair power slope and intercept values to use + /// to calculate the channel pair power (ie. power of dimms attached to channel pair) + /// @param[in] i_target_mba: MBA Target + /// @param[out] o_channel_power_slope channel pair power slope + /// @param[out] o_channel_power_intercept channel pair power intercept + /// @return fapi2::ReturnCode + /// + fapi2::ReturnCode p9c_mss_bulk_pwr_channel_pair_power_curve(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba, + double& o_channel_power_slope, + double& o_channel_power_intercept); + + /// + /// @brief This function determines the memory throttle and channel pair power + /// attribute values for a given dram data bus utilization value + /// @param[in] i_target_mba: MBA Target + /// @param[in] i_utilization Dram data bus utilization value (units %) + /// @param[in] i_channel_power_slope channel pair power slope + /// @param[in] i_channel_power_intercept channel pair power + /// @param[in] i_utilization_is_a_min_value tells us if i_utilization is a min or max target to meet (0=max, 1=min) + /// @return fapi2::ReturnCode + /// + fapi2::ReturnCode p9c_mss_bulk_pwr_util_to_throttle_power(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba, + double i_utilization, + const double i_channel_power_slope, + const double i_channel_power_intercept, + const bool i_utilization_is_a_min_value); + + /// + /// @brief This function determines the memory throttle values + /// for a given dram data bus utilization value + /// @param[in] i_target_mba: MBA Target + /// @param[in] i_utilization Input Dram data bus utilization value (units %) + /// @param[in] i_max_util Max Dram data bus utilization value (units %) + /// @param[out] o_throttle_n_per_mba N memory throttle for per mba throttles + /// @param[out] o_throttle_n_per_chip N memory throttle for per mba throttles + /// @param[out] o_throttle_adder N throttle adder to use to meet utilization min or max target + /// @param[in] i_utilization_is_a_min_value tells us if i_utilization is a min or max target to meet (0=max, 1=min) + /// @return fapi2::ReturnCode + /// + fapi2::ReturnCode p9c_mss_bulk_pwr_util_to_throttle(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba, + const double i_utilization, + const double i_max_util, + uint32_t& o_throttle_n_per_mba, + uint32_t& o_throttle_n_per_chip, + uint8_t& o_throttle_adder, + const bool i_utilization_is_a_min_value); + } // extern "C" #endif // MSS_BULK_PWR_THROTTLES_H_ diff --git a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_eff_config_thermal.C b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_eff_config_thermal.C index b30946cf8..69fe85e6e 100644 --- a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_eff_config_thermal.C +++ b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_eff_config_thermal.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -25,16 +25,15 @@ /// @file p9c_mss_eff_config_thermal.C /// @brief set the default throttle and power attributes for dimms in a given system /// -/// *HWP HWP Owner: Luke Mulkey <lwmulkey@us.ibm.com> +/// *HWP HWP Owner: Andre Marin <aamaring@us.ibm.com> /// *HWP HWP Backup: Mike Pardeik <pardeik@us.ibm.com> /// *HWP Team: Memory /// *HWP Level: 2 /// *HWP Consumed by: HB - -// attributes for dimms in a given system +// // -- The power attributes are the slope/intercept values. Note that these // values are in cW. -// -- ISDIMM will calculate values based on various attributes +// -- ISDIMM will use hardcoded values // -- CDIMM will get values from VPD // -- The throttle attributes will setup values for IPL and runtime // @@ -45,20 +44,34 @@ #include <p9c_mss_bulk_pwr_throttles.H> #include <generic/memory/lib/utils/c_str.H> #include <dimmConsts.H> +#include <generic/memory/lib/utils/count_dimm.H> +#include <generic/memory/lib/utils/find.H> //------------------------------------------------------------------------------ // Includes //------------------------------------------------------------------------------ #include <fapi2.H> +using fapi2::TARGET_TYPE_MEMBUF_CHIP; +using fapi2::TARGET_TYPE_MBA; +using fapi2::FAPI2_RC_SUCCESS; + // Only use values here (not any valid bits or flag bits) constexpr uint32_t CDIMM_POWER_SLOPE_DEFAULT = 0x0358; constexpr uint32_t CDIMM_POWER_INT_DEFAULT = 0x00CE; +// ISDIMM power curves (non-custom DIMMs) +// Hard coded values make one DIMM power curve for all configurations +// If other future systems need different hard coded values, then these will need to come from MRW +constexpr uint32_t ISDIMM_VMEM_POWER_SLOPE_DEFAULT = 0x0234; +constexpr uint32_t ISDIMM_VMEM_POWER_INT_DEFAULT = 0x027F; +constexpr uint32_t ISDIMM_VMEM_PLUS_VPP_POWER_SLOPE_DEFAULT = 0x0247; +constexpr uint32_t ISDIMM_VMEM_PLUS_VPP_POWER_INT_DEFAULT = 0x02BC; + extern "C" { /// - /// @brief mss_eff_config_thermal(): This function determines the + /// @brief This function determines the /// power curve and throttle attribute values to use - /// @param[in] const fapi2::Target<fapi2::TARGET_TYPE_MBA> & i_target_mba: MBA Target<fapi2::TARGET_TYPE_MBA> passed in + /// @param[in] i_target_mba: MBA Target /// @return fapi2::ReturnCode /// fapi2::ReturnCode p9c_mss_eff_config_thermal(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba) @@ -67,6 +80,13 @@ extern "C" { FAPI_INF("*** Running mss_eff_config_thermal on %s ***", mss::c_str(i_target_mba)); + // If MBA has no DIMMs, return as there is nothing to do + if (mss::count_dimm(i_target_mba) == 0) + { + FAPI_INF("++++ NO DIMM on %s ++++", mss::c_str(i_target_mba)); + return fapi2::FAPI2_RC_SUCCESS; + } + FAPI_TRY(mss_eff_config_thermal_powercurve(i_target_mba)); FAPI_TRY(mss_eff_config_thermal_throttles(i_target_mba)); @@ -78,9 +98,9 @@ extern "C" { } /// - /// @brief mss_eff_config_thermal_powercurve(): This function determines the + /// @brief This function determines the /// power curve attribute values to use - /// @param[in] const fapi2::Target<fapi2::TARGET_TYPE_MBA> & i_target_mba: MBA Target<fapi2::TARGET_TYPE_MBA> passed in + /// @param[in] i_target_mba: MBA Target /// @return fapi2::ReturnCode /// fapi2::ReturnCode mss_eff_config_thermal_powercurve(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba) @@ -123,7 +143,7 @@ extern "C" { FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DRAM_GEN, i_target_mba, l_dram_gen)); - // Only get power curve values for custom dimms to prevent errors + // get power curve values for custom DIMMs if (l_custom_dimm == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES) { // These are the CDIMM power curve values for only VMEM (DDR3 and DDR4) @@ -237,7 +257,8 @@ extern "C" { 0x4000) == 0)) ) { - FAPI_INF("WARNING: VMEM power curve data is lab data, not ship level data. Using data anyways."); + FAPI_INF("%s WARNING: VMEM power curve data is lab data, not ship level data. Using data anyways.", + mss::c_str(i_target_mba)); } // check total power curve (VMEM+VPP) values for DDR4 @@ -270,7 +291,8 @@ extern "C" { 0x4000) == 0)) ) { - FAPI_INF("WARNING: Total power curve data is lab data, not ship level data. Using data anyways."); + FAPI_INF("%s WARNING: Total power curve data is lab data, not ship level data. Using data anyways.", + mss::c_str(i_target_mba)); } } else @@ -293,11 +315,12 @@ extern "C" { FAPI_ASSERT(false, fapi2::CEN_MSS_DIMM_POWER_CURVE_DATA_INVALID(). set_MEM_CHIP(l_target_chip). - set_FFDC_DATA_1(l_cdimm_master_power_slope). - set_FFDC_DATA_2(l_cdimm_master_power_intercept). - set_FFDC_DATA_3(l_cdimm_supplier_power_slope). - set_FFDC_DATA_4(l_cdimm_supplier_power_intercept), - ""); + set_MASTER_SLOPE(l_cdimm_master_power_slope). + set_MASTER_INTERCEPT(l_cdimm_master_power_intercept). + set_SUPPLIER_SLOPE(l_cdimm_supplier_power_slope). + set_SUPPLIER_INTERCEPT(l_cdimm_supplier_power_intercept), + "%s CDIMM VPD power curve values not valid", mss::c_str(i_target_mba) + ); } } } @@ -342,26 +365,55 @@ extern "C" { FAPI_ASSERT(false, fapi2::CEN_MSS_DIMM_POWER_CURVE_DATA_INVALID(). set_MEM_CHIP(l_target_chip). - set_FFDC_DATA_1(l_cdimm_master_power_slope). - set_FFDC_DATA_2(l_cdimm_master_power_intercept). - set_FFDC_DATA_3(l_cdimm_supplier_power_slope). - set_FFDC_DATA_4(l_cdimm_supplier_power_intercept), - ""); + set_MASTER_SLOPE(l_cdimm_master_power_slope). + set_MASTER_INTERCEPT(l_cdimm_master_power_intercept). + set_SUPPLIER_SLOPE(l_cdimm_supplier_power_slope). + set_SUPPLIER_INTERCEPT(l_cdimm_supplier_power_intercept), + "%s CDIMM VPD power curve values not valid", mss::c_str(i_target_mba) + ); } } - FAPI_DBG("CDIMM VMEM Power [P%d:D%d][SLOPE=%d:INT=%d cW][SLOPE2=%d:INT2=%d cW]", l_port, l_dimm, + FAPI_DBG("%s CustomDIMM VMEM Power [P%d:D%d][SLOPE=%d:INT=%d cW][SLOPE2=%d:INT2=%d cW]", + mss::c_str(i_target_mba), l_port, l_dimm, l_power_slope_array[l_port][l_dimm], l_power_int_array[l_port][l_dimm], l_power_slope2_array[l_port][l_dimm], l_power_int2_array[l_port][l_dimm]); - FAPI_DBG("CDIMM Total Power [P%d:D%d][VMEM SLOPE=%d:INT=%d cW][VMEM SLOPE2=%d:INT2=%d cW]", l_port, l_dimm, + FAPI_DBG("%s CustomDIMM VMEM+VPP Power [P%d:D%d][SLOPE=%d:INT=%d cW][SLOPE2=%d:INT2=%d cW]", + mss::c_str(i_target_mba), l_port, l_dimm, l_total_power_slope_array[l_port][l_dimm], l_total_power_int_array[l_port][l_dimm], l_total_power_slope2_array[l_port][l_dimm], l_total_power_int2_array[l_port][l_dimm]); } + // non custom dimm power curves + else + { + l_power_slope_array[l_port][l_dimm] = + ISDIMM_VMEM_POWER_SLOPE_DEFAULT; + l_power_int_array[l_port][l_dimm] = + ISDIMM_VMEM_POWER_INT_DEFAULT; + l_power_slope2_array[l_port][l_dimm] = + ISDIMM_VMEM_POWER_SLOPE_DEFAULT; + l_power_int2_array[l_port][l_dimm] = + ISDIMM_VMEM_POWER_INT_DEFAULT; + l_total_power_slope_array[l_port][l_dimm] = + ISDIMM_VMEM_PLUS_VPP_POWER_SLOPE_DEFAULT; + l_total_power_int_array[l_port][l_dimm] = + ISDIMM_VMEM_PLUS_VPP_POWER_INT_DEFAULT; + l_total_power_slope2_array[l_port][l_dimm] = + ISDIMM_VMEM_PLUS_VPP_POWER_SLOPE_DEFAULT; + l_total_power_int2_array[l_port][l_dimm] = + ISDIMM_VMEM_PLUS_VPP_POWER_INT_DEFAULT; + FAPI_DBG("%s NonCustomDIMM VMEM Power [P%d:D%d][SLOPE=%d:INT=%d cW][SLOPE2=%d:INT2=%d cW]", + mss::c_str(i_target_mba), l_port, l_dimm, + l_power_slope_array[l_port][l_dimm], l_power_int_array[l_port][l_dimm], l_power_slope2_array[l_port][l_dimm], + l_power_int2_array[l_port][l_dimm]); + FAPI_DBG("%s NonCustomDIMM VMEM+VPP Power [P%d:D%d][SLOPE=%d:INT=%d cW][SLOPE2=%d:INT2=%d cW]", + mss::c_str(i_target_mba), l_port, l_dimm, + l_total_power_slope_array[l_port][l_dimm], l_total_power_int_array[l_port][l_dimm], + l_total_power_slope2_array[l_port][l_dimm], + l_total_power_int2_array[l_port][l_dimm]); - // non custom dimms will no longer use power curves - // These will use a simplified approach of using throttle values for certain ranges of power - // in mss_bulk_pwr_throttles. + } } } } @@ -388,8 +440,8 @@ extern "C" { } /// - /// @brief mss_eff_config_thermal_throttles(): This function determines the throttle attribute values to use - /// @l_param[in] const fapi2::Target<fapi2::TARGET_TYPE_MBA> & i_target_mba: MBA Target<fapi2::TARGET_TYPE_MBA> passed in + /// @brief This function determines the throttle attribute values to use + /// @param[in] i_target_mba: MBA Target /// @return fapi2::ReturnCode /// fapi2::ReturnCode mss_eff_config_thermal_throttles(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba) @@ -398,7 +450,7 @@ extern "C" { FAPI_INF("*** Running mss_eff_config_thermal_throttles on %s ***", mss::c_str(i_target_mba)); -// variables used in this function + // variables used in this function uint8_t l_custom_dimm = 0; uint8_t l_num_dimms_on_port = 0; uint32_t l_runtime_throttle_n_per_mba = 0; @@ -407,12 +459,12 @@ extern "C" { uint32_t l_dimm_thermal_power_limit = 0; uint32_t l_channel_pair_thermal_power_limit = 0; uint8_t l_num_mba_with_dimms = 0; - uint8_t l_mba_index = 0; uint8_t l_ras_increment = 0; uint8_t l_cas_increment = 0; uint32_t l_max_dram_databus_util = 0; uint32_t l_dimm_reg_power_limit_per_dimm_adj = 0; uint32_t l_dimm_reg_power_limit_per_dimm = 0; + uint32_t l_dimm_reg_power_limit_per_dimm_ddr3 = 0; uint32_t l_dimm_reg_power_limit_per_dimm_ddr4 = 0; uint8_t l_max_number_dimms_per_reg = 0; uint8_t l_dimm_reg_power_limit_adj_enable = 0; @@ -422,29 +474,16 @@ extern "C" { uint32_t l_power_int_array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; uint32_t l_total_power_slope_array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; uint32_t l_total_power_int_array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; - float MAX_UTIL; - fapi2::ReturnCode rc; + fapi2::ReturnCode l_rc; + uint8_t l_throttle_multiplier = 0; + uint32_t l_safemode_throttle_n_per_mba = 0; + uint32_t l_safemode_throttle_n_per_chip = 0; // Get Centaur target for the given MBA - const auto l_target_chip = i_target_mba.getParent<fapi2::TARGET_TYPE_MEMBUF_CHIP>(); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_CUSTOM_DIMM, i_target_mba, l_custom_dimm)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_NUM_DROPS_PER_PORT, i_target_mba, l_num_dimms_on_port)); - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MRW_THERMAL_MEMORY_POWER_LIMIT, - fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_dimm_thermal_power_limit)); - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_MEM_M_DRAM_CLOCKS, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), - l_runtime_throttle_d)); - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_MAX_DRAM_DATABUS_UTIL, - fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_max_dram_databus_util)); - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MRW_VMEM_REGULATOR_MEMORY_POWER_LIMIT_PER_DIMM_DDR3, - fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_dimm_reg_power_limit_per_dimm)); - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MRW_VMEM_REGULATOR_MEMORY_POWER_LIMIT_PER_DIMM_DDR4, - fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_dimm_reg_power_limit_per_dimm_ddr4)); - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_MAX_NUMBER_DIMMS_POSSIBLE_PER_VMEM_REGULATOR, - fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_max_number_dimms_per_reg)); - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_VMEM_REGULATOR_POWER_LIMIT_PER_DIMM_ADJ_ENABLE, - fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_dimm_reg_power_limit_adj_enable)); - FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_VMEM_REGULATOR_MAX_DIMM_COUNT, + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_VMEM_REGULATOR_MAX_DIMM_COUNT, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_reg_max_dimm_count)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DRAM_GEN, i_target_mba, l_dram_gen)); @@ -457,29 +496,84 @@ extern "C" { FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_TOTAL_POWER_INT, i_target_mba, l_total_power_int_array)); - // Get number of Centaur MBAs that have dimms present - // Custom dimms (CDIMMs) use mba/chip throttling, so count number of mbas that have dimms - if (l_custom_dimm == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES) + // If any of these are zero and used, then we will end up with an error in p9c_mss_bulk_pwr_throttles + // (CEN_MSS_NOT_ENOUGH_AVAILABLE_DIMM_POWER), so no need to check these here + // ATTR_CEN_MRW_THERMAL_MEMORY_POWER_LIMIT + // ATTR_MRW_VMEM_REGULATOR_MEMORY_POWER_LIMIT_PER_DIMM_DDR3 + // ATTR_MRW_VMEM_REGULATOR_MEMORY_POWER_LIMIT_PER_DIMM_DDR4 + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MRW_THERMAL_MEMORY_POWER_LIMIT, + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_dimm_thermal_power_limit)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MRW_VMEM_REGULATOR_MEMORY_POWER_LIMIT_PER_DIMM_DDR3, + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_dimm_reg_power_limit_per_dimm_ddr3)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MRW_VMEM_REGULATOR_MEMORY_POWER_LIMIT_PER_DIMM_DDR4, + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_dimm_reg_power_limit_per_dimm_ddr4)); + + // If these are zero then the power limit adjustment just won't happen + // Not deemed critical enough to stop the IPL, so no error will be called out + // ATTR_MSS_MRW_MAX_NUMBER_DIMMS_POSSIBLE_PER_VMEM_REGULATOR + // ATTR_MSS_MRW_VMEM_REGULATOR_POWER_LIMIT_PER_DIMM_ADJ_ENABLE + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_MAX_NUMBER_DIMMS_POSSIBLE_PER_VMEM_REGULATOR, + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_max_number_dimms_per_reg)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_VMEM_REGULATOR_POWER_LIMIT_PER_DIMM_ADJ_ENABLE, + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_dimm_reg_power_limit_adj_enable)); + + // Error out if we have invalid MRW attribute combination: + // ATTR_MSS_MRW_MAX_DRAM_DATABUS_UTIL = 0 with ATTR_MSS_MRW_MEM_M_DRAM_CLOCKS > 0 (throttling enabled) is not valid + // because we would end up with N=0 and M>0 for N/M throttling which will cause hangs + // Note that M=0 has memory throttling disabled + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_MEM_M_DRAM_CLOCKS, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), + l_runtime_throttle_d)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_MAX_DRAM_DATABUS_UTIL, + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_max_dram_databus_util)); + FAPI_ASSERT( !((l_runtime_throttle_d > 0) && (l_max_dram_databus_util == 0)), + fapi2::CEN_MSS_MRW_MAX_DRAM_DATABUS_UTIL_INVALID(). + set_MRW_DRAM_UTIL(l_max_dram_databus_util). + set_MRW_M_THROTTLE(l_runtime_throttle_d), + "Invalid MRW values: ATTR_MSS_MRW_MAX_DRAM_DATABUS_UTIL %d ATTR_MSS_MRW_MEM_M_DRAM_CLOCKS %d", l_max_dram_databus_util, + l_runtime_throttle_d); + + // Error out if the safemode MRW attributes are zero + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MRW_SAFEMODE_MEM_THROTTLE_NUMERATOR_PER_MBA, + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), + l_safemode_throttle_n_per_mba)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MRW_SAFEMODE_MEM_THROTTLE_NUMERATOR_PER_CHIP, + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), + l_safemode_throttle_n_per_chip)); + FAPI_ASSERT( !((l_safemode_throttle_n_per_mba == 0) || (l_safemode_throttle_n_per_chip == 0)), + fapi2::CEN_MSS_MRW_SAFEMODE_THROTTLES_INVALID(). + set_MRW_SAFEMODE_N_MBA(l_safemode_throttle_n_per_mba). + set_MRW_SAFEMODE_N_CHIP(l_safemode_throttle_n_per_chip), + "Invalid MRW values: ATTR_CEN_MRW_SAFEMODE_MEM_THROTTLE_NUMERATOR_PER_MBA %d ATTR_CEN_MRW_SAFEMODE_MEM_THROTTLE_NUMERATOR_PER_CHIP %d", + l_safemode_throttle_n_per_mba, l_safemode_throttle_n_per_chip); + + // If throttling is disabled, set max util to MAX_UTIL + if (l_runtime_throttle_d == 0) { - const auto l_target_mba_array = l_target_chip.getChildren<fapi2::TARGET_TYPE_MBA>(); - l_num_mba_with_dimms = 0; + FAPI_INF("%s Memory Throttling is Disabled with M=0", mss::c_str(i_target_mba)); + l_max_dram_databus_util = MAX_UTIL; + } - for (l_mba_index = 0; l_mba_index < l_target_mba_array.size(); l_mba_index++) - { - const auto l_target_dimm_array = l_target_mba_array[l_mba_index].getChildren<fapi2::TARGET_TYPE_DIMM>(); + // get number of mba's with dimms, used below to help determine power limit values below + // Have to have this section in braces otherwise compile fails + { + const auto& l_target_chip = mss::find_target<TARGET_TYPE_MEMBUF_CHIP>(i_target_mba); - if (l_target_dimm_array.size() > 0) + for (const auto& l_mba : mss::find_targets<TARGET_TYPE_MBA>(l_target_chip)) + { + if (mss::count_dimm(l_mba) > 0) { l_num_mba_with_dimms++; } } } - // ISDIMM (non custom dimm) uses dimm/mba throttling, so set num_mba_with_dimms to 1 - else - { - l_num_mba_with_dimms = 1; - } + // Set the throttle multiplier based on how throttles are used + // CDIMMs use per mba and per chip throttles (for l_throttle_n_per_mba and l_throttle_n_per_chip), set to 2 + // ISDIMMs use per slot and per mba throttles (for l_throttle_n_per_mba and l_throttle_n_per_chip), set to 1 + l_throttle_multiplier = (l_custom_dimm == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES) ? 2 : 1; + + FAPI_INF("%s [Number MBAs with DIMMs %d][Throttle Multiplier %d]", mss::c_str(i_target_mba), l_num_mba_with_dimms, + l_throttle_multiplier); //------------------------------------------------------------------------------ // Memory Throttle Determination @@ -503,16 +597,8 @@ extern "C" { // adjust the regulator power limit per dimm if enabled and use this if less than the thermal limit // If DDR4, use DDR4 regulator power limit - if (l_dram_gen == fapi2::ENUM_ATTR_CEN_EFF_DRAM_GEN_DDR4) - { - l_dimm_reg_power_limit_per_dimm = l_dimm_reg_power_limit_per_dimm_ddr4; - } - - // If reg power limit is zero, then set to thermal limit - needed for ISDIMM systems since some of these MRW attributes are not defined - if (l_dimm_reg_power_limit_per_dimm == 0) - { - l_dimm_reg_power_limit_per_dimm = l_dimm_thermal_power_limit; - } + l_dimm_reg_power_limit_per_dimm = (l_dram_gen == fapi2::ENUM_ATTR_CEN_EFF_DRAM_GEN_DDR4) ? + l_dimm_reg_power_limit_per_dimm_ddr4 : l_dimm_reg_power_limit_per_dimm_ddr3; l_dimm_reg_power_limit_per_dimm_adj = l_dimm_reg_power_limit_per_dimm; @@ -528,45 +614,35 @@ extern "C" { l_dimm_reg_power_limit_per_dimm * l_max_number_dimms_per_reg / l_reg_max_dimm_count; - FAPI_INF("VMEM Regulator Power/DIMM Limit Adjustment from %d to %d cW (DIMMs under regulator %d/%d)", - l_dimm_reg_power_limit_per_dimm, l_dimm_reg_power_limit_per_dimm_adj, l_reg_max_dimm_count, l_max_number_dimms_per_reg); + FAPI_INF("%s VMEM Regulator Power/DIMM Limit Adjustment from %d to %d cW (DIMMs under regulator %d/%d)", + mss::c_str(i_target_mba), l_dimm_reg_power_limit_per_dimm, l_dimm_reg_power_limit_per_dimm_adj, + l_reg_max_dimm_count, l_max_number_dimms_per_reg); } } // Use the smaller of the thermal limit and regulator power limit per dimm - if (l_dimm_reg_power_limit_per_dimm_adj < l_dimm_thermal_power_limit) - { - l_dimm_thermal_power_limit = l_dimm_reg_power_limit_per_dimm_adj; - } + FAPI_INF("%s Power/DIMM: VMEM Regulator Limit %d cW, DIMM Thermal Limit %d cW", + mss::c_str(i_target_mba), l_dimm_reg_power_limit_per_dimm_adj, l_dimm_thermal_power_limit); + l_dimm_thermal_power_limit = (l_dimm_reg_power_limit_per_dimm_adj < l_dimm_thermal_power_limit) ? + l_dimm_reg_power_limit_per_dimm_adj : l_dimm_thermal_power_limit; // Adjust the thermal/power limit to represent the power for all dimms under an MBA - if (l_custom_dimm == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES) - { - l_channel_pair_thermal_power_limit = - l_dimm_thermal_power_limit / l_num_mba_with_dimms; - } + // CDIMM thermal power limit is for both MBAs, so divide by number of MBAs // ISDIMMs thermal power limit from MRW is per DIMM, so multiply by number of dimms on channel to get channel power and multiply by 2 to get channel pair power - else - { - // ISDIMMs - l_channel_pair_thermal_power_limit = - l_dimm_thermal_power_limit * l_num_dimms_on_port * 2; - } + l_channel_pair_thermal_power_limit = (l_custom_dimm == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES) ? + (l_dimm_thermal_power_limit / l_num_mba_with_dimms) : + (l_dimm_thermal_power_limit * l_num_dimms_on_port * 2); // Update the channel pair power limit attribute FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_MEM_WATT_TARGET, i_target_mba, l_channel_pair_thermal_power_limit)); - - - - // Initialize the runtime throttle attributes to an unthrottled value for mss_bulk_pwr_throttles - // max utilization comes from MRW value in c% - convert to % - MAX_UTIL = (float) l_max_dram_databus_util / 100; - l_runtime_throttle_n_per_mba = (int)(l_runtime_throttle_d * (MAX_UTIL / 100) / 4); - l_runtime_throttle_n_per_chip = (int)(l_runtime_throttle_d * (MAX_UTIL / 100) / 4) * - l_num_mba_with_dimms; + l_runtime_throttle_n_per_mba = (static_cast<uint32_t>(l_runtime_throttle_d * ((static_cast<double> + (convert_to_percent(l_max_dram_databus_util))) / PERCENT_CONVERSION) / ADDR_TO_DATA_UTIL_CONVERSION)); + l_runtime_throttle_n_per_chip = (static_cast<uint32_t>(l_runtime_throttle_d * ((static_cast<double> + (convert_to_percent(l_max_dram_databus_util))) / PERCENT_CONVERSION) / ADDR_TO_DATA_UTIL_CONVERSION) * + l_throttle_multiplier); // for better custom dimm performance for DDR4, set the per mba throttle to the per chip throttle // Not planning on doing this for DDR3 @@ -579,17 +655,14 @@ extern "C" { FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_RUNTIME_MEM_THROTTLE_NUMERATOR_PER_MBA, i_target_mba, l_runtime_throttle_n_per_mba)); - - - FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_RUNTIME_MEM_THROTTLE_NUMERATOR_PER_CHIP, i_target_mba, l_runtime_throttle_n_per_chip)); - FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_RUNTIME_MEM_THROTTLE_DENOMINATOR, i_target_mba, l_runtime_throttle_d)); - FAPI_INF("Min Power/Thermal Limit per MBA %d cW. Unthrottled values [%d/%d/%d].", l_channel_pair_thermal_power_limit, + FAPI_INF("%s Min Power/Thermal Limit per MBA %d cW. Unthrottled values [%d/%d/%d].", + mss::c_str(i_target_mba), l_channel_pair_thermal_power_limit, l_runtime_throttle_n_per_mba, l_runtime_throttle_n_per_chip, l_runtime_throttle_d); @@ -606,7 +679,8 @@ extern "C" { // Call the procedure function that takes a channel pair power limit and // converts it to throttle values - FAPI_EXEC_HWP(rc, p9c_mss_bulk_pwr_throttles, i_target_mba); + FAPI_EXEC_HWP(l_rc, p9c_mss_bulk_pwr_throttles, i_target_mba); + FAPI_TRY(l_rc, "Failed running p9c_mss_bulk_pwr_throttles on %s", mss::c_str(i_target_mba)); // Reset the total power curve attributes back to the original values if (l_dram_gen == fapi2::ENUM_ATTR_CEN_EFF_DRAM_GEN_DDR4) @@ -635,14 +709,12 @@ extern "C" { FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_RUNTIME_MEM_THROTTLE_NUMERATOR_PER_MBA, i_target_mba, l_runtime_throttle_n_per_mba)); - FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_RUNTIME_MEM_THROTTLE_NUMERATOR_PER_CHIP, i_target_mba, l_runtime_throttle_n_per_chip)); FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_RUNTIME_MEM_THROTTLE_DENOMINATOR, i_target_mba, l_runtime_throttle_d)); - FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_THROTTLE_CONTROL_RAS_WEIGHT, i_target_mba, l_ras_increment)); diff --git a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_eff_config_thermal.H b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_eff_config_thermal.H index 9503e8474..a27e1dc56 100644 --- a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_eff_config_thermal.H +++ b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_eff_config_thermal.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -25,7 +25,7 @@ /// @file p9c_mss_eff_config_thermal.H /// @brief Header file for mss_eff_config_thermal /// -/// *HWP HWP Owner: Luke Mulkey <lwmulkey@us.ibm.com> +/// *HWP HWP Owner: Andre Marin <aamaring@us.ibm.com> /// *HWP HWP Backup: Mike Pardeik <pardeik@us.ibm.com> /// *HWP Team: Memory /// *HWP Level: 2 @@ -44,23 +44,23 @@ typedef fapi2::ReturnCode (*p9c_mss_eff_config_thermal_FP_t)(const fapi2::Target extern "C" { /// - /// @brief mss_eff_config_thermal procedure. Sets up dimm power curve attributes and dimm and channel throttle attributes - /// @param[in] i_target_mba Reference to centaur mba target + /// @brief Sets up dimm power curve attributes and dimm and channel throttle attributes + /// @param[in] i_target_mba: MBA Target /// @return ReturnCode /// fapi2::ReturnCode p9c_mss_eff_config_thermal(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba); /// - /// @brief mss_eff_config_thermal_powercurve(): This function determines the + /// @brief This function determines the /// power curve attribute values to use - /// @param[in] const fapi2::Target<fapi2::TARGET_TYPE_MBA> & i_target_mba: MBA Target<fapi2::TARGET_TYPE_MBA> passed in + /// @param[in] i_target_mba: MBA Target /// @return fapi2::ReturnCode /// fapi2::ReturnCode mss_eff_config_thermal_powercurve(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba); /// - /// @brief mss_eff_config_thermal_throttles(): This function determines the throttle attribute values to use - /// @l_param[in] const fapi2::Target<fapi2::TARGET_TYPE_MBA> & i_target_mba: MBA Target<fapi2::TARGET_TYPE_MBA> passed in + /// @brief This function determines the throttle attribute values to use + /// @param[in] i_target_mba: MBA Target /// @return fapi2::ReturnCode /// fapi2::ReturnCode mss_eff_config_thermal_throttles(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba); diff --git a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_util_to_throttle.C b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_util_to_throttle.C index 2c4f9a075..11ee3d3a7 100644 --- a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_util_to_throttle.C +++ b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_util_to_throttle.C @@ -22,3 +22,71 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ +/// +/// @file p9c_mss_util_to_throttle.C +/// @brief determine N throttle settings for N/M throttling for a given dram data bus util value +/// and the channel pair power at the given utilization value +//// OCC calls this HWP after setting ATTR_CEN_MSS_DATABUS_UTIL_PER_MBA +//// ATTR_CEN_MSS_DATABUS_UTIL_PER_MBA is a floor or minimum value to meet +/// +/// *HWP HWP Owner: Andre Marin <aamaring@us.ibm.com> +/// *HWP HWP Backup: Michael Pardeik <pardeik@us.ibm.com> +/// *HWP Team: Memory +/// *HWP Level: 2 +/// *HWP Consumed by: HB:CI +/// + +//------------------------------------------------------------------------------ +// My Includes +//------------------------------------------------------------------------------ +#include <p9c_mss_util_to_throttle.H> +#include <p9c_mss_bulk_pwr_throttles.C> +#include <p9c_mss_bulk_pwr_throttles.H> +#include <generic/memory/lib/utils/c_str.H> +#include <fapi2.H> +#include <generic/memory/lib/utils/c_str.H> + +using fapi2::FAPI2_RC_SUCCESS; + +extern "C" { + /// + /// @brief This function will determine N/M throttles and channel pair power + /// for a given dram data bus util value from attribute ATTR_CEN_MSS_DATABUS_UTIL_PER_MBA + /// @param[in] i_target_mba: MBA Target + /// @return fapi2::ReturnCode + /// + fapi2::ReturnCode p9c_mss_util_to_throttle(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba) + { + FAPI_INF("*** Running p9c_mss_util_to_throttle on %s ***", mss::c_str(i_target_mba)); + + uint8_t l_data_bus_util = 0; + double l_channel_power_slope = 0; + double l_channel_power_intercept = 0; + constexpr bool l_utilization_is_a_min_value = true; // set to true + + // If MBA has no DIMMs, return as there is nothing to do + if (mss::count_dimm(i_target_mba) == 0) + { + FAPI_INF("++++ NO DIMM on %s ++++", mss::c_str(i_target_mba)); + return fapi2::FAPI2_RC_SUCCESS; + } + + // Get input attributes + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_DATABUS_UTIL_PER_MBA, + i_target_mba, l_data_bus_util)); + FAPI_INF("[%s Input Attribute Utilization %d percent]", mss::c_str(i_target_mba), l_data_bus_util); + + // call p9c_mss_bulk_pwr_channel_power to get the channel pair power slope and intercept values to use + FAPI_TRY(p9c_mss_bulk_pwr_channel_pair_power_curve(i_target_mba, l_channel_power_slope, l_channel_power_intercept)); + + // call p9c_mss_bulk_pwr_util_to_throttle_power to get the memory throttle and channel pair power attributes defined + FAPI_TRY(p9c_mss_bulk_pwr_util_to_throttle_power(i_target_mba, + (static_cast<double>(l_data_bus_util)), l_channel_power_slope, + l_channel_power_intercept, l_utilization_is_a_min_value)); + + FAPI_INF("*** p9c_mss_util_to_throttle COMPLETE on %s ***", mss::c_str(i_target_mba)); + + fapi_try_exit: + return fapi2::current_err; + } +} //end extern C diff --git a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_util_to_throttle.H b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_util_to_throttle.H index 42276c2be..2e8c26071 100644 --- a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_util_to_throttle.H +++ b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_util_to_throttle.H @@ -22,3 +22,37 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ +/// +/// @file p9c_mss_util_to_throttle.H +/// @brief determine the minimum N throttle settings for N/M throttling for a given dram data bus util value +/// +/// *HWP HWP Owner: Andre Marin <aamaring@us.ibm.com> +/// *HWP HWP Backup: Michael Pardeik <pardeik@us.ibm.com> +/// *HWP Team: Memory +/// *HWP Level: 2 +/// *HWP Consumed by: HB:CI +/// + +#ifndef MSS_UTIL_TO_THROTTLE_H_ +#define MSS_UTIL_TO_THROTTLE_H_ + +//------------------------------------------------------------------------------ +// Includes +//------------------------------------------------------------------------------ +#include <fapi2.H> + +typedef fapi2::ReturnCode (*p9c_mss_util_to_throttle_FP_t)(const fapi2::Target<fapi2::TARGET_TYPE_MBA>&); + +extern "C" +{ + + /// + /// @brief This function will determine N/M throttles and channel pair power for a given dram data bus util value from attribute ATTR_CEN_MSS_DATABUS_UTIL_PER_MBA + /// @param[in] i_target_mba: MBA Target + /// @return fapi2::ReturnCode + /// + fapi2::ReturnCode p9c_mss_util_to_throttle(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba); + +} // extern "C" + +#endif // MSS_UTIL_TO_THROTTLE_H_ diff --git a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt.C b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt.C index ccde4f816..ba4182c72 100644 --- a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt.C +++ b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -25,7 +25,7 @@ /// @file p9c_mss_volt.C /// @brief Reads in supported DIMM voltages from SPD and determines optimal voltage bin for the DIMM voltage domain. /// -/// *HWP HWP Owner: Luke Mulkey <lwmulkey@us.ibm.com> +/// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com> /// *HWP HWP Backup: Andre Marin <aamaring@us.ibm.com> /// *HWP Team: Memory /// *HWP Level: 2 @@ -354,7 +354,7 @@ fapi2::ReturnCode p9c_mss_volt(const std::vector<fapi2::Target<fapi2::TARGET_TYP } // Initialize DIMM Count Attribute for mss_volt_dimm_count to use - FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_VMEM_REGULATOR_MAX_DIMM_COUNT, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), + FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_MSS_VMEM_REGULATOR_MAX_DIMM_COUNT, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_dimm_count)); fapi_try_exit: diff --git a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt.H b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt.H index db7db0d7c..d41d6e4cf 100644 --- a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt.H +++ b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -25,7 +25,7 @@ /// @file p9c_mss_volt.H /// @brief Reads in supported DIMM voltages from SPD and determines optimal voltage bin for the DIMM voltage domain. /// -/// *HWP HWP Owner: Luke Mulkey <lwmulkey@us.ibm.com> +/// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com> /// *HWP HWP Backup: Andre Marin <aamaring@us.ibm.com> /// *HWP Team: Memory /// *HWP Level: 2 diff --git a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt_dimm_count.C b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt_dimm_count.C index 4d155f9cb..858eb6255 100644 --- a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt_dimm_count.C +++ b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt_dimm_count.C @@ -22,3 +22,102 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ +/// +/// @file p9c_mss_volt_dimm_count.C +/// @brief Determines number of dimms present behind a VDDR voltage domain +/// +/// *HWP HWP Owner: Andre Marin <aamaring@us.ibm.com> +/// *HWP HWP Backup: Michael Pardeik <pardeik@us.ibm.com> +/// *HWP Team: Memory +/// *HWP Level: 2 +/// *HWP Consumed by: HB:CI +/// + +//---------------------------------------------------------------------- +// Includes - FAPI +//---------------------------------------------------------------------- +#include <fapi2.H> +#include <p9c_mss_volt_dimm_count.H> +#include <generic/memory/lib/utils/c_str.H> +#include <generic/memory/lib/utils/find.H> + +using fapi2::TARGET_TYPE_MBA; +using fapi2::TARGET_TYPE_DIMM; + +extern "C" { + /// + /// @brief Determines number of dimms present behind a VDDR voltage domain + /// @param[in] i_targets_memb Reference to vector of present Centaur Targets in a particular VDDR power domain + /// @return ReturnCode + /// + fapi2::ReturnCode p9c_mss_volt_dimm_count(std::vector<fapi2::Target<fapi2::TARGET_TYPE_MEMBUF_CHIP>>& i_targets_memb) + { + FAPI_INF("*** Running p9c_mss_volt_dimm_count ***"); + + uint8_t l_memb_count = 0; + uint8_t l_dimm_count = 0; + uint8_t l_mrw_reg_power_limit_adj_enable = 0; + uint8_t l_mrw_max_number_dimms_per_reg = 0; + uint8_t l_spd_custom = 0; + uint8_t l_custom_dimm = 0; + uint8_t l_dimm_count_under_reg = 0; + uint8_t l_max_dimm_count_per_reg = 0; + + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_VMEM_REGULATOR_POWER_LIMIT_PER_DIMM_ADJ_ENABLE, + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_mrw_reg_power_limit_adj_enable), + "Error gettting attribute ATTR_MSS_MRW_VMEM_REGULATOR_POWER_LIMIT_PER_DIMM_ADJ_ENABLE"); + + if (l_mrw_reg_power_limit_adj_enable == fapi2::ENUM_ATTR_MSS_MRW_VMEM_REGULATOR_POWER_LIMIT_PER_DIMM_ADJ_ENABLE_TRUE) + { + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_MAX_NUMBER_DIMMS_POSSIBLE_PER_VMEM_REGULATOR, + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_mrw_max_number_dimms_per_reg), + "failed to get attribute ATTR_MSS_MRW_MAX_NUMBER_DIMMS_POSSIBLE_PER_VMEM_REGULATOR"); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_VMEM_REGULATOR_MAX_DIMM_COUNT, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), + l_max_dimm_count_per_reg), "Failed to get attribute ATTR_MSS_VMEM_REGULATOR_MAX_DIMM_COUNT"); + + // Iterate through the list of centaurs (configured and deconfigured) + for (const auto& l_memb : i_targets_memb) + { + l_memb_count++; + + // Loop through the attached MBAs and their DIMMs to get a DIMM count + for (const auto& l_mba : mss::find_targets<TARGET_TYPE_MBA>(l_memb, fapi2::TARGET_STATE_PRESENT)) + { + for (const auto& l_dimm : mss::find_targets<TARGET_TYPE_DIMM>(l_mba, fapi2::TARGET_STATE_PRESENT)) + { + l_dimm_count++; + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_SPD_CUSTOM, l_dimm, l_spd_custom), + "failed to get ATTR_CEN_SPD_CUSTOM on dimm %s", mss::c_str(l_dimm)); + l_custom_dimm = (l_spd_custom == fapi2::ENUM_ATTR_CEN_SPD_CUSTOM_YES) ? 1 : l_custom_dimm; + } + } + + // DIMM count will be number of centaurs for custom dimms + // or number of dimms for non custom dimms + l_dimm_count_under_reg = (l_custom_dimm == 1) ? l_memb_count : l_dimm_count; + FAPI_INF("p9c_mss_volt_dimm_count: DIMM Count %d/%d/%d after processing target %s", l_dimm_count_under_reg, + l_max_dimm_count_per_reg, l_mrw_max_number_dimms_per_reg, mss::c_str(l_memb)); + } + + // Error out if number of DIMMs counted is higher than expected + FAPI_ASSERT((l_dimm_count_under_reg <= l_mrw_max_number_dimms_per_reg), + fapi2::CEN_MSS_DIMM_COUNT_EXCEEDS_MAX(). + set_COUNT_CALC(l_dimm_count_under_reg). + set_COUNT_MAX(l_mrw_max_number_dimms_per_reg), + "DIMM count [%d] for targets exceeds max MRW limit [%d]", l_dimm_count_under_reg, l_mrw_max_number_dimms_per_reg); + + // Update attribute only if the DIMM count is higher than what was previously counted on other VDDR rails + if (l_dimm_count_under_reg > l_max_dimm_count_per_reg) + { + FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_MSS_VMEM_REGULATOR_MAX_DIMM_COUNT, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), + l_dimm_count_under_reg), "Failed to set attr ATTR_MSS_VMEM_REGULATOR_MAX_DIMM_COUNT"); + } + } + + FAPI_INF("*** p9c_mss_volt_dimm_count COMPLETE ***"); + + fapi_try_exit: + return fapi2::current_err; + } + +} //end extern C diff --git a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt_dimm_count.H b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt_dimm_count.H index 992c66e1e..d7e2f7032 100644 --- a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt_dimm_count.H +++ b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt_dimm_count.H @@ -22,3 +22,34 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ +/// +/// @file p9c_mss_volt_dimm_count.H +/// @brief Determines number of dimms present behind a voltage domain +/// +/// *HWP HWP Owner: Andre Marin <aamaring@us.ibm.com> +/// *HWP HWP Backup: Michael Pardeik <pardeik@us.ibm.com> +/// *HWP Team: Memory +/// *HWP Level: 2 +/// *HWP Consumed by: HB:CI +/// + +#ifndef MSS_VOLT_DIMM_COUNT_H_ +#define MSS_VOLT_DIMM_COUNT_H_ + +#include <fapi2.H> + +typedef fapi2::ReturnCode (*p9c_mss_volt_dimm_count_FP_t)(std::vector<fapi2::Target<fapi2::TARGET_TYPE_MEMBUF_CHIP>>&); + +extern "C" +{ + + /// + /// @brief Determines number of dimms present behind a voltage domain + /// @param[in] i_targets_memb Reference to vector of present Centaur Targets in a particular power domain + /// @return ReturnCode + /// + fapi2::ReturnCode p9c_mss_volt_dimm_count(std::vector<fapi2::Target<fapi2::TARGET_TYPE_MEMBUF_CHIP>>& i_targets_memb); + +} // extern "C" + +#endif // MSS_VOLT_DIMM_COUNT_H_ diff --git a/src/import/chips/centaur/procedures/xml/attribute_info/memory_attributes.xml b/src/import/chips/centaur/procedures/xml/attribute_info/memory_attributes.xml index 281b03a77..248fda9ef 100644 --- a/src/import/chips/centaur/procedures/xml/attribute_info/memory_attributes.xml +++ b/src/import/chips/centaur/procedures/xml/attribute_info/memory_attributes.xml @@ -3471,16 +3471,6 @@ Will be set at an MBA level with one policy to be used</description> </attribute> <attribute> - <id>ATTR_CEN_MSS_VMEM_REGULATOR_MAX_DIMM_COUNT</id> - <targetType>TARGET_TYPE_SYSTEM</targetType> - <description>Maximum number of installed DIMMs per VMEM regulator for all VMEM regulators in the system.</description> - <valueType>uint8</valueType> - <writeable/> - <odmVisable/> - <odmChangeable/> -</attribute> - -<attribute> <id>ATTR_CEN_MRW_WR_VREF_CHECK_VREF_STEP_SIZE</id> <targetType>TARGET_TYPE_SYSTEM</targetType> <description>Machine Readable Workbook attribute that holds the step size of the VREF when doing a box shmoo</description> diff --git a/src/import/chips/centaur/procedures/xml/attribute_info/memory_occ_attributes.xml b/src/import/chips/centaur/procedures/xml/attribute_info/memory_occ_attributes.xml index 800d17b18..3dd9741b9 100644 --- a/src/import/chips/centaur/procedures/xml/attribute_info/memory_occ_attributes.xml +++ b/src/import/chips/centaur/procedures/xml/attribute_info/memory_occ_attributes.xml @@ -22,5 +22,41 @@ <!-- permissions and limitations under the License. --> <!-- --> <!-- IBM_PROLOG_END_TAG --> +<!-- --> +<!-- @file memory_occ_attributes.xml --> +<!-- @brief Attribute xml for occ memory attributes --> +<!-- --> +<!-- *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com> --> +<!-- *HWP HWP Backup: Michael Pardeik <pardeik@us.ibm.com> --> +<!-- *HWP FW Owner: Bill Hoffa <wghoffa@us.ibm.com> --> +<!-- *HWP Team: Memory --> +<!-- *HWP Level: 2 --> +<!-- *HWP Consumed by: FSP:HB --> +<!-- --> <attributes> + +<attribute> + <id>ATTR_CEN_MSS_DATABUS_UTIL_PER_MBA</id> + <targetType>TARGET_TYPE_MBA</targetType> + <description>MBA DRAM data bus utilization percent to use to determine cfg_nm_n_per_mba</description> + <valueType>uint8</valueType> + <writeable/> + <odmVisable/> + <odmChangeable/> + <persistRuntime/> +</attribute> + +<!-- +<attribute> + <id>ATTR_CEN_MSS_UTIL_N_PER_MBA</id> + <targetType>TARGET_TYPE_MBA</targetType> + <description>cfg_nm_n_per_mba throttle N value calculated from ATTR_CEN_MSS_DATABUS_UTIL_PER_MBA</description> + <valueType>uint32</valueType> + <writeable/> + <odmVisable/> + <odmChangeable/> + <persistRuntime/> +</attribute> +--> + </attributes> diff --git a/src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_bulk_pwr_throttles_errors.xml b/src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_bulk_pwr_throttles_errors.xml index 3c021abe6..0012384d3 100644 --- a/src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_bulk_pwr_throttles_errors.xml +++ b/src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_bulk_pwr_throttles_errors.xml @@ -5,7 +5,7 @@ <!-- --> <!-- OpenPOWER HostBoot Project --> <!-- --> -<!-- Contributors Listed Below - COPYRIGHT 2016,2017 --> +<!-- Contributors Listed Below - COPYRIGHT 2016,2018 --> <!-- [+] International Business Machines Corp. --> <!-- --> <!-- --> @@ -22,13 +22,14 @@ <!-- permissions and limitations under the License. --> <!-- --> <!-- IBM_PROLOG_END_TAG --> -<hwpErrors> <!-- $Id: memory_mss_bulk_pwr_throttles.xml,v 1.5 2014/06/02 13:11:07 pardeik Exp $ --> <!-- For file ../../ipl/fapi/mss_bulk_pwr_throttles.C --> <!-- // *! OWNER NAME : Michael Pardeik Email: pardeik@us.ibm.com --> -<!-- // *! BACKUP NAME : Jacob Sloat Email: jdsloat@us.ibm.com --> - +<!-- // *! BACKUP NAME : Stephen Glancy Email: sglancy@us.ibm.com --> <!-- Original Source for RC_CEN_MSS_NOT_ENOUGH_AVAILABLE_DIMM_POWER memory_errors.xml --> + +<hwpErrors> + <hwpError> <rc>RC_CEN_MSS_NOT_ENOUGH_AVAILABLE_DIMM_POWER</rc> <description>Unable to find throttle setting that has DIMM power underneath the limit.</description> @@ -51,6 +52,30 @@ <childType>TARGET_TYPE_DIMM</childType> </childTargets> </deconfigure> -</hwpError> + </hwpError> + + <hwpError> + <rc>RC_CEN_MSS_MIN_UTILIZATION_ERROR</rc> + <description>Unable to find throttle setting that has utilization at or higher than the minimum limit.</description> + <ffdc>UTIL_CALC</ffdc> + <ffdc>UTIL_TARGET</ffdc> + <callout> + <childTargets> + <parent>MEM_MBA</parent> + <childType>TARGET_TYPE_DIMM</childType> + </childTargets> + <priority>MEDIUM</priority> + </callout> + <callout> + <procedure>CODE</procedure> + <priority>HIGH</priority> + </callout> + <deconfigure> + <childTargets> + <parent>MEM_MBA</parent> + <childType>TARGET_TYPE_DIMM</childType> + </childTargets> + </deconfigure> + </hwpError> </hwpErrors> diff --git a/src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_eff_config_thermal_errors.xml b/src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_eff_config_thermal_errors.xml index 4cf1c7b29..3aea2efe2 100644 --- a/src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_eff_config_thermal_errors.xml +++ b/src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_eff_config_thermal_errors.xml @@ -5,7 +5,7 @@ <!-- --> <!-- OpenPOWER HostBoot Project --> <!-- --> -<!-- Contributors Listed Below - COPYRIGHT 2016,2017 --> +<!-- Contributors Listed Below - COPYRIGHT 2016,2018 --> <!-- [+] International Business Machines Corp. --> <!-- --> <!-- --> @@ -39,18 +39,26 @@ <hwpError> <rc>RC_CEN_MSS_DIMM_POWER_CURVE_DATA_INVALID</rc> <description>DIMM power curve data is invalid</description> - <ffdc>FFDC_DATA_1</ffdc> - <ffdc>FFDC_DATA_2</ffdc> - <ffdc>FFDC_DATA_3</ffdc> - <ffdc>FFDC_DATA_4</ffdc> + <ffdc>MASTER_SLOPE</ffdc> + <ffdc>MASTER_INTERCEPT</ffdc> + <ffdc>SUPPLIER_SLOPE</ffdc> + <ffdc>SUPPLIER_INTERCEPT</ffdc> <callout><target>MEM_CHIP</target><priority>HIGH</priority></callout> -</hwpError> + </hwpError> + + <hwpError> + <rc>RC_CEN_MSS_MRW_MAX_DRAM_DATABUS_UTIL_INVALID</rc> + <description>Invalid value found for attribute </description> + <ffdc>MRW_DRAM_UTIL</ffdc> + <ffdc>MRW_M_THROTTLE</ffdc> + <callout><procedure>CODE</procedure><priority>HIGH</priority></callout> + </hwpError> + <hwpError> - <rc>RC_CEN_MSS_DIMM_NOT_FOUND_IN_POWER_TABLE</rc> - <description>Unable to find matching entry in DIMM power table</description> - <ffdc>FFDC_DATA_1</ffdc> - <ffdc>FFDC_DATA_2</ffdc> - <ffdc>FFDC_DATA_3</ffdc> - <callout><target>MEM_DIMM</target><priority>HIGH</priority></callout> -</hwpError> + <rc>RC_CEN_MSS_MRW_SAFEMODE_THROTTLES_INVALID</rc> + <description>Invalid value found for attribute </description> + <ffdc>MRW_SAFEMODE_N_MBA</ffdc> + <ffdc>MRW_SAFEMODE_N_CHIP</ffdc> + <callout><procedure>CODE</procedure><priority>HIGH</priority></callout> + </hwpError> </hwpErrors> diff --git a/src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_volt_dimm_count_errors.xml b/src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_volt_dimm_count_errors.xml index bd48aa4cc..c1cbbddd8 100644 --- a/src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_volt_dimm_count_errors.xml +++ b/src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_volt_dimm_count_errors.xml @@ -22,5 +22,20 @@ <!-- permissions and limitations under the License. --> <!-- --> <!-- IBM_PROLOG_END_TAG --> +<!-- // *! OWNER NAME : Michael Pardeik Email: pardeik@us.ibm.com --> +<!-- // *! BACKUP NAME : Stephen Glancy Email: sglancy@us.ibm.com --> + <hwpErrors> + + <hwpError> + <rc>RC_CEN_MSS_DIMM_COUNT_EXCEEDS_MAX</rc> + <description>DIMM count for targets exceeds MRW VMEM DIMM Limit.</description> + <ffdc>COUNT_CALC</ffdc> + <ffdc>COUNT_MAX</ffdc> + <callout> + <procedure>CODE</procedure> + <priority>HIGH</priority> + </callout> + </hwpError> + </hwpErrors> diff --git a/src/import/generic/memory/lib/utils/find.H b/src/import/generic/memory/lib/utils/find.H index c73b49619..f5f723438 100644 --- a/src/import/generic/memory/lib/utils/find.H +++ b/src/import/generic/memory/lib/utils/find.H @@ -27,8 +27,8 @@ /// @file find.H /// @brief Templates for finding things /// -// *HWP HWP Owner: Jacob Harvey <jlharvey@us.ibm.com> -// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com> +// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com> +// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com> // *HWP Team: Memory // *HWP Level: 3 // *HWP Consumed by: HB:FSP @@ -62,6 +62,25 @@ inline std::vector< fapi2::Target<M> > find_targets( const fapi2::Target<T>& i_t } /// +/// @brief find a set of elements based on a fapi2 target +/// @tparam M the target type to be returned +/// @tparam T the fapi2 target type of the argument +/// @param[in] i_target the fapi2 target T +/// @param[in] i_state the fapi2 target state for the children of i_target +/// @return a vector of M targets that match the target state specified +/// @note Only works for valid parent-child relationships +/// So calling find_targets<TARGET_TYPE_DIMM>(l_mca) will work here +/// but calling find_targets<TARGET_TYPE_DIMM>(l_mcs) will not work +/// Compiler will freak out and we'll never get a bad relationship/ error at runtime +/// If we do, it's on fapi2 +/// +template< fapi2::TargetType M, fapi2::TargetType T > +inline std::vector< fapi2::Target<M> > find_targets( const fapi2::Target<T>& i_target, fapi2::TargetState i_state) +{ + return i_target.template getChildren<M>(i_state); +} + +/// /// @brief find an element based on a fapi2 target /// @tparam M the target type to be returned /// @tparam T the fapi2 target type of the argument |