summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuke Mulkey <lwmulkey@us.ibm.com>2017-10-11 14:02:56 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2018-05-17 11:35:06 -0400
commit1fd1cc97eb824b7853e652379ba8698c519512e2 (patch)
tree45650b979e378eeac216cd006ada1633771d6aa4
parent01be61c03770d4f837febb9debdfb7318d0b6f3c (diff)
downloadtalos-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>
-rw-r--r--src/import/chips/centaur/procedures/hwp/memory/p9c_mss_bulk_pwr_throttles.C671
-rw-r--r--src/import/chips/centaur/procedures/hwp/memory/p9c_mss_bulk_pwr_throttles.H92
-rw-r--r--src/import/chips/centaur/procedures/hwp/memory/p9c_mss_eff_config_thermal.C286
-rw-r--r--src/import/chips/centaur/procedures/hwp/memory/p9c_mss_eff_config_thermal.H16
-rw-r--r--src/import/chips/centaur/procedures/hwp/memory/p9c_mss_util_to_throttle.C68
-rw-r--r--src/import/chips/centaur/procedures/hwp/memory/p9c_mss_util_to_throttle.H34
-rw-r--r--src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt.C6
-rw-r--r--src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt.H4
-rw-r--r--src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt_dimm_count.C99
-rw-r--r--src/import/chips/centaur/procedures/hwp/memory/p9c_mss_volt_dimm_count.H31
-rw-r--r--src/import/chips/centaur/procedures/xml/attribute_info/memory_attributes.xml10
-rw-r--r--src/import/chips/centaur/procedures/xml/attribute_info/memory_occ_attributes.xml36
-rw-r--r--src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_bulk_pwr_throttles_errors.xml35
-rw-r--r--src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_eff_config_thermal_errors.xml34
-rw-r--r--src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_volt_dimm_count_errors.xml15
-rw-r--r--src/import/generic/memory/lib/utils/find.H23
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
OpenPOWER on IntegriCloud