summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal
diff options
context:
space:
mode:
Diffstat (limited to 'src/import/chips/p9/procedures/hwp/memory/lib/power_thermal')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/decoder.C73
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/decoder.H11
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/throttle.C389
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/throttle.H164
4 files changed, 450 insertions, 187 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/decoder.C b/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/decoder.C
index a6129774a..11da9b2dd 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/decoder.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/decoder.C
@@ -115,6 +115,30 @@ fapi2::ReturnCode decoder::generate_encoding()
fapi_try_exit:
return fapi2::current_err;
}
+///
+///@brief a compare functor for the decoder::find_attr functions below
+///@note AND's the input hash with the generated hash from the DIMM to see if they match
+///@note Using an AND instead of == because not all DIMM configs have power slopes, so defaults are needed
+///
+struct is_match
+{
+ ///
+ ///@brief functor constructor
+ ///@param[in] i_gen_key the class object's constructed hash for the installed dimm, to be compared with the attr array
+ ///
+ is_match(const fapi2::buffer<uint32_t> i_gen_key) : iv_gen_key(i_gen_key) {}
+ const fapi2::buffer<uint32_t> iv_gen_key;
+
+ ///
+ ///@brief Boolean compare used for find_if function
+ ///
+ bool operator()(const fapi2::buffer<uint64_t> i_hash)
+ {
+ uint32_t l_temp = 0;
+ i_hash.extractToRight<ENCODING_START, ENCODING_LENGTH>(l_temp);
+ return ((l_temp & iv_gen_key) == iv_gen_key);
+ }
+};
///
/// @brief Finds a value for the power curve slope attributes by matching the generated hashes
@@ -124,27 +148,18 @@ fapi_try_exit:
///
fapi2::ReturnCode decoder::find_slope (const std::vector<fapi2::buffer<uint64_t>>& i_slope)
{
-
- // Comparator lambda expression
- const auto compare = [this](const fapi2::buffer<uint64_t>& i_hash)
- {
- uint32_t l_temp = 0;
- i_hash.extractToRight<ENCODING_START, ENCODING_LENGTH>(l_temp);
- return ((l_temp & iv_gen_key) == iv_gen_key);
- };
-
// Find iterator to matching key (if it exists)
const auto l_value_iterator = std::find_if(i_slope.begin(),
i_slope.end(),
- compare);
+ is_match(iv_gen_key));
- //Should have matched with the all default ATTR at least
+ //Should have matched with the default ATTR value at least
//The last value should always be the default value
FAPI_ASSERT(l_value_iterator != i_slope.end(),
fapi2::MSS_NO_POWER_THERMAL_ATTR_FOUND()
.set_GENERATED_KEY(iv_gen_key)
.set_DIMM_TARGET(iv_kind.iv_target),
- "Couldn't find %s value for generated key:%016lx, for target %s. "
+ "Couldn't find %s value for generated key:%08lx, for target %s. "
"DIMM values for generated key are "
"size is %d, gen is %d, type is %d, width is %d, density %d, stack %d, mfgid %d, dimms %d",
"ATTR_MSS_MRW_POWER_CURVE_SLOPE",
@@ -159,8 +174,8 @@ fapi2::ReturnCode decoder::find_slope (const std::vector<fapi2::buffer<uint64_t>
iv_kind.iv_mfgid,
iv_dimms_per_port);
- (*l_value_iterator).extractToRight<VDDR_START, VDDR_LENGTH>( iv_vddr_slope);
- (*l_value_iterator).extractToRight<TOTAL_START, TOTAL_LENGTH>(iv_total_slope);
+ l_value_iterator->extractToRight<VDDR_START, VDDR_LENGTH>( iv_vddr_slope);
+ l_value_iterator->extractToRight<TOTAL_START, TOTAL_LENGTH>(iv_total_slope);
fapi_try_exit:
return fapi2::current_err;
@@ -174,18 +189,10 @@ fapi_try_exit:
///
fapi2::ReturnCode decoder::find_intercept (const std::vector<fapi2::buffer<uint64_t>>& i_intercept)
{
- // Comparator lambda expression
- const auto compare = [this](const fapi2::buffer<uint64_t>& i_hash)
- {
- uint32_t l_temp = 0;
- i_hash.extractToRight<ENCODING_START, ENCODING_LENGTH>(l_temp);
- return ((l_temp & iv_gen_key) == iv_gen_key);
- };
-
// Find iterator to matching key (if it exists)
const auto l_value_iterator = std::find_if(i_intercept.begin(),
i_intercept.end(),
- compare);
+ is_match(iv_gen_key));
//Should have matched with the all default ATTR at least
//The last value should always be the default value
@@ -193,7 +200,7 @@ fapi2::ReturnCode decoder::find_intercept (const std::vector<fapi2::buffer<uint6
fapi2::MSS_NO_POWER_THERMAL_ATTR_FOUND()
.set_GENERATED_KEY(iv_gen_key)
.set_DIMM_TARGET(iv_kind.iv_target),
- "Couldn't find %s value for generated key:%016lx, for target %s. "
+ "Couldn't find %s value for generated key:%08lx, for target %s. "
"DIMM values for generated key are "
"size is %d, gen is %d, type is %d, width is %d, density %d, stack %d, mfgid %d, dimms %d",
"ATTR_MSS_MRW_POWER_CURVE_INTERCEPT",
@@ -208,8 +215,8 @@ fapi2::ReturnCode decoder::find_intercept (const std::vector<fapi2::buffer<uint6
iv_kind.iv_mfgid,
iv_dimms_per_port);
- (*l_value_iterator).extractToRight<VDDR_START, VDDR_LENGTH>( iv_vddr_intercept);
- (*l_value_iterator).extractToRight<TOTAL_START, TOTAL_LENGTH>(iv_total_intercept);
+ l_value_iterator->extractToRight<VDDR_START, VDDR_LENGTH>( iv_vddr_intercept);
+ l_value_iterator->extractToRight<TOTAL_START, TOTAL_LENGTH>(iv_total_intercept);
fapi_try_exit:
return fapi2::current_err;
@@ -223,18 +230,10 @@ fapi_try_exit:
///
fapi2::ReturnCode decoder::find_thermal_power_limit (const std::vector<fapi2::buffer<uint64_t>>& i_thermal_limits)
{
- // Comparator lambda expression
- const auto compare = [this](const fapi2::buffer<uint64_t>& i_hash)
- {
- uint32_t l_temp = 0;
- i_hash.extractToRight<ENCODING_START, ENCODING_LENGTH>(l_temp);
- return ((l_temp & iv_gen_key) == iv_gen_key);
- };
-
// Find iterator to matching key (if it exists)
const auto l_value_iterator = std::find_if(i_thermal_limits.begin(),
i_thermal_limits.end(),
- compare);
+ is_match(iv_gen_key));
//Should have matched with the all default ATTR at least
//The last value should always be the default value
@@ -242,7 +241,7 @@ fapi2::ReturnCode decoder::find_thermal_power_limit (const std::vector<fapi2::bu
fapi2::MSS_NO_POWER_THERMAL_ATTR_FOUND()
.set_GENERATED_KEY(iv_gen_key)
.set_DIMM_TARGET(iv_kind.iv_target),
- "Couldn't find %s value for generated key:%016lx, for target %s. "
+ "Couldn't find %s value for generated key:%8lx, for target %s. "
"DIMM values for generated key are "
"size is %d, gen is %d, type is %d, width is %d, density %d, stack %d, mfgid %d, dimms %d",
"ATTR_MSS_MRW_THERMAL_POWER_LIMIT",
@@ -257,7 +256,7 @@ fapi2::ReturnCode decoder::find_thermal_power_limit (const std::vector<fapi2::bu
iv_kind.iv_mfgid,
iv_dimms_per_port);
- (*l_value_iterator).extractToRight<THERMAL_POWER_START, THERMAL_POWER_LENGTH>( iv_thermal_power_limit);
+ l_value_iterator->extractToRight<THERMAL_POWER_START, THERMAL_POWER_LENGTH>( iv_thermal_power_limit);
fapi_try_exit:
return fapi2::current_err;
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/decoder.H b/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/decoder.H
index d7ca5bf71..aa339fd93 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/decoder.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/decoder.H
@@ -41,17 +41,17 @@
#include <lib/utils/count_dimm.H>
namespace mss
{
+
+namespace power_thermal
+{
+
enum size_of_attrs : size_t
{
SIZE_OF_POWER_CURVES_ATTRS = 100,
SIZE_OF_THERMAL_ATTR = 10,
};
-
-namespace power_thermal
-{
//Currently needs to be in sorted order for lookup to work
-
static const std::vector< std::pair<uint32_t , uint8_t> > DIMM_SIZE_MAP =
{
{4, 0b0000},
@@ -162,8 +162,8 @@ enum ATTR_DECODE_INFO
///
class decoder
{
- private:
public:
+
//IVs for all of the attributes per MCS
const mss::dimm::kind iv_kind;
@@ -252,7 +252,6 @@ fapi2::ReturnCode get_power_attrs (const fapi2::Target<fapi2::TARGET_TYPE_MCS>&
uint16_t o_total_slope [PORTS_PER_MCS][MAX_DIMM_PER_PORT],
uint16_t o_total_int [PORTS_PER_MCS][MAX_DIMM_PER_PORT],
uint32_t o_thermal_power [PORTS_PER_MCS][MAX_DIMM_PER_PORT]);
-
///
/// @brief Encode the attribute into a bit encoding
/// @tparam[in] S *ATTR*_SIZE enum used for fapi2::buffer position
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/throttle.C b/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/throttle.C
index f468ec708..031c846b1 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/throttle.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/throttle.C
@@ -23,15 +23,16 @@
/* */
/* IBM_PROLOG_END_TAG */
///
-/// @file eff_config.C
-/// @brief Determine effective config for mss settings
+/// @file throttle.C
+/// @brief Determine throttle settings for memory
///
// *HWP HWP Owner: Jacob Harvey <jlharvey@us.ibm.com>
// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB
-
+//std lib
+#include<algorithm>
// fapi2
#include <fapi2.H>
@@ -48,8 +49,6 @@ namespace mss
{
namespace power_thermal
{
-
-
///
/// @brief Constructor
/// @param[in] i_target MCS target to call power thermal stuff on
@@ -63,23 +62,20 @@ throttle::throttle( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_mca, fapi2::R
iv_n_slot(0),
iv_n_port(0),
iv_port_power_limit(0),
- iv_port_maxpower(0),
iv_calc_port_maxpower(0)
{
+ //holder for watt_target to add up for port
uint32_t l_dimm_power_limits [MAX_DIMM_PER_PORT] = {};
-
- FAPI_TRY( mem_throttled_n_commands_per_slot( iv_target, iv_n_slot) );
- FAPI_TRY( mem_throttled_n_commands_per_port( iv_target, iv_n_port) );
- FAPI_TRY( port_maxpower ( iv_target, iv_port_maxpower) );
FAPI_TRY( mrw_max_dram_databus_util(iv_databus_port_max) );
- FAPI_TRY( mrw_dimm_power_curve_percent_uplift( iv_power_uplift) );
- FAPI_TRY( mrw_dimm_power_curve_percent_uplift_idle( iv_power_uplift_idle) );
- //FAPI_TRY( mrw_thermal_memory_power_limit( iv_dimm_thermal_limit) );
-
+ FAPI_TRY( mrw_dimm_power_curve_percent_uplift(iv_power_uplift) );
+ FAPI_TRY( mrw_dimm_power_curve_percent_uplift_idle(iv_power_uplift_idle) );
+ FAPI_TRY( dimm_thermal_limit( iv_target, iv_dimm_thermal_limit) );
+ FAPI_TRY( total_pwr_intercept( iv_target, iv_pwr_int));
+ FAPI_TRY( total_pwr_slope( iv_target, iv_pwr_slope));
FAPI_TRY( runtime_mem_throttled_n_commands_per_slot(iv_target, iv_runtime_n_slot ) );
FAPI_TRY( runtime_mem_throttled_n_commands_per_port(iv_target, iv_runtime_n_port ) );
- FAPI_TRY( mem_watt_target( iv_target, &(l_dimm_power_limits[0])) );
+ FAPI_TRY( mem_watt_target( iv_target, l_dimm_power_limits) );
FAPI_TRY( mrw_mem_m_dram_clocks(iv_m_clocks) );
//Port power limit = sum of dimm power limits
@@ -88,15 +84,35 @@ throttle::throttle( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_mca, fapi2::R
iv_port_power_limit += l_dimm_power_limits[mss::index(l_dimm)];
}
+ FAPI_INF("Setting up throttle for target %s, Values are: max databus is %d, uplifts are %d %d, runtime throttles are %d %d",
+ mss::c_str(iv_target),
+ iv_databus_port_max,
+ iv_power_uplift,
+ iv_power_uplift_idle,
+ iv_runtime_n_slot,
+ iv_runtime_n_port);
+
+ FAPI_INF("The dimm power limit is %d, port power limit is %d, dram clocks are %d, dimm power curve slopes are %d %d,",
+ l_dimm_power_limits[0],
+ iv_port_power_limit,
+ iv_m_clocks,
+ iv_pwr_slope[0],
+ iv_pwr_slope[1]);
+
+ FAPI_INF("DIMM power curve intercepts are %d %d, DIMM power thermal limits are %d %d",
+ iv_pwr_int[0],
+ iv_pwr_int[1],
+ iv_dimm_thermal_limit[0],
+ iv_dimm_thermal_limit[1]);
+
+ o_rc = fapi2::FAPI2_RC_SUCCESS;
FAPI_ASSERT ( (iv_databus_port_max != 0),
fapi2::MSS_NO_DATABUS_UTILIZATION()
.set_PORT_DATABUS_UTIL(iv_databus_port_max)
.set_MCA_TARGET(iv_target),
"Failed to get max databus utilization for target %s",
mss::c_str(iv_target));
- o_rc = fapi2::FAPI2_RC_SUCCESS;
return;
-
fapi_try_exit:
o_rc = fapi2::current_err;
FAPI_ERR("Error getting attributes for mss::power_thermal::throttle ctor");
@@ -113,6 +129,54 @@ fapi_try_exit:
///
fapi2::ReturnCode throttle::power_regulator_throttles ()
{
+ double l_port_power_calc_idle = 0;
+ double l_port_power_calc_max = 0;
+ uint32_t l_port_power_slope = 0;
+ uint32_t l_port_power_int = 0;
+ double l_calc_util_port = 0;
+ double l_databus_dimm_max[MAX_DIMM_PER_PORT] = {};
+ double l_calc_databus_port_idle[MAX_DIMM_PER_PORT] = {IDLE_UTIL, IDLE_UTIL};
+
+ FAPI_INF("Starting power regulator throttles");
+
+ //Decide utilization for each dimm based off of dimm count and power slopes
+ FAPI_TRY( calc_databus(iv_databus_port_max, l_databus_dimm_max));
+
+ //Use the dimm utilizations and dimm power slopes to calculate port min and max power
+ calc_port_power(l_calc_databus_port_idle,
+ l_databus_dimm_max,
+ l_port_power_calc_idle,
+ l_port_power_calc_max);
+ FAPI_INF("POWER calculated port power is %f", l_port_power_calc_max);
+
+ //Calculate the power curve slope and intercept using the port's min and max power values
+ FAPI_TRY(calc_power_curve(l_port_power_calc_idle,
+ l_port_power_calc_max,
+ l_port_power_slope,
+ l_port_power_int));
+
+ FAPI_INF("POWER Port power limit is %d", iv_port_power_limit);
+ //Calculate the port's utilization to get under watt target using the port's calculated slopes
+ calc_util_usage(l_port_power_slope,
+ l_port_power_int,
+ iv_port_power_limit,
+ l_calc_util_port);
+
+ FAPI_INF("POWER calc util port is %f", l_calc_util_port);
+
+ //Calculate the N throttles
+ iv_n_port = power_thermal::throttled_cmds(l_calc_util_port, iv_m_clocks);
+
+ //Set iv_n_slot to the lower value between the slot runtime and iv_n_port
+ iv_n_slot = (iv_runtime_n_slot != 0) ? std::min (iv_n_port, iv_runtime_n_slot) : iv_n_port;
+
+ //Choose the lowest value of the runtime and the calculated
+ iv_n_port = (iv_runtime_n_port != 0) ? std::min (iv_n_port, iv_runtime_n_port) : iv_n_port;
+
+ //Use the throttle value to calculate the power that gets to exactly that value
+ iv_calc_port_maxpower = calc_power_from_n(iv_n_port);
+
+fapi_try_exit:
return fapi2::current_err;
}
@@ -125,12 +189,70 @@ fapi2::ReturnCode throttle::power_regulator_throttles ()
///
fapi2::ReturnCode throttle::thermal_throttles ()
{
+ double l_dimm_power_idle [MAX_DIMM_PER_PORT] = {};
+ double l_dimm_power_max [MAX_DIMM_PER_PORT] = {};
+ uint32_t l_dimm_power_slope [MAX_DIMM_PER_PORT] = {};
+ uint32_t l_dimm_power_int [MAX_DIMM_PER_PORT] = {};
+ double l_calc_util [MAX_DIMM_PER_PORT] = {};
+ uint16_t l_n_slots [MAX_DIMM_PER_PORT] = {};
+ const auto l_count = count_dimm (iv_target);
+
+ //Calculate the dimm power range for each dimm at max utilization for each
+ calc_dimm_power(power_thermal::IDLE_UTIL,
+ iv_databus_port_max,
+ l_dimm_power_idle,
+ l_dimm_power_max);
+
+ //Let's calculate the N throttle for each DIMM
+ for ( const auto& l_dimm : find_targets<TARGET_TYPE_DIMM>(iv_target) )
+ {
+ uint8_t l_pos = mss::index(l_dimm);
+ //Calculate the power curve taking the thermal limit into account
+ FAPI_TRY( calc_power_curve(l_dimm_power_idle[l_pos],
+ l_dimm_power_max[l_pos],
+ l_dimm_power_slope[l_pos],
+ l_dimm_power_int[l_pos]));
+
+ //Calculate the databus utilization at the calculated power curve
+ calc_util_usage(l_dimm_power_slope[l_pos],
+ l_dimm_power_int[l_pos],
+ iv_dimm_thermal_limit[l_pos],
+ l_calc_util[l_pos]);
+
+ FAPI_INF("THERMAL Dimm at pos %d's util is %f", l_pos, l_calc_util[l_pos]);
+
+ l_n_slots[l_pos] = power_thermal::throttled_cmds (l_calc_util[l_pos], iv_m_clocks);
+
+ //Set to the min between the two value
+ //If iv_n_slot == 0 (so uninitialized), set it to the calculated slot value
+ //The l_n_slot value can't be equal to 0 because there's a dimm installed
+ if ((l_n_slots[l_pos] < iv_n_slot) || (iv_n_slot == 0))
+ {
+ iv_n_slot = l_n_slots[l_pos];
+ }
+ }
+
+ //Set to lowest value between calculated and runtime
+ FAPI_INF("THERMAL runtime slot is %d, calc n slot is %d", iv_runtime_n_slot, iv_n_slot);
+ //Taking the min of the SLOT * (# of dimms on the port) and that maximum allowed port throttle (iv_runtime_port)
+ //So it's the min of either to actually utilized to the maximum allowed utilization
+ iv_n_port = std::min(iv_runtime_n_port, uint16_t(iv_n_slot * l_count));
+
+ iv_n_slot = std::min(iv_n_slot, iv_runtime_n_slot);
+
+ //Now time to get and set iv_calc_port_max from the calculated N throttle
+ iv_calc_port_maxpower = calc_power_from_n(iv_n_port);
return fapi2::FAPI2_RC_SUCCESS;
+fapi_try_exit:
+ FAPI_ERR("Error calculating mss::power_thermal::thermal_throttles()");
+ return fapi2::current_err;
}
+
+
///
-/// @brief Calculates the min and max power usage for a port based off of power curves and utilizati
+/// @brief Calculates the min and max power usage for a port based off of power curves and utilizations
/// @param[in] i_idle_util the utilization of the databus in idle mode
/// @param[in] i_max_util the utilization of the port at maximum possible (mrw or calculated)
/// @param[out] o_port_power_idle max value of port power in cW
@@ -138,108 +260,147 @@ fapi2::ReturnCode throttle::thermal_throttles ()
/// @note Called twice in p9_mss_bulk_pwr_throttles
/// @note uses dimm power curves from class variables
///
-void throttle::calc_port_power( const double i_idle_util [MAX_DIMM_PER_PORT],
- const double i_max_util [MAX_DIMM_PER_PORT],
- double& o_port_power_idle,
- double& o_port_power_max)
+void throttle::calc_port_power(const double i_idle_util [MAX_DIMM_PER_PORT],
+ const double i_max_util [MAX_DIMM_PER_PORT],
+ double& o_port_power_idle,
+ double& o_port_power_max)
{
//Playing it safe
o_port_power_idle = 0;
o_port_power_max = 0;
+ FAPI_INF("max util is %f, %f", i_max_util[0], i_max_util[1]);
//Calculate the port power curve info by summing the dimms on the port
for ( const auto& l_dimm : mss::find_targets<TARGET_TYPE_DIMM>(iv_target) )
{
uint32_t l_pos = mss::index(l_dimm);
//Sum up the dim's power to calculate the port power curve
- o_port_power_idle +=
- ( i_idle_util[l_pos] / UTIL_CONVERSION * iv_pwr_slope[l_pos]) + iv_pwr_int[l_pos];
-
- o_port_power_max +=
- ( i_max_util[l_pos] / UTIL_CONVERSION * iv_pwr_slope[l_pos]) + iv_pwr_int[l_pos];
+ o_port_power_idle += calc_power(i_idle_util[l_pos], l_pos);
+ o_port_power_max += calc_power(i_max_util[l_pos], l_pos);
}
//Raise the powers by the uplift percent
- o_port_power_idle *= (1 + (double(iv_power_uplift_idle) / PERCENT_CONVERSION));
- o_port_power_max *= (1 + (double(iv_power_uplift) / PERCENT_CONVERSION));
+ calc_power_uplift(iv_power_uplift_idle, o_port_power_idle);
+ calc_power_uplift(iv_power_uplift, o_port_power_max);
}
///
-/// @brief Calculate the port power curve in order to calculate the port utilization
-/// @paramp[in] i_port_power_calc_idle double of the port's power consumption at idle
-/// @paramp[in] i_port_power_calc_max double of the port's power consumption at max utilization
-/// @paramp[out] o_port_power_slope
-/// @paramp[out] o_port_power_int
+/// @brief Calculates max and min power usages based off of DIMM power curves
+/// @param[in] i_databus_idle idle databus utilization (either calculated or mrw)
+/// @param[in] i_databus_max max databus utilization (either calculated or mrw)
+/// @param[out] o_dimm_power_idle array of dimm power in cW
+/// @param[out] o_dimm_power_max array of dimm power in cW
+/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff the split is OK
/// @note Called in p9_mss_bulk_pwr_throttles
-/// @note Port power curve needed to calculate the port utilization
+/// @note used for the thermal throttles
///
-fapi2::ReturnCode throttle::calc_port_power_curve (const double& i_port_power_calc_idle,
- const double& i_port_power_calc_max,
- uint32_t& o_port_power_slope,
- uint32_t& o_port_power_int)
+void throttle::calc_dimm_power(const double i_databus_idle,
+ const double i_databus_max,
+ double o_dimm_power_idle [MAX_DIMM_PER_PORT],
+ double o_dimm_power_max [MAX_DIMM_PER_PORT])
{
- double l_denominator = ((double(iv_databus_port_max) / UTIL_CONVERSION) - IDLE_UTIL);
+ for ( const auto& l_dimm : mss::find_targets<TARGET_TYPE_DIMM>(iv_target) )
+ {
+ const uint8_t l_pos = mss::index(l_dimm);
+ o_dimm_power_idle[l_pos] = calc_power(i_databus_idle, l_pos);
+ o_dimm_power_max[l_pos] = calc_power(i_databus_max, l_pos);
- FAPI_ASSERT(l_denominator != 0,
- fapi2::MSS_CALC_PORT_POWER_CURVE_DIVIDE_BY_ZERO().
- set_PORT_DATABUS_UTIL(iv_databus_port_max).
- set_UTIL_CONVERSION(UTIL_CONVERSION).
- set_IDLE_UTIL(IDLE_UTIL),
- "Denominator = (databus(%d) / UTIL_CONVERSION (%d)) - IDLE_UTIL(%d)",
- iv_databus_port_max,
- UTIL_CONVERSION,
- IDLE_UTIL);
+ //Raise the powers by the uplift percent
- o_port_power_slope = (i_port_power_calc_max - i_port_power_calc_idle) / l_denominator;
- o_port_power_int = i_port_power_calc_idle - (o_port_power_slope * IDLE_UTIL);
+ calc_power_uplift(iv_power_uplift_idle, o_dimm_power_idle[l_pos]);
+ calc_power_uplift(iv_power_uplift, o_dimm_power_max[l_pos]);
+ FAPI_INF("Calc_dimm_power: dimm (%d) power max is %f, %f for dimm slope of %d, intercept of %d",
+ l_pos,
+ o_dimm_power_max[l_pos],
+ o_dimm_power_max[l_pos],
+ iv_pwr_slope[l_pos],
+ iv_pwr_int[l_pos]);
+ }
+}
+
+///
+/// @brief Calculate the port power curve in order to calculate the port utilization
+/// @param[in] i_power_idle double of the port's power consumption at idle
+/// @param[in] i_power_max double of the port's power consumption at max utilization
+/// @param[out] o_slope
+/// @param[out] o_int
+/// @note Called in p9_mss_bulk_pwr_throttles
+/// @note Port power curve needed to calculate the port utilization
+///
+fapi2::ReturnCode throttle::calc_power_curve(const double i_power_idle,
+ const double i_power_max,
+ uint32_t& o_slope,
+ uint32_t& o_int)
+{
+ double l_divisor = ((double(iv_databus_port_max) / UTIL_CONVERSION) - IDLE_UTIL);
+ FAPI_ASSERT ((l_divisor != 0),
+ fapi2::MSS_CALC_POWER_CURVE_DIVIDE_BY_ZERO()
+ .set_PORT_DATABUS_UTIL(iv_databus_port_max)
+ .set_UTIL_CONVERSION(UTIL_CONVERSION)
+ .set_IDLE_UTIL(IDLE_UTIL),
+ "Calculated zero for the divisor in calc_power_curve on target %s, the equation is %s",
+ mss::c_str(iv_target),
+ "(double(iv_databus_port_max) / UTIL_CONVERSION) - IDLE_UTIL");
+
+ o_slope = (i_power_max - i_power_idle) / l_divisor;
+ o_int = i_power_idle - (o_slope * IDLE_UTIL);
+ FAPI_INF("Calc_power_curve: power idle is %f, max is %f, slope is %d, int is %d",
+ i_power_idle,
+ i_power_max,
+ o_slope,
+ o_int);
return fapi2::FAPI2_RC_SUCCESS;
fapi_try_exit:
+ FAPI_INF("Error calculating mss::power_thermal::calc_power_curve");
return fapi2::current_err;
+
}
///
-/// @brief Calculate the port's databus utilization given the port's power curve
-/// @paramp[in] i_port_power_slope
-/// @paramp[in] i_port_power_int
-/// @paramp[out] o_port_util the port's databus utilization
+/// @brief Calculate the databus utilization given the power curve
+/// @param[in] i_slope
+/// @param[in] i_int
+/// @param[in] i_power_limit either the port_power_limit or the dimm thermal power limit
+/// @param[out] o_port_util the port's databus utilization
/// @note Called in p9_mss_bulk_pwr_throttles
/// @note Chooses worst case between the maximum allowed databus utilization and the calculated value
-/// @notes makes sure that the utilization isn't 0
///
-void throttle::calc_port_util_usage (const uint32_t& i_port_power_slope,
- const uint32_t& i_port_power_int,
- double& o_port_util)
+void throttle::calc_util_usage(const uint32_t i_slope,
+ const uint32_t i_int,
+ const uint32_t i_power_limit,
+ double& o_util)
{
- o_port_util = (double(iv_port_power_limit) - i_port_power_int) / i_port_power_slope * UTIL_CONVERSION;
- o_port_util = (uint32_t(o_port_util) < iv_databus_port_max) ? o_port_util : iv_databus_port_max;
- o_port_util = (o_port_util == 0) ? 1 : o_port_util;
+ o_util = (double(i_power_limit) - i_int) / i_slope * UTIL_CONVERSION;
+ o_util = (uint32_t(o_util) < iv_databus_port_max) ? o_util : iv_databus_port_max;
+ o_util = (o_util == 0) ? MIN_UTIL : o_util;
}
///
-/// @brief Calculates the power max and idle for each dimm using power curves and databus utilization
-/// @param[out] o_dimm_power_idle double type for precision, the DIMM power limit in idle state (0 utilization)
-/// @param[out] o_dimm_power_max double type for precision, the DIMM power limit at max utilization
-/// @note Called in p9_mss_bulk_pwr_throttle for thermal_throttles, eff_config_thermal
-/// @note power values are as if dimm is alone on port, using port_databus_util_max
+///@brief calculated the output power estimate from the calculated N throttle
+///@param[in] i_n_throttle is the throtte N (address operations) that the power (cW) should be calculated fro
+///@return the power calculated from the uint
///
-void throttle::calc_dimm_power( double o_dimm_power_idle [MAX_DIMM_PER_PORT],
- double o_dimm_power_max [MAX_DIMM_PER_PORT])
+uint32_t throttle::calc_power_from_n (const uint16_t i_n_throttle)
{
- for ( const auto& l_dimm : mss::find_targets<TARGET_TYPE_DIMM>(iv_target) )
- {
- const auto l_pos = mss::index(l_dimm);
+ double l_calc_util;
+ double l_calc_databus_port_max[MAX_DIMM_PER_PORT] = {};
+ double l_calc_databus_port_idle[MAX_DIMM_PER_PORT] = {};
+ double l_port_power_max = 0;
+ double l_port_power_idle = 0;
- o_dimm_power_idle[l_pos] = iv_pwr_int[l_pos];
- o_dimm_power_max[l_pos] = (double(iv_databus_port_max) / UTIL_CONVERSION) * iv_pwr_slope[l_pos] +
- iv_pwr_int[l_pos];
+ l_calc_util = calc_util_from_throttles(i_n_throttle, iv_m_clocks);
+ //Now do everything as port stuff
+ calc_databus(l_calc_util, l_calc_databus_port_max);
- //Raise the powers by the uplift percent
- o_dimm_power_idle[l_pos] *= (1 + (iv_power_uplift_idle / PERCENT_CONVERSION));
- o_dimm_power_max[l_pos] *= (1 + (iv_power_uplift / PERCENT_CONVERSION));
- }
+ calc_port_power(l_calc_databus_port_idle,
+ l_calc_databus_port_max,
+ l_port_power_idle,
+ l_port_power_max);
+
+ return uint32_t(power_thermal::round_up (l_port_power_max));
}
///
@@ -250,7 +411,7 @@ void throttle::calc_dimm_power( double o_dimm_power_idle [MAX_DIMM_PER_PORT],
/// @note Called in p9_mss_bulk_pwr_throttles
/// @used to calculate the port power based off of DIMM power curves
///
-fapi2::ReturnCode throttle::calc_databus( const double& i_databus_port_max,
+fapi2::ReturnCode throttle::calc_databus( const double i_databus_port_max,
double o_databus_dimm_max [MAX_DIMM_PER_PORT])
{
uint8_t l_count_dimms = count_dimm (iv_target);
@@ -267,22 +428,21 @@ fapi2::ReturnCode throttle::calc_databus( const double& i_databus_port_max,
o_databus_dimm_max[mss::index(l_dimm)] = i_databus_port_max / l_count_dimms;
}
- //If not equal power slopes, set the dimm with the highest power slope
- //Should be correct even if only one DIMM installed
+ //If the power slopes aren't equal, set the dimm with the highest power slope
+ //Should be correct even if only one DIMM is installed
if (iv_pwr_slope[0] != iv_pwr_slope[1])
{
o_databus_dimm_max[0] = (iv_pwr_slope[0] > iv_pwr_slope[1]) ? i_databus_port_max : 0;
o_databus_dimm_max[1] = (iv_pwr_slope[1] > iv_pwr_slope[0]) ? i_databus_port_max : 0;
}
- //make sure both aren't equal to 0
+ //make sure both are not 0
FAPI_ASSERT ( (o_databus_dimm_max[0] != 0) || (o_databus_dimm_max[1] != 0),
fapi2::MSS_NO_DATABUS_UTILIZATION()
- .set_PORT_DATABUS_UTIL(iv_databus_port_max)
+ .set_PORT_DATABUS_UTIL(i_databus_port_max)
.set_MCA_TARGET(iv_target),
"Failed to calculated databus utilization for target %s",
mss::c_str(iv_target));
-
fapi_try_exit:
return fapi2::current_err;
}
@@ -291,28 +451,71 @@ fapi_try_exit:
/// @brief Perform thermal calculations as part of the effective configuration
/// @param[in] i_target the MCS target in which the runtime throttles will be reset
/// @return FAPI2_RC_SUCCESS iff ok
-/// TK implement/ will be overun?
///
fapi2::ReturnCode restore_runtime_throttles( const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target )
{
- uint32_t l_run_throttles [PORTS_PER_MCS] = {};
+ uint16_t l_run_throttles [MAX_DIMM_PER_PORT] = {};
uint32_t l_max_databus = 0;
- uint32_t l_throttle_m_clocks [PORTS_PER_MCS] = {};
+ uint32_t l_throttle_m_clocks = {};
- FAPI_TRY( runtime_mem_m_dram_clocks(i_target, l_throttle_m_clocks) );
+ FAPI_TRY( mrw_mem_m_dram_clocks(l_throttle_m_clocks) );
FAPI_TRY( mrw_max_dram_databus_util(l_max_databus) );
- for (const auto& l_mca : find_targets<TARGET_TYPE_MCA> (i_target))
+ //set runtime throttles to unthrottled value, using max dram utilization and M throttle
+ //Do I need to check to see if any DIMMS configured on the port?
+ for (const auto& l_mca : find_targets<TARGET_TYPE_MCA>(i_target))
{
- const uint8_t l_pos = mss::index(l_mca);
- l_run_throttles[l_pos] = mss::power_thermal::throttled_cmds(l_max_databus, l_throttle_m_clocks[0]);
+ const auto l_pos = mss::index(l_mca);
+
+ if (mss::count_dimm (l_mca) != 0)
+ {
+ l_run_throttles[l_pos] = mss::power_thermal::throttled_cmds (l_max_databus, l_throttle_m_clocks);
+ }
}
FAPI_TRY( FAPI_ATTR_SET( fapi2::ATTR_MSS_RUNTIME_MEM_THROTTLED_N_COMMANDS_PER_PORT, i_target, l_run_throttles) );
+ FAPI_TRY( FAPI_ATTR_SET( fapi2::ATTR_MSS_RUNTIME_MEM_THROTTLED_N_COMMANDS_PER_SLOT, i_target, l_run_throttles) );
fapi_try_exit:
return fapi2::current_err;
}
-}//namespace power_thermal
+///
+/// @brief Update the runtime throttles to the worst case of the general throttle values and the runtime values
+/// @param[in] i_target the MCS target in which the runtime throttles will be set
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode update_runtime_throttles( const std::vector< fapi2::Target<fapi2::TARGET_TYPE_MCS> >& i_targets )
+{
+ for (const auto& l_mcs : i_targets)
+ {
+ uint16_t l_run_slot [PORTS_PER_MCS] = {};
+ uint16_t l_run_port [PORTS_PER_MCS] = {};
+ uint16_t l_calc_slot [PORTS_PER_MCS] = {};
+ uint16_t l_calc_port [PORTS_PER_MCS] = {};
+
+ FAPI_TRY(runtime_mem_throttled_n_commands_per_slot(l_mcs, l_run_slot));
+ FAPI_TRY(runtime_mem_throttled_n_commands_per_port(l_mcs, l_run_port));
+ FAPI_TRY(mem_throttled_n_commands_per_slot(l_mcs, l_calc_slot));
+ FAPI_TRY(mem_throttled_n_commands_per_port(l_mcs, l_calc_port));
+
+ for (const auto& l_mca : find_targets<TARGET_TYPE_MCA>(l_mcs))
+ {
+ const auto l_pos = mss::index(l_mca);
+ //Choose the worst case between runtime and calculated throttles
+ //Have to make sure the calc_slot isn't equal to 0 though
+ l_run_slot[l_pos] = (l_calc_slot[l_pos] != 0) ? std::min(l_run_slot[l_pos], l_calc_slot[l_pos]) : l_run_slot[l_pos];
+ l_run_port[l_pos] = (l_calc_port[l_pos] != 0) ? std::min(l_run_port[l_pos], l_calc_port[l_pos]) : l_run_port[l_pos];
+ FAPI_INF("New runtime throttles dimm %d for slot are %d, port are %d", l_pos, l_run_slot[l_pos], l_run_port[l_pos]);
+ }
+
+ FAPI_TRY( FAPI_ATTR_SET( fapi2::ATTR_MSS_RUNTIME_MEM_THROTTLED_N_COMMANDS_PER_PORT, l_mcs, l_run_port) );
+ FAPI_TRY( FAPI_ATTR_SET( fapi2::ATTR_MSS_RUNTIME_MEM_THROTTLED_N_COMMANDS_PER_SLOT, l_mcs, l_run_slot) );
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+}//namespace power_thermal
}//namespace mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/throttle.H b/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/throttle.H
index 3259608ce..876e277a3 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/throttle.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/power_thermal/throttle.H
@@ -46,9 +46,12 @@ enum throttle_const : size_t
{
// Dram data bus utilization is bus utilization / 4
DRAM_BUS_UTILS = 4,
+ //10000 to convert to and from c%
UTIL_CONVERSION = 10000,
PERCENT_CONVERSION = 100,
- MIN_UTIL = 1,
+
+ //MIN_UTIL and IDLE_UTIL are in c%
+ MIN_UTIL = 100,
IDLE_UTIL = 0,
};
///
@@ -58,25 +61,47 @@ enum throttle_const : size_t
class throttle
{
private:
+ ///
+ /// @brief Calculate the power (cW) of inputs and the power curve
+ /// @tparam T
+ /// @param[in] i_util the databus utilization that the power will be based on
+ /// @param[in] l_pos the dimm position for the power value being calculated.
+ /// @return Integral type T
+ ///
+ template<typename T>
+ inline T calc_power (const T i_util, const size_t i_pos)
+ {
+ return ((i_util / UTIL_CONVERSION) * iv_pwr_slope[i_pos]) + iv_pwr_int[i_pos];
+ }
+
+ ///
+ /// @brief Raise the o_value by the percent passed in
+ /// @param[in] i_uplift the percent the o_Value should be raised by
+ /// @param[out] o_value the value that will be modified
+ ///
+ inline void calc_power_uplift (const uint8_t i_uplift, double& o_value)
+ {
+ o_value *= (1 + (double(i_uplift) / PERCENT_CONVERSION));
+ }
public:
const fapi2::Target<fapi2::TARGET_TYPE_MCA>& iv_target;
//dimm level
uint32_t iv_databus_port_max;
+ //TK change thermal limit as well as power curves
uint8_t iv_power_uplift_idle;
uint8_t iv_power_uplift;
- uint32_t iv_runtime_n_slot;
- uint32_t iv_runtime_n_port;
+ uint16_t iv_runtime_n_slot;
+ uint16_t iv_runtime_n_port;
uint32_t iv_m_clocks;
uint32_t iv_dimm_thermal_limit[MAX_DIMM_PER_PORT] = {};
uint16_t iv_pwr_slope[MAX_DIMM_PER_PORT] = {};
uint16_t iv_pwr_int[MAX_DIMM_PER_PORT] = {};
- uint32_t iv_n_slot;
- uint32_t iv_n_port;
+ uint16_t iv_n_slot;
+ uint16_t iv_n_port;
uint32_t iv_port_power_limit;
- uint32_t iv_port_maxpower;
uint32_t iv_calc_port_maxpower;
//default ctor deleted
@@ -95,71 +120,82 @@ class throttle
~throttle() = default;
///
- /// @brief Calculates the min and max power usage for a port based off of power curves and utilizati
+ /// @brief Calculates the min and max power usage for a port
/// @param[in] i_idle_util the utilization of the databus in idle mode
/// @param[in] i_max_util the utilization of the port at maximum possible (mrw or calculated)
/// @param[out] o_port_power_idle max value of port power in cW
/// @param[out] o_port_power_max max value of port power in cW
/// @note Called twice in p9_mss_bulk_pwr_throttles
- /// @note uses dimm power curves from class variables
- ///
- void calc_port_power(const double i_idle_util [MAX_DIMM_PER_PORT],
- const double i_max_util [MAX_DIMM_PER_PORT],
- double& o_port_power_idle,
- double& o_port_power_max);
- ///
- /// @brief Calculate the port power curve in order to calculate the port utilization
- /// @paramp[in] i_port_power_calc_idle double of the port's power consumption at idle
- /// @paramp[in] i_port_power_calc_max double of the port's power consumption at max utilization
- /// @paramp[out] o_port_power_slope
- /// @paramp[out] o_port_power_int
- /// @return FAPI2_RC_SUCCESS iff success
+ ///
+ void calc_port_power( const double i_idle_util [MAX_DIMM_PER_PORT],
+ const double i_max_util [MAX_DIMM_PER_PORT],
+ double& o_port_power_idle,
+ double& o_port_power_max);
+ ///
+ /// @brief Calculates max and min power usages based off of DIMM power curves
+ /// @param[in] i_databus_port_max max databus utilization for the port (either calculated or mrw)
+ /// @param[in] i_port_power_calc_idle double of the port's power consumption at idle
+ /// @param[out] o_dimm_power_idle array of dimm power in cW
+ /// @param[out] o_dimm_power_max array of dimm power in cW
/// @note Called in p9_mss_bulk_pwr_throttles
- /// @note Port power curve needed to calculate the port utilization
+ /// @note used for the thermal throttles
///
- fapi2::ReturnCode calc_port_power_curve(const double& i_port_power_calc_idle,
- const double& i_port_power_calc_max,
- uint32_t& o_port_power_slope,
- uint32_t& o_port_power_int);
+ void calc_dimm_power(const double i_databus_idle,
+ const double i_databus_max,
+ double o_dimm_power_idle [MAX_DIMM_PER_PORT],
+ double o_dimm_power_max [MAX_DIMM_PER_PORT]);
+
///
- /// @brief Calculate the port's databus utilization given the port's power curve
- /// @paramp[in] i_port_power_slope
- /// @paramp[in] i_port_power_int
- /// @paramp[out] o_port_util the port's databus utilization
+ /// @brief Calculate the power curve in order to calculate databus utilization
+ /// @param[in] i_power_idle double of the port's power consumption at idle
+ /// @param[in] i_power_max double of the port's power consumption at max utilization
+ /// @param[out] o_power_slope
+ /// @param[out] o_power_int
+ /// @note Called in p9_mss_bulk_pwr_throttles
+ /// @note Power curve needed to calculate the utilization
+ ///
+ fapi2::ReturnCode calc_power_curve(const double i_power_idle,
+ const double i_power_max,
+ uint32_t& o_power_slope,
+ uint32_t& o_power_int);
+ ///
+ /// @brief Calculate the databus utilization given the power curve
+ /// @param[in] i_slope
+ /// @param[in] i_int
+ /// @param[in] i_power_limit either iv_port_power_limit or thermal_power_limit depending on throttle type
+ /// @param[out] o_port_util the port's databus utilization
/// @note Called in p9_mss_bulk_pwr_throttles
/// @note Chooses worst case between the maximum allowed databus utilization and the calculated value
- /// @notes makes sure that the utilization isn't 0
///
- void calc_port_util_usage(const uint32_t& i_port_power_slope,
- const uint32_t& i_port_power_int,
- double& o_port_util);
-
+ void calc_util_usage(const uint32_t i_slope,
+ const uint32_t i_int,
+ const uint32_t i_power_limit,
+ double& o_util);
///
- /// @brief Calculates the power max and idle for each dimm using power curves and databus utilization
- /// @param[out] o_dimm_power_idle double type for precision, the DIMM power limit in idle state (0 utilization)
- /// @param[out] o_dimm_power_max double type for precision, the DIMM power limit at max utilization
- /// @note Called in p9_mss_bulk_pwr_throttle for thermal_throttles, eff_config_thermal
- /// @note power values are as if dimm is alone on port, using port_databus_util_max
+ ///@brief calculated the output power estimate from the calculated N throttle
+ ///@param[in] i_n_port is the throtte N (address operations) that the power (cW) is be calculated from
+ ///@return the power calculated from the uint
///
- void calc_dimm_power(double o_dimm_power_idle [MAX_DIMM_PER_PORT],
- double o_dimm_power_max [MAX_DIMM_PER_PORT]);
+ uint32_t calc_power_from_n (const uint16_t i_n_port);
+
///
- /// @brief Converts the port maximum databus to a dimm level based on powerslopes and dimms installed
+ /// @brief Converts the port maximum databus util to a dimm level based on powerslopes and dimms installed
/// @param[in] i_databus_port_max max databus utilization for the port (either calculated or mrw)
/// @param[out] o_databus_dimm_max array of dimm utilization values
/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff the split is OK
/// @note Called in p9_mss_bulk_pwr_throttles
/// @used to calculate the port power based off of DIMM power curves
///
- fapi2::ReturnCode calc_databus(const double& i_databus_port_max,
- double o_databus_dimm_max [MAX_DIMM_PER_PORT]);
+ fapi2::ReturnCode calc_databus( const double i_databus_port_max,
+ double o_databus_dimm_max [MAX_DIMM_PER_PORT]);
///
- /// @brief Set ATTR_MSS_CHANNEL_PAIR_MAXPOWER and ATTR_MSS_MEM_THROTTLED_N_COMMANDS_PER_SLOT,
+ /// @brief Calculate ATTR_MSS_CHANNEL_PAIR_MAXPOWER and ATTR_MSS_MEM_THROTTLED_N_COMMANDS_PER_SLOT,
/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK
/// @note Called in p9_mss_bulk_pwr_throttles
- /// @note determines the throttle levels based off of the port's power curve,
- /// sets the slot throttles to the same
+ /// @note determines the throttle levels based off of the port's power curve, max databus utilization,
+ /// and memwat target.
+ /// @note currently sets the slot and port throttles to the same value
///
fapi2::ReturnCode power_regulator_throttles ();
@@ -179,15 +215,16 @@ class throttle
/// @param[in] i_num_dram_clocks window of M DRAM clocks
/// @return number of throttled commands allowed
/// @note Uses N/M Throttling.
-/// Equation: (DRAM data bus utilization Percent / 10000 ) = ((N * M) / 4 )
-/// Equation: N = (DRAM data bus utilization Percent * M) / (4 * 10000)
+/// Equation: N = (DRAM data bus utilization * M) / (4 * 10000)
+///
inline uint32_t throttled_cmds(const uint32_t i_databus_util, const uint32_t i_num_dram_clocks)
{
constexpr uint64_t l_divisor = DRAM_BUS_UTILS * UTIL_CONVERSION;
const uint64_t l_dividend = i_databus_util * i_num_dram_clocks;
const uint64_t l_result = l_dividend / l_divisor;
- return l_result;
+ //Make sure N is not equal to 0, or we brick the dram until reboot
+ return ((l_result == 0) ? 1 : l_result);
}
///
@@ -196,7 +233,7 @@ inline uint32_t throttled_cmds(const uint32_t i_databus_util, const uint32_t i_n
/// @param[in] i_num_dram_clocks window of M DRAM clocks
/// @return number of throttled commands allowed
/// @note Uses N/M Throttling.
-/// Equation: databus utilization = (N * 4 * 100000) / M
+/// @note DRAM databus utilization = N * 4 * 10000 / M
///
inline double calc_util_from_throttles(const uint16_t i_n_throttles, const uint32_t i_num_dram_clocks)
{
@@ -206,12 +243,37 @@ inline double calc_util_from_throttles(const uint16_t i_n_throttles, const uint3
}
///
+/// @brief Determines if the double has decimal digits and adds 1 and rounds if true
+/// @param[in] io_val the double to be rounded up if trialing digits
+/// @return the input value rounded up to the next whole digit
+/// @note Called in p9_mss_bulk_pwr_throttles
+///
+inline uint32_t round_up(double i_val)
+{
+ //convert to uint to truncate decimals and convert back to double for comparison
+ uint32_t temp = uint32_t (i_val);
+
+ //if not equal, lost something from truncating, so add 1
+ temp += (temp == i_val) ? 0 : 1;
+
+ //Truncate final value
+ return temp;
+}
+
+///
/// @brief Perform thermal calculations as part of the effective configuration
/// @param[in] i_target the MCS target in which the runtime throttles will be reset
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode restore_runtime_throttles( const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target );
+///
+/// @brief Update the runtime throttles to the worst case of the general throttle values and the runtime values
+/// @param[in] i_target the MCS target in which the runtime throttles will be set
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode update_runtime_throttles(const std::vector< fapi2::Target<fapi2::TARGET_TYPE_MCS> >& i_targets);
+
}//power_thermal
}// mss
OpenPOWER on IntegriCloud