summaryrefslogtreecommitdiffstats
path: root/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_eff_config_thermal.C
diff options
context:
space:
mode:
authorLuke Mulkey <lwmulkey@us.ibm.com>2017-02-02 11:38:38 -0600
committerDaniel M. Crowell <dcrowell@us.ibm.com>2017-07-26 00:29:10 -0400
commit7d245fb021ff8a6df7e44482b000ce7cf5c2919c (patch)
tree781d3ee4de98f33f07238bc60495b9e15f098b89 /src/import/chips/centaur/procedures/hwp/memory/p9c_mss_eff_config_thermal.C
parent5afd9a14f2299a8acf43fa462f46dd382aecef1f (diff)
downloadtalos-hostboot-7d245fb021ff8a6df7e44482b000ce7cf5c2919c.tar.gz
talos-hostboot-7d245fb021ff8a6df7e44482b000ce7cf5c2919c.zip
Eff_config, volt, freq for p9c
Change-Id: I2a22441507fdb886acb46f61c0d58f852192f78a Original-Change-Id: I13fe2c0b91c0ae5b1c7ee37445775af566638c40 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/35841 Reviewed-by: STEPHEN GLANCY <sglancy@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Reviewed-by: ANDRE A. MARIN <aamarin@us.ibm.com> Tested-by: PPE CI <ppe-ci+hostboot@us.ibm.com> Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com> Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com> Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/43539 Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/import/chips/centaur/procedures/hwp/memory/p9c_mss_eff_config_thermal.C')
-rw-r--r--src/import/chips/centaur/procedures/hwp/memory/p9c_mss_eff_config_thermal.C658
1 files changed, 658 insertions, 0 deletions
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
new file mode 100644
index 000000000..87489fece
--- /dev/null
+++ b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_eff_config_thermal.C
@@ -0,0 +1,658 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/centaur/procedures/hwp/memory/p9c_mss_eff_config_thermal.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+/// @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 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
+// -- CDIMM will get values from VPD
+// -- The throttle attributes will setup values for IPL and runtime
+//
+//------------------------------------------------------------------------------
+// My Includes
+//------------------------------------------------------------------------------
+#include <p9c_mss_eff_config_thermal.H>
+#include <p9c_mss_bulk_pwr_throttles.H>
+#include <generic/memory/lib/utils/c_str.H>
+#include <dimmConsts.H>
+//------------------------------------------------------------------------------
+// Includes
+//------------------------------------------------------------------------------
+#include <fapi2.H>
+
+// 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;
+
+extern "C" {
+ ///
+ /// @brief mss_eff_config_thermal(): 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
+ /// @return fapi2::ReturnCode
+ ///
+ fapi2::ReturnCode p9c_mss_eff_config_thermal(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba)
+ {
+
+ FAPI_INF("*** Running mss_eff_config_thermal on %s ***",
+ mss::c_str(i_target_mba));
+
+ FAPI_TRY(mss_eff_config_thermal_powercurve(i_target_mba));
+ FAPI_TRY(mss_eff_config_thermal_throttles(i_target_mba));
+
+
+ FAPI_INF("*** mss_eff_config_thermal COMPLETE on %s ***",
+ mss::c_str(i_target_mba));
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+
+ ///
+ /// @brief mss_eff_config_thermal_powercurve(): 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
+ /// @return fapi2::ReturnCode
+ ///
+ fapi2::ReturnCode mss_eff_config_thermal_powercurve(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba)
+ {
+ FAPI_INF("*** Running mss_eff_config_thermal_powercurve on %s ***",
+ mss::c_str(i_target_mba));
+ uint8_t l_port = 0;
+ uint8_t l_dimm = 0;
+ uint8_t l_custom_dimm = 0;
+ uint8_t l_dimm_ranks_array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0};
+ uint32_t l_power_slope_array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0};
+ uint32_t l_power_int_array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0};
+ uint32_t l_power_slope2_array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0};
+ uint32_t l_power_int2_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};
+ uint32_t l_total_power_slope2_array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0};
+ uint32_t l_total_power_int2_array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0};
+ uint32_t l_cdimm_master_power_slope = 0;
+ uint32_t l_cdimm_master_power_intercept = 0;
+ uint32_t l_cdimm_supplier_power_slope = 0;
+ uint32_t l_cdimm_supplier_power_intercept = 0;
+ uint32_t l_cdimm_master_total_power_slope = 0;
+ uint32_t l_cdimm_master_total_power_intercept = 0;
+ uint32_t l_cdimm_supplier_total_power_slope = 0;
+ uint32_t l_cdimm_supplier_total_power_intercept = 0;
+ uint8_t l_dram_gen = 0;
+ uint8_t l_logged_error_power_curve = 0;
+ uint8_t l_logged_error_total_power_curve = 0;
+
+ //------------------------------------------------------------------------------
+ // Get input attributes
+ //------------------------------------------------------------------------------
+
+ // 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_RANKS_PER_DIMM,
+ i_target_mba, l_dimm_ranks_array));
+ 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
+ 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)
+ FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_CDIMM_VPD_MASTER_POWER_SLOPE,
+ l_target_chip, l_cdimm_master_power_slope));
+
+ FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_CDIMM_VPD_MASTER_POWER_INTERCEPT,
+ l_target_chip, l_cdimm_master_power_intercept));
+
+ FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_CDIMM_VPD_SUPPLIER_POWER_SLOPE,
+ l_target_chip, l_cdimm_supplier_power_slope));
+
+
+ FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_CDIMM_VPD_SUPPLIER_POWER_INTERCEPT,
+ l_target_chip, l_cdimm_supplier_power_intercept));
+
+
+ // These are for the total CDIMM power (VMEM+VPP for DDR4)
+ if (l_dram_gen == fapi2::ENUM_ATTR_CEN_EFF_DRAM_GEN_DDR4)
+ {
+
+ FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_CDIMM_VPD_MASTER_TOTAL_POWER_SLOPE,
+ l_target_chip, l_cdimm_master_total_power_slope));
+
+ FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_CDIMM_VPD_MASTER_TOTAL_POWER_INTERCEPT,
+ l_target_chip, l_cdimm_master_total_power_intercept));
+
+ FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_CDIMM_VPD_SUPPLIER_TOTAL_POWER_SLOPE,
+ l_target_chip, l_cdimm_supplier_total_power_slope));
+
+ FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_CDIMM_VPD_SUPPLIER_TOTAL_POWER_INTERCEPT,
+ l_target_chip, l_cdimm_supplier_total_power_intercept));
+ }
+ else
+ {
+ // Set total power curve variables to the VMEM power curve variables for DDR3
+ l_cdimm_master_total_power_slope = l_cdimm_master_power_slope;
+ l_cdimm_master_total_power_intercept = l_cdimm_master_power_intercept;
+ l_cdimm_supplier_total_power_slope = l_cdimm_supplier_power_slope;
+ l_cdimm_supplier_total_power_intercept = l_cdimm_supplier_power_intercept;
+ }
+ }
+
+ // Power Curve Determination
+ // Iterate through the MBA ports to get power slope/intercept values
+ for (l_port = 0; l_port + MAX_PORTS_PER_MBA; l_port++)
+ {
+ // iterate through the dimms on each port again to determine power slope and
+ // intercept
+ for (l_dimm = 0; l_dimm + MAX_DIMM_PER_PORT; l_dimm++)
+ {
+ // initialize dimm entries to zero
+ l_power_slope_array[l_port][l_dimm] = 0;
+ l_power_int_array[l_port][l_dimm] = 0;
+ l_power_slope2_array[l_port][l_dimm] = 0;
+ l_power_int2_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;
+ l_total_power_slope2_array[l_port][l_dimm] = 0;
+ l_total_power_int2_array[l_port][l_dimm] = 0;
+
+ // only update values for l_dimms that are physically present
+ if (l_dimm_ranks_array[l_port][l_dimm] > 0)
+ {
+ // CDIMM power slope/intercept will come from VPD
+ // Data in VPD needs to be the power per virtual dimm on the CDIMM
+ if (l_custom_dimm == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES)
+ {
+ l_power_slope_array[l_port][l_dimm] =
+ l_cdimm_master_power_slope;
+ l_power_int_array[l_port][l_dimm] =
+ l_cdimm_master_power_intercept;
+ l_power_slope2_array[l_port][l_dimm] =
+ l_cdimm_supplier_power_slope;
+ l_power_int2_array[l_port][l_dimm] =
+ l_cdimm_supplier_power_intercept;
+ l_total_power_slope_array[l_port][l_dimm] =
+ l_cdimm_master_total_power_slope;
+ l_total_power_int_array[l_port][l_dimm] =
+ l_cdimm_master_total_power_intercept;
+ l_total_power_slope2_array[l_port][l_dimm] =
+ l_cdimm_supplier_total_power_slope;
+ l_total_power_int2_array[l_port][l_dimm] =
+ l_cdimm_supplier_total_power_intercept;
+
+ // check to see if VMEM power curve data is valid
+ if (
+ (((l_cdimm_master_power_slope & 0x8000) != 0) &&
+ ((l_cdimm_master_power_intercept & 0x8000) != 0))
+ &&
+ (((l_cdimm_supplier_power_slope & 0x8000) != 0) &&
+ ((l_cdimm_supplier_power_intercept & 0x8000) != 0))
+ )
+ {
+ l_power_slope_array[l_port][l_dimm] =
+ l_cdimm_master_power_slope & 0x1FFF;
+ l_power_int_array[l_port][l_dimm] =
+ l_cdimm_master_power_intercept & 0x1FFF;
+ l_power_slope2_array[l_port][l_dimm] =
+ l_cdimm_supplier_power_slope & 0x1FFF;
+ l_power_int2_array[l_port][l_dimm] =
+ l_cdimm_supplier_power_intercept & 0x1FFF;
+
+ // check to see if data is lab data
+ if (
+ (((l_cdimm_master_power_slope & 0x4000) == 0) ||
+ ((l_cdimm_master_power_intercept & 0x4000) == 0))
+ ||
+ (((l_cdimm_supplier_power_slope & 0x4000) == 0) ||
+ ((l_cdimm_supplier_power_intercept &
+ 0x4000) == 0))
+ )
+ {
+ FAPI_INF("WARNING: VMEM power curve data is lab data, not ship level data. Using data anyways.");
+ }
+
+ // check total power curve (VMEM+VPP) values for DDR4
+ if (l_dram_gen == fapi2::ENUM_ATTR_CEN_EFF_DRAM_GEN_DDR4)
+ {
+ if (
+ (((l_cdimm_master_total_power_slope & 0x8000) != 0) &&
+ ((l_cdimm_master_total_power_intercept & 0x8000) != 0))
+ &&
+ (((l_cdimm_supplier_total_power_slope & 0x8000) != 0) &&
+ ((l_cdimm_supplier_total_power_intercept & 0x8000) != 0))
+ )
+ {
+ l_total_power_slope_array[l_port][l_dimm] =
+ l_cdimm_master_total_power_slope & 0x1FFF;
+ l_total_power_int_array[l_port][l_dimm] =
+ l_cdimm_master_total_power_intercept & 0x1FFF;
+ l_total_power_slope2_array[l_port][l_dimm] =
+ l_cdimm_supplier_total_power_slope & 0x1FFF;
+ l_total_power_int2_array[l_port][l_dimm] =
+ l_cdimm_supplier_total_power_intercept & 0x1FFF;
+
+ // check to see if data is lab data
+ if (
+ (((l_cdimm_master_total_power_slope & 0x4000) == 0) ||
+ ((l_cdimm_master_total_power_intercept & 0x4000) == 0))
+ ||
+ (((l_cdimm_supplier_total_power_slope & 0x4000) == 0) ||
+ ((l_cdimm_supplier_total_power_intercept &
+ 0x4000) == 0))
+ )
+ {
+ FAPI_INF("WARNING: Total power curve data is lab data, not ship level data. Using data anyways.");
+ }
+ }
+ else
+ {
+ // Set to VMEM power curve values if total values are not valid and log an error
+ // early DDR4 CDIMMs will have the total power curve entries all zero (not valid)
+ l_total_power_slope_array[l_port][l_dimm] =
+ l_power_slope_array[l_port][l_dimm];
+ l_total_power_int_array[l_port][l_dimm] =
+ l_power_int_array[l_port][l_dimm];
+ l_total_power_slope2_array[l_port][l_dimm] =
+ l_power_slope2_array[l_port][l_dimm];
+ l_total_power_int2_array[l_port][l_dimm] =
+ l_power_int2_array[l_port][l_dimm];
+
+ // only log the error once per MBA, since all dimms will have the same power curve values
+ if (l_logged_error_total_power_curve == 0)
+ {
+ l_logged_error_total_power_curve = 1;
+ 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),
+ "");
+ }
+ }
+ }
+ else
+ {
+ // Set total power curve values to VMEM power curve values for anything other than DDR4 (ie. DDR3)
+ l_total_power_slope_array[l_port][l_dimm] =
+ l_power_slope_array[l_port][l_dimm];
+ l_total_power_int_array[l_port][l_dimm] =
+ l_power_int_array[l_port][l_dimm];
+ l_total_power_slope2_array[l_port][l_dimm] =
+ l_power_slope2_array[l_port][l_dimm];
+ l_total_power_int2_array[l_port][l_dimm] =
+ l_power_int2_array[l_port][l_dimm];
+ }
+ }
+ else
+ {
+ // Set to default values and log an error if VMEM power curve values are not valid
+ l_power_slope_array[l_port][l_dimm] =
+ CDIMM_POWER_SLOPE_DEFAULT;
+ l_power_int_array[l_port][l_dimm] =
+ CDIMM_POWER_INT_DEFAULT;
+ l_power_slope2_array[l_port][l_dimm] =
+ CDIMM_POWER_SLOPE_DEFAULT;
+ l_power_int2_array[l_port][l_dimm] =
+ CDIMM_POWER_INT_DEFAULT;
+ l_total_power_slope_array[l_port][l_dimm] =
+ CDIMM_POWER_SLOPE_DEFAULT;
+ l_total_power_int_array[l_port][l_dimm] =
+ CDIMM_POWER_INT_DEFAULT;
+ l_total_power_slope2_array[l_port][l_dimm] =
+ CDIMM_POWER_SLOPE_DEFAULT;
+ l_total_power_int2_array[l_port][l_dimm] =
+ CDIMM_POWER_INT_DEFAULT;
+
+ // only log the error once per MBA, since all dimms will have the same power curve values
+ if (l_logged_error_power_curve == 0)
+ {
+ l_logged_error_power_curve = 1;
+
+ 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),
+ "");
+ }
+ }
+
+ FAPI_DBG("CDIMM VMEM Power [P%d:D%d][SLOPE=%d:INT=%d cW][SLOPE2=%d:INT2=%d cW]", 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,
+ 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.
+ }
+ }
+ }
+
+ // write output attributes
+ FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_POWER_SLOPE,
+ i_target_mba, l_power_slope_array));
+ FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_POWER_INT, i_target_mba, l_power_int_array));
+ FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_POWER_SLOPE2,
+ i_target_mba, l_power_slope2_array));
+ FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_POWER_INT2,
+ i_target_mba, l_power_int2_array));
+ FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_TOTAL_POWER_SLOPE,
+ i_target_mba, l_total_power_slope_array));
+ FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_TOTAL_POWER_INT, i_target_mba, l_total_power_int_array));
+ FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_TOTAL_POWER_SLOPE2,
+ i_target_mba, l_total_power_slope2_array));
+ FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_TOTAL_POWER_INT2,
+ i_target_mba, l_total_power_int2_array));
+ FAPI_INF("*** mss_eff_config_thermal_powercurve COMPLETE on %s ***",
+ mss::c_str(i_target_mba));
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+
+ ///
+ /// @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
+ /// @return fapi2::ReturnCode
+ ///
+ fapi2::ReturnCode mss_eff_config_thermal_throttles(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target_mba)
+ {
+
+ FAPI_INF("*** Running mss_eff_config_thermal_throttles on %s ***",
+ mss::c_str(i_target_mba));
+
+// 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;
+ uint32_t l_runtime_throttle_n_per_chip = 0;
+ uint32_t l_runtime_throttle_d = 0;
+ 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_ddr4 = 0;
+ uint8_t l_max_number_dimms_per_reg = 0;
+ uint8_t l_dimm_reg_power_limit_adj_enable = 0;
+ uint8_t l_reg_max_dimm_count = 0;
+ uint8_t l_dram_gen = 0;
+ uint32_t l_power_slope_array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0};
+ 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;
+
+ // 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_CEN_MRW_MEM_THROTTLE_DENOMINATOR, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(),
+ l_runtime_throttle_d));
+ FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MRW_MAX_DRAM_DATABUS_UTIL,
+ fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_max_dram_databus_util));
+ FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MRW_VMEM_REGULATOR_MEMORY_POWER_LIMIT_PER_DIMM,
+ fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_dimm_reg_power_limit_per_dimm));
+ FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_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_CEN_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_CEN_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,
+ 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));
+ FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_POWER_SLOPE,
+ i_target_mba, l_power_slope_array));
+ FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_POWER_INT,
+ i_target_mba, l_power_int_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));
+
+ // 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)
+ {
+ const auto l_target_mba_array = l_target_chip.getChildren<fapi2::TARGET_TYPE_MBA>();
+ l_num_mba_with_dimms = 0;
+
+ 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>();
+
+ if (l_target_dimm_array.size() > 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;
+ }
+
+
+//------------------------------------------------------------------------------
+// Memory Throttle Determination
+//------------------------------------------------------------------------------
+
+// Determine memory throttle settings needed based on dimm thermal power limit
+
+//------------------------------------------------------------------------------
+// Determine the thermal power limit to use, which represents a single channel
+// pair power limit for the dimms on that channel pair (ie. power for all dimms
+// attached to one MBA). The procedure mss_bulk_power_throttles takes the
+// input of channel pair power to determine throttles.
+// CDIMM thermal power limit from MRW is per CDIMM, so divide by number of mbas
+// that have dimms to get channel pair power
+// CDIMM: Allow all commands to be directed toward one MBA to achieve the power
+// limit
+// This means that the power limit for a MBA channel pair must be the total
+// CDIMM power limit minus the idle power of the other MBAs logical dimms
+//------------------------------------------------------------------------------
+
+ // 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_adj = l_dimm_reg_power_limit_per_dimm;
+
+ if (l_dimm_reg_power_limit_adj_enable == fapi2::ENUM_ATTR_CEN_MRW_VMEM_REGULATOR_POWER_LIMIT_PER_DIMM_ADJ_ENABLE_TRUE)
+ {
+ // adjust reg power limit per cdimm only if l_reg_max_dimm_count>0 and l_reg_max_dimm_count<l_max_number_dimms_per_reg
+ if (
+ (l_reg_max_dimm_count > 0)
+ && (l_reg_max_dimm_count < l_max_number_dimms_per_reg)
+ )
+ {
+ l_dimm_reg_power_limit_per_dimm_adj =
+ 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);
+ }
+ }
+
+ // 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;
+ }
+
+ // 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;
+ }
+ // 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;
+ }
+
+ // 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;
+
+ // 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) )
+ {
+ l_runtime_throttle_n_per_mba = l_runtime_throttle_n_per_chip;
+ }
+
+ 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,
+ l_runtime_throttle_n_per_mba, l_runtime_throttle_n_per_chip, l_runtime_throttle_d);
+
+
+ // For DDR4, use the VMEM power to determine the runtime throttle settings that are based
+ // on a VMEM power limit (not a VMEM+VPP power limit which is to be used at runtime for tmgt)
+ // Need to temporarily override attributes for mss_bulk_pwr_throttles to use
+ // Needed to determines runtime memory throttle settings based on any VMEM power limits
+ if (l_dram_gen == fapi2::ENUM_ATTR_CEN_EFF_DRAM_GEN_DDR4)
+ {
+ FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_TOTAL_POWER_SLOPE,
+ i_target_mba, l_power_slope_array));
+ FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_TOTAL_POWER_INT, i_target_mba, l_power_int_array));
+ }
+
+ // 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);
+
+ // Reset the total power curve attributes back to the original values
+ if (l_dram_gen == fapi2::ENUM_ATTR_CEN_EFF_DRAM_GEN_DDR4)
+ {
+ FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_TOTAL_POWER_SLOPE,
+ i_target_mba, l_total_power_slope_array));
+ FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_TOTAL_POWER_INT, i_target_mba, l_total_power_int_array));
+ }
+
+ // Read back in the updated throttle attribute values (these are now set to
+ // values that will give dimm/channel power underneath the thermal power limit)
+ FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_MEM_THROTTLE_NUMERATOR_PER_MBA,
+ i_target_mba, l_runtime_throttle_n_per_mba));
+
+ FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_MEM_THROTTLE_NUMERATOR_PER_CHIP,
+ i_target_mba, l_runtime_throttle_n_per_chip));
+
+ FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_MEM_THROTTLE_DENOMINATOR,
+ i_target_mba, l_runtime_throttle_d));
+
+ // Setup the RAS and CAS increments used in the throttling register
+ l_ras_increment = 0;
+ l_cas_increment = 1;
+
+ // update output attributes
+ 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));
+
+ FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_THROTTLE_CONTROL_CAS_WEIGHT,
+ i_target_mba, l_cas_increment));
+
+ FAPI_INF("*** mss_eff_config_thermal_throttles COMPLETE on %s ***",
+ mss::c_str(i_target_mba));
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+
+} //end extern C
OpenPOWER on IntegriCloud