summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/eff_config/attr_setters.C30
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/eff_config/attr_setters.H10
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/eff_config/nimbus_pre_data_engine.C363
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/freq/nimbus_mss_freq.C278
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.C781
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.H209
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H9
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C108
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H117
-rw-r--r--src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_freq.xml37
-rw-r--r--src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_general_errors.xml17
-rw-r--r--src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_lib.xml11
-rw-r--r--src/import/generic/memory/lib/data_engine/pre_data_init.H360
-rw-r--r--src/import/generic/memory/lib/utils/freq/gen_mss_freq.H485
-rw-r--r--src/import/generic/memory/lib/utils/freq/gen_mss_freq_traits.H76
-rw-r--r--src/import/generic/memory/lib/utils/freq/mss_freq_scoreboard.C150
-rw-r--r--src/import/generic/memory/lib/utils/freq/mss_freq_scoreboard.H600
-rw-r--r--src/import/generic/memory/lib/utils/shared/mss_generic_consts.H20
-rw-r--r--src/import/generic/procedures/xml/error_info/generic_error.xml66
19 files changed, 2110 insertions, 1617 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/attr_setters.C b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/attr_setters.C
index aeb61f126..ce42c0b28 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/attr_setters.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/attr_setters.C
@@ -61,35 +61,5 @@ fapi_try_exit:
return fapi2::current_err;
}
-///
-/// @brief Sets pre_eff_config attributes
-/// @param[in] i_target the DIMM target
-/// @param[in] i_spd_decoder SPD decoder
-/// @return FAPI2_RC_SUCCESS iff ok
-///
-fapi2::ReturnCode set_pre_init_attrs( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
- const spd::facade& i_spd_decoder )
-{
- fapi2::ReturnCode l_rc(fapi2::FAPI2_RC_SUCCESS);
- mss::pre_data_engine<mss::NIMBUS> l_data_engine(i_target, i_spd_decoder, l_rc);
- FAPI_TRY(l_rc, "Failed to instantiate pre_data_engine object for %s", spd::c_str(i_target));
-
- // Set attributes needed before eff_config
- // DIMM type and DRAM gen are needed for c_str to aid debugging
- FAPI_TRY(l_data_engine.set_dimm_type(), "Failed to set DIMM type %s", spd::c_str(i_target) );
- FAPI_TRY(l_data_engine.set_dram_gen(), "Failed to set DRAM gen %s", spd::c_str(i_target) );
-
- // Hybrid and hybrid media help detect hybrid modules, specifically NVDIMMs for Nimbus
- FAPI_TRY(l_data_engine.set_hybrid(), "Failed to set Hybrid %s", spd::c_str(i_target) );
- FAPI_TRY(l_data_engine.set_hybrid_media(), "Failed to set Hybrid Media %s", spd::c_str(i_target) );
-
- // Number of master ranks needed for VPD decoding
- // and dimm_ranks_configured is a PRD attr...
- FAPI_TRY(l_data_engine.set_master_ranks(), "Failed to set Master ranks %s", spd::c_str(i_target) );
- FAPI_TRY(l_data_engine.set_dimm_ranks_configured(), "Failed to set DIMM ranks configured %s", spd::c_str(i_target) );
-
-fapi_try_exit:
- return fapi2::current_err;
-}
} // mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/attr_setters.H b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/attr_setters.H
index 976c1077d..8b703f72e 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/attr_setters.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/attr_setters.H
@@ -37,7 +37,6 @@
#define _MSS_ATTR_SETTERS_H_
#include <fapi2.H>
-#include <generic/memory/lib/spd/spd_facade.H>
namespace mss
{
@@ -53,15 +52,6 @@ namespace mss
fapi2::ReturnCode set_voltage_attributes(const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target_mcs,
uint32_t i_selected_dram_voltage,
uint32_t i_selected_dram_voltage_vpp);
-
-///
-/// @brief Sets pre_eff_config attributes
-/// @param[in] i_target the DIMM target
-/// @param[in] i_spd_decoder SPD decoder
-/// @return FAPI2_RC_SUCCESS iff ok
-///
-fapi2::ReturnCode set_pre_init_attrs( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
- const spd::facade& i_spd_decoder );
} // mss
#endif
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/nimbus_pre_data_engine.C b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/nimbus_pre_data_engine.C
index eba1fcac0..c93559ed5 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/nimbus_pre_data_engine.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/nimbus_pre_data_engine.C
@@ -25,7 +25,7 @@
///
/// @file nimbus_pre_data_engine.C
-/// @brief pre_data_engine implimentation for Nimbus
+/// @brief pre_data_engine implimentation for mss::proc_type::NIMBUS
///
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP FW Owner: Stephen Glancy <sglancy@us.ibm.com>
@@ -42,11 +42,287 @@
namespace mss
{
+///
+/// @brief Traits for pre_data_engine
+/// @class preDataInitTraits
+/// @note NIMBUS, DIMM_TYPE specialization
+///
+template<>
+class preDataInitTraits<mss::proc_type::NIMBUS, DIMM_TYPE>
+{
+ public:
+ using attr_type = fapi2::ATTR_EFF_DIMM_TYPE_Type;
+ static const fapi2::TargetType TARGET_TYPE = fapi2::ATTR_EFF_DIMM_TYPE_TargetType;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the MCS target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_EFF_DIMM_TYPE, i_target, o_setting) );
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the MCS target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ const attr_type& i_setting)
+ {
+ attr_type l_data = {};
+ memcpy(l_data, i_setting, sizeof(l_data));
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_TYPE, i_target, l_data) );
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for pre_data_engine
+/// @class preDataInitTraits
+/// @note NIMBUS, DRAM_GEN specialization
+///
+template<>
+class preDataInitTraits<mss::proc_type::NIMBUS, DRAM_GEN>
+{
+ public:
+ using attr_type = fapi2::ATTR_EFF_DRAM_GEN_Type;
+ static const fapi2::TargetType TARGET_TYPE = fapi2::ATTR_EFF_DRAM_GEN_TargetType;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the MCS target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_EFF_DRAM_GEN, i_target, o_setting) );
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the MCS target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ const attr_type& i_setting)
+ {
+ attr_type l_data = {};
+ memcpy(l_data, i_setting, sizeof(l_data));
+
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_GEN, i_target, l_data) );
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for pre_data_engine
+/// @class preDataInitTraits
+/// @note NIMBUS, HYBRID specialization
+///
+template<>
+class preDataInitTraits<mss::proc_type::NIMBUS, HYBRID>
+{
+ public:
+ using attr_type = fapi2::ATTR_EFF_HYBRID_Type;
+ static const fapi2::TargetType TARGET_TYPE = fapi2::ATTR_EFF_HYBRID_TargetType;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the MCS target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_EFF_HYBRID, i_target, o_setting) );
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the MCS target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ const attr_type& i_setting)
+ {
+ attr_type l_data = {};
+ memcpy(l_data, i_setting, sizeof(l_data));
+
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_HYBRID, i_target, l_data) );
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for pre_data_engine
+/// @class preDataInitTraits
+/// @note NIMBUS, HYBRID_MEDIA specialization
+///
+template<>
+class preDataInitTraits<mss::proc_type::NIMBUS, HYBRID_MEDIA>
+{
+ public:
+ using attr_type = fapi2::ATTR_EFF_HYBRID_MEMORY_TYPE_Type;
+ static const fapi2::TargetType TARGET_TYPE = fapi2::ATTR_EFF_HYBRID_MEMORY_TYPE_TargetType;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the MCS target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_EFF_HYBRID_MEMORY_TYPE, i_target, o_setting) );
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the MCS target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ const attr_type& i_setting)
+ {
+ attr_type l_data = {};
+ memcpy(l_data, i_setting, sizeof(l_data));
+
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_HYBRID_MEMORY_TYPE, i_target, l_data) );
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for pre_data_engine
+/// @class preDataInitTraits
+/// @note NIMBUS, MRANKS specialization
+///
+template<>
+class preDataInitTraits<mss::proc_type::NIMBUS, MRANKS>
+{
+ public:
+ using attr_type = fapi2::ATTR_EFF_NUM_MASTER_RANKS_PER_DIMM_Type;
+ static const fapi2::TargetType TARGET_TYPE = fapi2::ATTR_EFF_NUM_MASTER_RANKS_PER_DIMM_TargetType;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the MCS target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_EFF_NUM_MASTER_RANKS_PER_DIMM, i_target, o_setting) );
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the MCS target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ const attr_type& i_setting)
+ {
+ attr_type l_data = {};
+ memcpy(l_data, i_setting, sizeof(l_data));
+
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_NUM_MASTER_RANKS_PER_DIMM, i_target, l_data) );
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
+///
+/// @brief Traits for pre_data_engine
+/// @class preDataInitTraits
+/// @note NIMBUS, DIMM_RANKS_CNFG specialization
+///
+template<>
+class preDataInitTraits<mss::proc_type::NIMBUS, DIMM_RANKS_CNFG>
+{
+ public:
+ using attr_type = fapi2::ATTR_EFF_DIMM_RANKS_CONFIGED_Type;
+ static const fapi2::TargetType TARGET_TYPE = fapi2::ATTR_EFF_NUM_MASTER_RANKS_PER_DIMM_TargetType;
+
+ ///
+ /// @brief attribute getter
+ /// @param[in] i_target the MCS target
+ /// @param[out] o_setting array to populate
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ attr_type& o_setting)
+ {
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_EFF_DIMM_RANKS_CONFIGED, i_target, o_setting) );
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+
+ ///
+ /// @brief attribute setter
+ /// @param[in] i_target the MCS target
+ /// @param[in] i_setting array to set
+ /// @return FAPI2_RC_SUCCESS iff okay
+ ///
+ static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
+ const attr_type& i_setting)
+ {
+ attr_type l_data = {};
+ memcpy(l_data, i_setting, sizeof(l_data));
+
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_RANKS_CONFIGED, i_target, l_data) );
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+};
+
// =========================================================
// DDR4 SPD Document Release 4
// Byte 2 (0x002): Key Byte / DRAM Device Type
// =========================================================
-const std::vector< std::pair<uint8_t, uint8_t> > pre_data_engine<NIMBUS>::DRAM_GEN_MAP =
+template<>
+const std::vector< std::pair<uint8_t, uint8_t> > pre_data_engine<mss::proc_type::NIMBUS>::DRAM_GEN_MAP =
{
//{key value, dram gen}
{0x0C, fapi2::ENUM_ATTR_EFF_DRAM_GEN_DDR4}
@@ -57,7 +333,8 @@ const std::vector< std::pair<uint8_t, uint8_t> > pre_data_engine<NIMBUS>::DRAM_G
// DDR4 SPD Document Release 4
// Byte 3 (0x003): Key Byte / Module Type - Hybrid
// =========================================================
-const std::vector< std::pair<uint8_t, uint8_t> > pre_data_engine<NIMBUS>::HYBRID_MAP =
+template<>
+const std::vector< std::pair<uint8_t, uint8_t> > pre_data_engine<mss::proc_type::NIMBUS>::HYBRID_MAP =
{
//{key byte, dimm type}
{0, fapi2::ENUM_ATTR_EFF_HYBRID_NOT_HYBRID},
@@ -70,7 +347,8 @@ const std::vector< std::pair<uint8_t, uint8_t> > pre_data_engine<NIMBUS>::HYBRID
// DDR4 SPD Document Release 4
// Byte 3 (0x003): Key Byte / Module Type - Hybrid
// =========================================================
-const std::vector< std::pair<uint8_t, uint8_t> > pre_data_engine<NIMBUS>::HYBRID_MEMORY_TYPE_MAP =
+template<>
+const std::vector< std::pair<uint8_t, uint8_t> > pre_data_engine<mss::proc_type::NIMBUS>::HYBRID_MEMORY_TYPE_MAP =
{
//{key byte, dimm type}
@@ -83,7 +361,8 @@ const std::vector< std::pair<uint8_t, uint8_t> > pre_data_engine<NIMBUS>::HYBRID
// DDR4 SPD Document Release 4
// Byte 3 (0x003): Key Byte / Module Type
// =========================================================
-const std::vector< std::pair<uint8_t, uint8_t> > pre_data_engine<NIMBUS>::BASE_MODULE_TYPE_MAP =
+template<>
+const std::vector< std::pair<uint8_t, uint8_t> > pre_data_engine<mss::proc_type::NIMBUS>::BASE_MODULE_TYPE_MAP =
{
//{key byte, dimm type}
{1, fapi2::ENUM_ATTR_EFF_DIMM_TYPE_RDIMM},
@@ -96,7 +375,8 @@ const std::vector< std::pair<uint8_t, uint8_t> > pre_data_engine<NIMBUS>::BASE_M
// DDR4 SPD Document Release 4
// Byte 12 (0x00C): Module Organization
// =========================================================
-const std::vector< std::pair<uint8_t, uint8_t> > pre_data_engine<NIMBUS>::NUM_PACKAGE_RANKS_MAP =
+template<>
+const std::vector< std::pair<uint8_t, uint8_t> > pre_data_engine<mss::proc_type::NIMBUS>::NUM_PACKAGE_RANKS_MAP =
{
// {key byte, num of package ranks per DIMM (package ranks)}
{0, fapi2::ENUM_ATTR_EFF_NUM_MASTER_RANKS_PER_DIMM_1R},
@@ -105,42 +385,18 @@ const std::vector< std::pair<uint8_t, uint8_t> > pre_data_engine<NIMBUS>::NUM_PA
};
///
-/// @brief ctor
-/// @param[in] i_target the DIMM target
-/// @param[in] i_spd_data SPD data
-/// @param[out] o_rc ReturnCode for failure to init object
-///
-pre_data_engine<NIMBUS>::pre_data_engine(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
- const spd::facade& i_spd_data,
- fapi2::ReturnCode& o_rc):
- iv_dimm(i_target),
- iv_spd_data(i_spd_data)
-{
- // Sets up commonly used member variables
- uint8_t l_master_ranks = 0;
- FAPI_TRY(iv_spd_data.num_package_ranks_per_dimm(l_master_ranks));
- FAPI_TRY(lookup_table_check(i_target, NUM_PACKAGE_RANKS_MAP, PRE_DATA_ENGINE_CTOR, l_master_ranks, iv_master_ranks));
-
- o_rc = fapi2::FAPI2_RC_SUCCESS;
- return;
-
-fapi_try_exit:
- o_rc = fapi2::current_err;
- return;
-}
-
-///
/// @brief Set ATTR_EFF_DIMM_TYPE
/// @return FAPI2_RC_SUCCESS iff ok
///
-fapi2::ReturnCode pre_data_engine<NIMBUS>::set_dimm_type()
+template<>
+fapi2::ReturnCode pre_data_engine<mss::proc_type::NIMBUS>::set_dimm_type()
{
uint8_t l_base_module_type = 0;
uint8_t l_dimm_type = 0;
FAPI_TRY(iv_spd_data.base_module(l_base_module_type));
FAPI_TRY(lookup_table_check(iv_dimm, BASE_MODULE_TYPE_MAP, SET_ATTR_DIMM_TYPE, l_base_module_type, l_dimm_type));
- FAPI_TRY( (set_field<NIMBUS, DIMM_TYPE>(iv_dimm, l_dimm_type)) );
+ FAPI_TRY( (set_field<mss::proc_type::NIMBUS, DIMM_TYPE>(iv_dimm, l_dimm_type)) );
fapi_try_exit:
return fapi2::current_err;
@@ -150,7 +406,8 @@ fapi_try_exit:
/// @brief Set ATTR_EFF_DRAM_GEN
/// @return FAPI2_RC_SUCCESS iff ok
///
-fapi2::ReturnCode pre_data_engine<NIMBUS>::set_dram_gen()
+template<>
+fapi2::ReturnCode pre_data_engine<mss::proc_type::NIMBUS>::set_dram_gen()
{
uint8_t l_device_type = 0;
uint8_t l_dram_gen = 0;
@@ -158,7 +415,7 @@ fapi2::ReturnCode pre_data_engine<NIMBUS>::set_dram_gen()
FAPI_TRY(iv_spd_data.device_type(l_device_type));
FAPI_TRY(lookup_table_check(iv_dimm, DRAM_GEN_MAP, SET_ATTR_DRAM_GEN, l_device_type, l_dram_gen));
- FAPI_TRY( (set_field<NIMBUS, DRAM_GEN>(iv_dimm, l_dram_gen)) );
+ FAPI_TRY( (set_field<mss::proc_type::NIMBUS, DRAM_GEN>(iv_dimm, l_dram_gen)) );
fapi_try_exit:
return fapi2::current_err;
@@ -168,7 +425,8 @@ fapi_try_exit:
/// @brief Set ATTR_EFF_HYBRID
/// @return FAPI2_RC_SUCCESS iff ok
///
-fapi2::ReturnCode pre_data_engine<NIMBUS>::set_hybrid()
+template<>
+fapi2::ReturnCode pre_data_engine<mss::proc_type::NIMBUS>::set_hybrid()
{
uint8_t l_spd_hybrid_type = 0;
uint8_t l_hybrid = 0;
@@ -176,7 +434,7 @@ fapi2::ReturnCode pre_data_engine<NIMBUS>::set_hybrid()
FAPI_TRY(iv_spd_data.hybrid(l_spd_hybrid_type));
FAPI_TRY(lookup_table_check(iv_dimm, HYBRID_MAP, SET_ATTR_HYBRID, l_spd_hybrid_type, l_hybrid));
- FAPI_TRY( (set_field<NIMBUS, HYBRID>(iv_dimm, l_hybrid)) );
+ FAPI_TRY( (set_field<mss::proc_type::NIMBUS, HYBRID>(iv_dimm, l_hybrid)) );
fapi_try_exit:
return fapi2::current_err;
@@ -186,7 +444,8 @@ fapi_try_exit:
/// @brief Set ATTR_EFF_HYBRID_MEMORY_TYPE
/// @return FAPI2_RC_SUCCESS iff ok
///
-fapi2::ReturnCode pre_data_engine<NIMBUS>::set_hybrid_media()
+template<>
+fapi2::ReturnCode pre_data_engine<mss::proc_type::NIMBUS>::set_hybrid_media()
{
uint8_t l_hybrid_media = 0;
uint8_t l_spd_hybrid_media = 0;
@@ -194,7 +453,7 @@ fapi2::ReturnCode pre_data_engine<NIMBUS>::set_hybrid_media()
FAPI_TRY(iv_spd_data.hybrid_media(l_spd_hybrid_media));
FAPI_TRY(lookup_table_check(iv_dimm, HYBRID_MAP, SET_ATTR_HYBRID, l_spd_hybrid_media, l_hybrid_media));
- FAPI_TRY( (set_field<NIMBUS, HYBRID_MEDIA>(iv_dimm, l_hybrid_media)) );
+ FAPI_TRY( (set_field<mss::proc_type::NIMBUS, HYBRID_MEDIA>(iv_dimm, l_hybrid_media)) );
fapi_try_exit:
return fapi2::current_err;
@@ -204,9 +463,18 @@ fapi_try_exit:
/// @brief Set ATTR_EFF_NUM_MASTER_RANKS_PER_DIMM
/// @return FAPI2_RC_SUCCESS iff ok
///
-fapi2::ReturnCode pre_data_engine<NIMBUS>::set_master_ranks()
+template<>
+fapi2::ReturnCode pre_data_engine<mss::proc_type::NIMBUS>::set_master_ranks()
{
- FAPI_TRY( (set_field<NIMBUS, MRANKS>(iv_dimm, iv_master_ranks)) );
+ // Sets up commonly used member variables
+ uint8_t l_master_ranks_spd = 0;
+ uint8_t l_master_ranks_to_set = 0;
+ FAPI_TRY(iv_spd_data.num_package_ranks_per_dimm(l_master_ranks_spd),
+ "%s failed to get number of package ranks from SPD", spd::c_str(iv_dimm));
+ FAPI_TRY(lookup_table_check(iv_dimm, NUM_PACKAGE_RANKS_MAP, PRE_DATA_ENGINE_CTOR, l_master_ranks_spd,
+ l_master_ranks_to_set), "%s failed MASTER_RANKS lookup check", spd::c_str(iv_dimm));
+
+ FAPI_TRY( (set_field<mss::proc_type::NIMBUS, MRANKS>(iv_dimm, l_master_ranks_to_set)) );
fapi_try_exit:
return fapi2::current_err;
@@ -216,16 +484,23 @@ fapi_try_exit:
/// @brief Sets ATTR_EFF_DIMM_RANKS_CONFIGED
/// @return FAPI2_RC_SUCCESS iff okay
///
-fapi2::ReturnCode pre_data_engine<NIMBUS>::set_dimm_ranks_configured()
+template<>
+fapi2::ReturnCode pre_data_engine<mss::proc_type::NIMBUS>::set_dimm_ranks_configured()
{
// Set configed ranks. Set the bit representing the master rank configured (0 being left most.) So,
// a 4R DIMM would be 0b11110000 (0xF0). This is used by PRD.
fapi2::buffer<uint8_t> l_ranks_configed;
+ uint8_t l_master_ranks = 0;
+
+ // Make sure the number of master ranks is setup
+ FAPI_TRY( set_master_ranks(), "%s Failed to set the number of master ranks", spd::c_str(iv_dimm) );
+ FAPI_TRY( eff_num_master_ranks_per_dimm(iv_dimm, l_master_ranks),
+ "%s Failed to get the number of master ranks", spd::c_str(iv_dimm) );
- FAPI_TRY( l_ranks_configed.setBit(0, iv_master_ranks),
+ FAPI_TRY( l_ranks_configed.setBit(0, l_master_ranks),
"%s. Failed to setBit", spd::c_str(iv_dimm) );
- FAPI_TRY( (set_field<NIMBUS, DIMM_RANKS_CNFG>(iv_dimm, uint8_t(l_ranks_configed))) );
+ FAPI_TRY( (set_field<mss::proc_type::NIMBUS, DIMM_RANKS_CNFG>(iv_dimm, uint8_t(l_ranks_configed))) );
fapi_try_exit:
return fapi2::current_err;
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/freq/nimbus_mss_freq.C b/src/import/chips/p9/procedures/hwp/memory/lib/freq/nimbus_mss_freq.C
index ee00486be..688875f34 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/freq/nimbus_mss_freq.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/freq/nimbus_mss_freq.C
@@ -22,3 +22,281 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
+
+///
+/// @file nimbus_mss_freq.C
+/// @brief Nimbus specializations for frequency library
+///
+// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com>
+// *HWP HWP Backup: Louis Stermole <stermole@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 3
+// *HWP Consumed by: HB:FSP
+
+#include <fapi2.H>
+#include <vpd_access.H>
+#include <vector>
+
+// Memory libraries
+#include <lib/mss_attribute_accessors.H>
+#include <lib/utils/assert_noexit.H>
+#include <lib/shared/mss_const.H>
+#include <lib/freq/sync.H>
+#include <lib/workarounds/freq_workarounds.H>
+
+// Generic libraries
+#include <generic/memory/lib/utils/count_dimm.H>
+#include <generic/memory/lib/utils/freq/gen_mss_freq_traits.H>
+#include <generic/memory/lib/utils/freq/gen_mss_freq.H>
+#include <generic/memory/lib/utils/freq/mss_freq_scoreboard.H>
+
+namespace mss
+{
+
+const std::vector< uint64_t > frequency_traits<mss::proc_type::NIMBUS>::SUPPORTED_FREQS =
+{
+ mss::DIMM_SPEED_1866,
+ mss::DIMM_SPEED_2133,
+ mss::DIMM_SPEED_2400,
+ mss::DIMM_SPEED_2666,
+};
+
+///
+/// @brief Sets DRAM CAS latency attributes - specialization for NIMBUS and MCA
+/// @param[in] i_target the controller target the cas_latency value
+/// @param[in] i_cas_latency cas latency to update
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode set_CL_attr<mss::proc_type::NIMBUS>(
+ const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_cas_latency)
+{
+ // I wish I could do the reinterpret cast or set the pointer to the vector :(
+ // But no can do, manual copy pasta
+ uint8_t l_temp [mss::PORTS_PER_MCS] = {0};
+
+ // Local variable instead of calling it three times. Hopefully compiler can optimize this better
+ const auto l_index = mss::index(i_target);
+ const auto& l_mcs = mss::find_target<fapi2::TARGET_TYPE_MCS>(i_target);
+
+ if ( l_index >= PORTS_PER_MCS)
+ {
+ FAPI_ERR("%s mss::index returned a value greater than PORTS_PER_MCS", mss::c_str(i_target) );
+ fapi2::Assert(false);
+ }
+
+ FAPI_TRY(mss::eff_dram_cl(l_mcs, l_temp), "%s failed to get cas latency attribute", mss::c_str(i_target));
+
+ l_temp[l_index] = i_cas_latency;
+
+ //Check for rounding issues. Going from a uint64_t to a uint8_t
+ FAPI_ASSERT( l_temp[l_index] == i_cas_latency,
+ fapi2::MSS_BAD_CL_CAST()
+ .set_CL(i_cas_latency)
+ .set_MCA_TARGET(i_target),
+ "%s bad cast for cas latency from %d to %d",
+ mss::c_str(i_target),
+ i_cas_latency,
+ l_temp[l_index]);
+
+ FAPI_INF( "Final Chosen CL: %d for %s", l_temp[l_index], mss::c_str(i_target));
+
+ // set CAS latency attribute
+ // casts vector into the type FAPI_ATTR_SET is expecting by deduction
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_CL,
+ l_mcs,
+ l_temp) ,
+ "%s Failed to set CAS latency attribute", mss::c_str(i_target));
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Sets the frequency value - specialization for NIMBUS and MCBIST
+/// @param[in] i_target the target on which to set the frequency values
+/// @param[in] i_freq frequency value to set
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode set_freq<mss::proc_type::NIMBUS>(
+ const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
+ const uint64_t i_freq)
+{
+ // Local variable to avoid compile fails - ATTR_SET cannot operate on consts
+ auto l_freq = i_freq;
+ return FAPI_ATTR_SET(fapi2::ATTR_MSS_FREQ, i_target, l_freq);
+}
+
+///
+/// @brief Gets the number of master ranks per DIMM - specialization for NIMBUS and MCA
+/// @param[in] i_target the target on which to set the frequency values
+/// @param[out] o_master_ranks number of master ranks per DIMM
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode get_master_rank_per_dimm<mss::proc_type::NIMBUS>(
+ const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ uint8_t* o_master_ranks)
+{
+ return mss::eff_num_master_ranks_per_dimm(i_target, o_master_ranks);
+}
+
+///
+/// @brief Gets the attribute for the maximum - specialization for NIMBUS
+/// @param[out] o_allowed_dimm_freq allowed dimm frequency
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode max_allowed_dimm_freq<mss::proc_type::NIMBUS>(uint32_t* o_allowed_dimm_freq)
+{
+ return mss::max_allowed_dimm_freq(o_allowed_dimm_freq);
+}
+
+///
+/// @brief Update supported frequency scoreboard according to processor limits - specialization for NIMBUS and MCBIST
+/// @param[in] i_target processor frequency domain
+/// @param[in,out] io_scoreboard scoreboard of port targets supporting each frequency
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode limit_freq_by_processor<mss::proc_type::NIMBUS>(
+ const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
+ freq_scoreboard& io_scoreboard)
+{
+ uint8_t l_req_sync_mode = 0;
+ FAPI_TRY( mss::required_synch_mode(l_req_sync_mode) );
+ FAPI_TRY( limit_freq_by_processor(i_target, l_req_sync_mode == fapi2::ENUM_ATTR_REQUIRED_SYNCH_MODE_ALWAYS,
+ io_scoreboard) );
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Gets the number of master ranks on each DIMM - specialization for the NIMBUS processor type
+/// @param[in] i_target DIMM target
+/// @param[out] o_master_ranks number of master ranks
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode num_master_ranks_per_dimm<mss::proc_type::NIMBUS>(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>&
+ i_target, uint8_t& o_master_ranks)
+{
+ return mss::eff_num_master_ranks_per_dimm(i_target, o_master_ranks);
+}
+
+///
+/// @brief Calls out the target if no DIMM frequencies are supported - specialization for NIMBUS and MCBIST
+/// @param[in] i_target target on which to operate
+/// @param[in] i_supported_freq true if any FREQ's are supported
+/// @param[in,out] io_scoreboard scoreboard of port targets supporting each frequency
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode callout_no_common_freq<mss::proc_type::NIMBUS>(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>&
+ i_target,
+ const bool l_supported_freq,
+ const uint64_t i_num_ports)
+{
+ std::vector<uint32_t> l_max_mrw_freqs(NUM_MAX_FREQS, 0);
+ uint8_t l_req_sync_mode = 0;
+ FAPI_TRY( mss::required_synch_mode(l_req_sync_mode) );
+ FAPI_TRY( max_allowed_dimm_freq(l_max_mrw_freqs.data()) );
+ {
+ const bool l_sync_mode = l_req_sync_mode == fapi2::ENUM_ATTR_REQUIRED_SYNCH_MODE_ALWAYS;
+ FAPI_ASSERT(l_supported_freq,
+ fapi2::MSS_NO_SUPPORTED_FREQ()
+ .set_REQUIRED_SYNC_MODE(l_sync_mode)
+ .set_MCBIST_TARGET(i_target)
+ .set_NUM_PORTS(i_num_ports)
+ .set_MRW_MAX_FREQ_0(l_max_mrw_freqs[0])
+ .set_MRW_MAX_FREQ_1(l_max_mrw_freqs[1])
+ .set_MRW_MAX_FREQ_2(l_max_mrw_freqs[2])
+ .set_MRW_MAX_FREQ_3(l_max_mrw_freqs[3])
+ .set_MRW_MAX_FREQ_4(l_max_mrw_freqs[4]),
+ "%s didn't find a frequency that was supported on any ports", mss::c_str(i_target));
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Calls out the target if no DIMM frequencies are supported - specialization for NIMBUS and MCBIST
+/// @param[in] i_target target on which to operate
+/// @param[in] i_vpd_supported_freqs VPD supported frequencies for the callout
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode callout_max_freq_empty_set<mss::proc_type::NIMBUS>(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>&
+ i_target,
+ const std::vector<std::vector<uint32_t>>& i_vpd_supported_freqs)
+{
+
+ std::vector<uint32_t> l_port_vpd_max_freq;
+
+ // Get the max freq supported on each port
+ for ( const auto& l_port_supported_freqs : i_vpd_supported_freqs )
+ {
+ l_port_vpd_max_freq.push_back(l_port_supported_freqs.back());
+ }
+
+ std::vector<uint32_t> l_max_mrw_freqs(NUM_MAX_FREQS, 0);
+ uint8_t l_req_sync_mode = 0;
+ FAPI_TRY( mss::required_synch_mode(l_req_sync_mode) );
+ FAPI_TRY( max_allowed_dimm_freq(l_max_mrw_freqs.data()) );
+
+ {
+ // TK Louis and I will be checking on this - I think we need this to be 4 instead of 8 and will need a mustfix
+ const bool l_sync_mode = l_req_sync_mode == fapi2::ENUM_ATTR_REQUIRED_SYNCH_MODE_ALWAYS;
+ FAPI_ASSERT(false,
+ fapi2::MSS_MRW_FREQ_MAX_FREQ_EMPTY_SET()
+ .set_MSS_VPD_FREQ_0(l_port_vpd_max_freq[0])
+ .set_MSS_VPD_FREQ_1(l_port_vpd_max_freq[1])
+ .set_MSS_VPD_FREQ_2(l_port_vpd_max_freq[2])
+ .set_MSS_VPD_FREQ_3(l_port_vpd_max_freq[3])
+ .set_MSS_MAX_FREQ_0(l_max_mrw_freqs[0])
+ .set_MSS_MAX_FREQ_1(l_max_mrw_freqs[1])
+ .set_MSS_MAX_FREQ_2(l_max_mrw_freqs[2])
+ .set_MSS_MAX_FREQ_3(l_max_mrw_freqs[3])
+ .set_MSS_MAX_FREQ_4(l_max_mrw_freqs[4])
+ .set_MSS_NEST_FREQ_0(fapi2::ENUM_ATTR_FREQ_PB_MHZ_1600)
+ .set_MSS_NEST_FREQ_1(fapi2::ENUM_ATTR_FREQ_PB_MHZ_1866)
+ .set_MSS_NEST_FREQ_2(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2000)
+ .set_MSS_NEST_FREQ_3(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2133)
+ .set_MSS_NEST_FREQ_4(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2400)
+ .set_REQUIRED_SYNC_MODE(l_sync_mode)
+ .set_MCBIST_TARGET(i_target),
+ "%s didn't find a common frequency for all ports", mss::c_str(i_target));
+ }
+fapi_try_exit:
+ return fapi2::current_err;
+}
+namespace check
+{
+
+///
+/// @brief Checks the final frequency for the system type - NIMBUS and MCBIST specialization
+/// @param[in] i_target the target on which to operate
+/// @return FAPI2_RC_SUCCESS iff okay
+///
+template<>
+fapi2::ReturnCode final_freq<mss::proc_type::NIMBUS>(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target)
+{
+ uint64_t l_mss_freq = 0;
+ uint32_t l_nest_freq = 0;
+ FAPI_TRY( mss::freq_pb_mhz(l_nest_freq) );
+ FAPI_TRY( mss::freq(i_target, l_mss_freq) );
+ FAPI_TRY( mss::workarounds::check_dimm_nest_freq_ratio(i_target, l_mss_freq, l_nest_freq) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+} // ns check
+
+} // ns mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.C b/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.C
index 4de154092..9b864695a 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.C
@@ -38,14 +38,21 @@
#include <algorithm>
#include <vector>
#include <map>
+
+// Memory libraries
#include <lib/freq/sync.H>
-#include <generic/memory/lib/utils/find.H>
+#include <lib/mss_attribute_accessors.H>
#include <lib/utils/assert_noexit.H>
+
+// Generic libraries
+#include <generic/memory/lib/utils/find.H>
#include <generic/memory/lib/utils/count_dimm.H>
#include <generic/memory/lib/spd/spd_facade.H>
#include <generic/memory/lib/spd/spd_utils.H>
#include <generic/memory/lib/utils/conversions.H>
-#include <lib/mss_attribute_accessors.H>
+#include <generic/memory/lib/utils/freq/gen_mss_freq_traits.H>
+#include <generic/memory/lib/utils/freq/gen_mss_freq.H>
+#include <generic/memory/lib/utils/freq/mss_freq_scoreboard.H>
using fapi2::TARGET_TYPE_DIMM;
using fapi2::TARGET_TYPE_MCS;
@@ -314,774 +321,4 @@ fapi_try_exit:
#endif
}
-///
-/// @brief Create a vector of support freq based on VPD config
-/// @param[in] i_target MCBIST target for which to get the DIMM configs
-/// @param[out] o_vpd_supported_freqs reference to a 2 dimensional vector of supported VPD frequencies for each MCA
-/// @return FAPI2_RC_SUCCESS iff ok
-///
-fapi2::ReturnCode vpd_supported_freqs( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
- std::vector<std::vector<uint32_t>>& o_vpd_supported_freqs)
-{
- uint8_t l_rank_count_dimm[MAX_DIMM_PER_PORT] = {};
- uint8_t l_mr_blob[mss::VPD_KEYWORD_MAX] = {};
-
- // This bitmap will keep track of the ports we visit.
- // Any we don't are not configured, so will support all frequencies in the scoreboard
- fapi2::buffer<uint8_t> configured_ports;
-
- // Clearing output Just.In.Case
- o_vpd_supported_freqs.clear();
-
- for ( size_t l_index = 0; l_index < PORTS_PER_MCBIST; ++l_index )
- {
- o_vpd_supported_freqs.push_back(std::vector<uint32_t>());
- }
-
- fapi2::VPDInfo<fapi2::TARGET_TYPE_MCS> l_vpd_info(fapi2::MemVpdData::MR);
-
- for( const auto& mcs : mss::find_targets<TARGET_TYPE_MCS>(i_target) )
- {
- for( const auto& p : mss::find_targets<TARGET_TYPE_MCA>(mcs) )
- {
- const auto l_port_pos = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(p);
- FAPI_TRY( configured_ports.setBit(l_port_pos) );
-
- if( mss::count_dimm(p) == 0 )
- {
- // Cronus lets you have an MCA w/no DIMMs. In this case, we say the port supports all frequencies
- for( const auto& freq : NIMBUS_SUPPORTED_FREQS )
- {
- o_vpd_supported_freqs[l_port_pos].push_back(freq);
- }
-
- continue;
- }
-
- FAPI_TRY( mss::eff_num_master_ranks_per_dimm(p, &(l_rank_count_dimm[0])) );
-
- l_vpd_info.iv_rank_count_dimm_0 = l_rank_count_dimm[0];
- l_vpd_info.iv_rank_count_dimm_1 = l_rank_count_dimm[1];
- l_vpd_info.iv_is_config_ffdc_enabled = false;
-
- // Iterate through all Nimbus supported freqs
- for( const auto& freq : NIMBUS_SUPPORTED_FREQS )
- {
- l_vpd_info.iv_freq_mhz = freq;
-
- FAPI_INF("%s. VPD info - frequency: %d MT/s, rank count for dimm_0: %d, dimm_1: %d",
- mss::c_str(p), l_vpd_info.iv_freq_mhz, l_vpd_info.iv_rank_count_dimm_0, l_vpd_info.iv_rank_count_dimm_1);
-
- // In order to retrieve the VPD contents we first need the keyword size.
- // If we are unable to retrieve the keyword size then this speed isn't
- // supported in the VPD in Cronus (but not FW) and we skip to the next
- // possible speed bin.
- if( fapi2::getVPD(mcs, l_vpd_info, nullptr) != fapi2::FAPI2_RC_SUCCESS )
- {
- FAPI_INF("Couldn't retrieve MR size from VPD for this config %s -- skipping freq %d MT/s", mss::c_str(p), freq );
-
- fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
- continue;
- }
-
- FAPI_ASSERT( l_vpd_info.iv_size <= mss::VPD_KEYWORD_MAX,
- fapi2::MSS_INVALID_VPD_KEYWORD_MAX().
- set_MAX(mss::VPD_KEYWORD_MAX).
- set_ACTUAL(l_vpd_info.iv_size).
- set_KEYWORD(fapi2::MemVpdData::MR).
- set_MCS_TARGET(i_target),
- "VPD MR keyword size retrieved: %d, is larger than max: %d for %s",
- l_vpd_info.iv_size, mss::VPD_KEYWORD_MAX, mss::c_str(i_target));
-
- // Firmware doesn't do the VPD lookup in the size check so repeat the logic here
- if( fapi2::getVPD(mcs, l_vpd_info, &(l_mr_blob[0])) != fapi2::FAPI2_RC_SUCCESS )
- {
- FAPI_INF("Couldn't retrieve MR data from VPD for this config %s -- skipping freq %d MT/s", mss::c_str(p), freq );
-
- fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
- continue;
- }
-
- // Add supported freqs to our output
- FAPI_INF("VPD supported freq added: %d for %s", freq, mss::c_str(p) );
- o_vpd_supported_freqs[l_port_pos].push_back(freq);
- }// freqs
- }// mca
- }//mcs
-
- // Mark any ports we didn't visit as supporting all frequencies
- for ( uint64_t l_port_pos = 0; l_port_pos < PORTS_PER_MCBIST; ++l_port_pos )
- {
- if ( !configured_ports.getBit(l_port_pos) )
- {
- for ( const auto l_freq : NIMBUS_SUPPORTED_FREQS )
- {
- o_vpd_supported_freqs[l_port_pos].push_back(l_freq);
- }
- }
- }
-
- for ( auto& l_freqs : o_vpd_supported_freqs )
- {
- std::sort( l_freqs.begin(), l_freqs.end() );
- }
-
- return fapi2::FAPI2_RC_SUCCESS;
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
-///
-/// @brief Retrieves max frequency each port supports due to DIMM SPD
-/// @param[in] i_target the MCBIST target
-/// @param[out] o_supported_freqs reference to vector of max SPD supported freq for each port
-/// @return FAPI2_RC_SUCCESS iff okay
-///
-fapi2::ReturnCode spd_supported_freq(const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
- std::vector<uint32_t>& o_supported_freqs)
-{
- uint64_t l_largest_tck = 0;
-
- // Start with a really high value so we can use std::min to reduce it below
- o_supported_freqs = std::vector<uint32_t>(PORTS_PER_MCBIST, ~(0));
-
- // Get cached decoder
- std::vector< mss::spd::facade > l_spd_facades;
- FAPI_TRY( get_spd_decoder_list(i_target, l_spd_facades), "%s get decoder - spd", mss::c_str(i_target) );
-
- // Looking for the biggest application period on an MC.
- // This will further reduce supported frequencies the system can run on.
- for ( const auto& l_cache : l_spd_facades )
- {
- const auto l_dimm = l_cache.get_dimm_target();
- const auto l_mca = mss::find_target<TARGET_TYPE_MCA>(l_dimm);
- const auto l_port_pos = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(l_mca);
- uint64_t l_tckmax_in_ps = 0;
- uint64_t l_tck_min_in_ps = 0;
- uint32_t l_dimm_freq = 0;
-
- FAPI_TRY( spd::get_tckmax(l_cache, l_tckmax_in_ps),
- "%s. Failed to get tCKmax", mss::c_str(l_dimm) );
- FAPI_TRY( spd::get_tckmin(l_cache, l_tck_min_in_ps),
- "%s. Failed to get tCKmin", mss::c_str(l_dimm) );
-
- // Determine a proposed tCK value that is greater than or equal tCKmin
- // But less than tCKmax
- l_largest_tck = std::max(l_largest_tck, l_tck_min_in_ps);
- l_largest_tck = std::min(l_largest_tck, l_tckmax_in_ps);
-
- FAPI_TRY( mss::ps_to_freq(l_largest_tck, l_dimm_freq), "%s ps to freq %lu", mss::c_str(i_target), l_largest_tck );
- FAPI_INF("Biggest freq supported from SPD %d MT/s for %s",
- l_dimm_freq, mss::c_str(l_dimm));
-
- o_supported_freqs[l_port_pos] = std::min(l_dimm_freq, o_supported_freqs[l_port_pos]);
- }
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
-///
-/// @brief Create and sort a vector of supported MT/s (freq)
-/// @param[in] i_target MCBIST target for which to get the DIMM configs
-/// @param[out] o_freqs reference to a std::vector to put the sorted vector
-/// @return FAPI2_RC_SUCCESS iff ok
-/// @note Taken from VPD supported freqs. The result is sorted so such that the min
-/// supported freq is std::vector<>.begin and the max is std::vector<>.end - 1. You can
-/// search the resulting vector for valid frequencies as it is sorted.
-///
-fapi2::ReturnCode supported_freqs(const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
- std::vector<uint32_t>& o_freqs)
-{
- o_freqs.clear();
-
- freq_scoreboard l_scoreboard;
- std::vector<uint32_t> l_max_freqs(NUM_MAX_FREQS, 0);
- std::vector<std::vector<uint32_t>> l_vpd_supported_freqs;
- std::vector<uint32_t> l_spd_supported_freq(NUM_MAX_FREQS, 0);
- uint8_t l_req_sync_mode = 0;
- std::vector<uint8_t> l_deconfigured = {0};
-
- // Retrieve system MRW, SPD, and VPD constraints
- FAPI_TRY( mss::max_allowed_dimm_freq(l_max_freqs.data()), "%s max_allowed_dimm_freq", mss::c_str(i_target) );
- FAPI_TRY( spd_supported_freq(i_target, l_spd_supported_freq), "%s spd supported freqs", mss::c_str(i_target) );
- FAPI_TRY( vpd_supported_freqs(i_target, l_vpd_supported_freqs), "%s vpd supported freqs", mss::c_str(i_target) );
-
- // Limit frequency scoreboard according to MRW constraints
- FAPI_TRY( limit_freq_by_mrw(i_target, l_max_freqs, l_scoreboard) );
-
- // Limit frequency scoreboard according to VPD constraints
- FAPI_TRY( limit_freq_by_vpd(i_target, l_vpd_supported_freqs, l_scoreboard) );
-
- // Limit frequency scoreboard according to SPD (DIMM) constraints
- FAPI_TRY( limit_freq_by_spd(i_target, l_spd_supported_freq, l_scoreboard) );
-
- // Callout the fewest number of MCAs to achieve a common shared freq
- FAPI_TRY( mss::required_synch_mode(l_req_sync_mode) );
- FAPI_TRY( l_scoreboard.resolve(i_target,
- l_req_sync_mode == fapi2::ENUM_ATTR_REQUIRED_SYNCH_MODE_ALWAYS,
- l_vpd_supported_freqs,
- l_deconfigured,
- o_freqs) );
-
- FAPI_INF("%s supported freqs:", mss::c_str(i_target));
-
- for (const auto l_freq : o_freqs)
- {
- FAPI_INF("%s %d", mss::c_str(i_target), l_freq);
- }
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
-///
-/// @brief Update supported frequency scoreboard according to MRW/config limits
-/// @param[in] i_target MCBIST target for which to get the DIMM configs
-/// @param[in] i_max_mrw_freqs vector of max allowed freqs
-/// @param[in,out] io_scoreboard scoreboard of MCA targets supporting each frequency
-/// @return FAPI2_RC_SUCCESS iff ok
-/// @note This helper allows us to use the attributes for the main path but
-/// have a path for testing
-///
-fapi2::ReturnCode limit_freq_by_mrw(const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
- const std::vector<uint32_t>& i_max_mrw_freqs,
- freq_scoreboard& io_scoreboard)
-{
- // Indexes into the ATTR_MAX_ALLOWED_DIMM_FREQ arrary. e.g., [0][0] is 1R 1 drop
- constexpr size_t l_indexes[MAX_DIMM_PER_PORT][MAX_PRIMARY_RANKS_PER_PORT] =
- {
- {0, 1, 0xFF, 2},
- {3, 4, 0xFF, 0xFF}
- };
-
- // This is the number of elements in the max_allowed_dimm_freq attribute, not the frequencies of
- // the system.
- FAPI_ASSERT( i_max_mrw_freqs.size() == NUM_MAX_FREQS,
- fapi2::MSS_MAX_FREQ_ATTR_SIZE_CHANGED()
- .set_ACTUAL_SIZE(i_max_mrw_freqs.size())
- .set_SUPPOSED_SIZE(NUM_MAX_FREQS)
- .set_MCA_TARGET(i_target),
- "%s Incorrect number of max frequencies in attribute for (%d)",
- mss::c_str(i_target),
- i_max_mrw_freqs.size());
-
- FAPI_INF("attribute supported max allowed dimm freqs %d %d %d %d %d for %s",
- i_max_mrw_freqs[0], i_max_mrw_freqs[1], i_max_mrw_freqs[2], i_max_mrw_freqs[3], i_max_mrw_freqs[4],
- mss::c_str(i_target));
-
- for( const auto& p : mss::find_targets<fapi2::TARGET_TYPE_MCA>(i_target) )
- {
- const auto l_port_pos = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(p);
- const auto l_dimms = mss::find_targets<TARGET_TYPE_DIMM>(p);
- const uint64_t l_dimms_on_port = l_dimms.size();
-
- // Holds the max freq allowed for this port. This is the minimum of maximum
- // frequencies allowed by the DIMM. So, we start way off the charts so std::min can do the lifting for us.
- uint32_t l_mca_max_freq = ~(0);
-
- FAPI_ASSERT( (l_dimms_on_port <= MAX_DIMM_PER_PORT),
- fapi2::MSS_TOO_MANY_DIMMS_ON_PORT()
- .set_DIMM_COUNT(l_dimms_on_port)
- .set_MCA_TARGET(p),
- "Seeing %d DIMM on port %s",
- l_dimms_on_port,
- mss::c_str(p));
-
- // Find the max supported frequency for this port
- for (const auto& d : l_dimms)
- {
- uint8_t l_num_master_ranks = 0;
- size_t l_index = 0xFF;
-
- FAPI_TRY( mss::eff_num_master_ranks_per_dimm(d, l_num_master_ranks) );
-
- // Just a quick check but we're in deep yogurt if this triggers
- FAPI_ASSERT( (l_num_master_ranks <= MAX_PRIMARY_RANKS_PER_PORT),
- fapi2::MSS_TOO_MANY_PRIMARY_RANKS_ON_DIMM()
- .set_RANK_COUNT(l_num_master_ranks)
- .set_DIMM_TARGET(d),
- "seeing %d primary ranks on DIMM %s",
- l_dimms_on_port,
- mss::c_str(d));
-
- l_index = l_indexes[l_dimms_on_port - 1][l_num_master_ranks - 1];
-
- FAPI_ASSERT( (l_index < NUM_MAX_FREQS),
- fapi2::MSS_FREQ_INDEX_TOO_LARGE()
- .set_INDEX(l_index)
- .set_NUM_MAX_FREQS(NUM_MAX_FREQS),
- "seeing %d index for %d DIMM and %d ranks on DIMM %s",
- l_index,
- l_dimms_on_port,
- l_num_master_ranks,
- mss::c_str(d));
-
- FAPI_INF("%s rank config %d drop %d yields max freq attribute index of %d (%d)",
- mss::c_str(d), l_num_master_ranks, l_dimms_on_port,
- l_indexes[l_dimms_on_port - 1][l_num_master_ranks - 1],
- i_max_mrw_freqs[l_index] );
-
- l_mca_max_freq = std::min(l_mca_max_freq, i_max_mrw_freqs[l_index]);
- }// dimm
-
- // Remove any frequencies bigger than this port's max from the scoreboard
- io_scoreboard.remove_freqs_above_limit(l_port_pos, l_mca_max_freq);
-
- FAPI_INF("%s after processing MRW, max freq is %d", mss::c_str(p), l_mca_max_freq);
- }// mca
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
-///
-/// @brief Update supported frequency scoreboard according to VPD limits
-/// @param[in] i_target MCBIST target for which to get the DIMM configs
-/// @param[in] i_hw_freqs vector of hardware supported freqs -- from VPD
-/// @param[in,out] io_scoreboard scoreboard of MCA targets supporting each frequency
-/// @return FAPI2_RC_SUCCESS iff ok
-/// @note This helper allows us to use the attributes for the main path but
-/// have a path for testing
-///
-fapi2::ReturnCode limit_freq_by_vpd(const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
- const std::vector<std::vector<uint32_t>>& i_hw_freqs,
- freq_scoreboard& io_scoreboard)
-{
- FAPI_ASSERT(i_hw_freqs.size() == PORTS_PER_MCBIST,
- fapi2::MSS_INVALID_VPD_FREQ_LIST_PASSED()
- .set_SIZE(i_hw_freqs.size())
- .set_EXPECTED(PORTS_PER_MCBIST),
- "Wrong size VPD frequency vector passed to limit_freq_by_vpd (got %d, expected %d)",
- i_hw_freqs.size(), PORTS_PER_MCBIST);
-
- for( const auto& p : mss::find_targets<fapi2::TARGET_TYPE_MCA>(i_target) )
- {
- const auto l_port_pos = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(p);
- const auto& l_port_freqs = i_hw_freqs[l_port_pos];
-
- // This is the list of supported frequencies for VPD
- FAPI_ASSERT( !l_port_freqs.empty(),
- fapi2::MSS_EMPTY_VECTOR().
- set_FUNCTION(LIMIT_FREQ_BY_VPD).
- set_TARGET(p),
- "Supported system freqs from VPD are empty for %s",
- mss::c_str(p));
-
- for( const auto& freq : l_port_freqs )
- {
- FAPI_DBG("VPD supported freqs %d for %s", freq, mss::c_str(p) );
- }
-
- // Remove any frequencies that aren't in this port's list from the scoreboard
- io_scoreboard.remove_freqs_not_on_list(l_port_pos, l_port_freqs);
-
- uint32_t l_max_freq = 0;
- FAPI_TRY( io_scoreboard.max_supported_freq(l_port_pos, l_max_freq) );
- FAPI_INF("%s after processing VPD, max freq is %d", mss::c_str(p), l_max_freq);
- }// mca
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
-///
-/// @brief Update supported frequency scoreboard according to SPD limits
-/// @param[in] i_target MCBIST target for which to get the DIMM configs
-/// @param[in] i_hw_freqs vector of hardware supported freqs -- from SPD
-/// @param[in,out] io_scoreboard scoreboard of MCA targets supporting each frequency
-/// @return FAPI2_RC_SUCCESS iff ok
-/// @note This helper allows us to use the attributes for the main path but
-/// have a path for testing
-///
-fapi2::ReturnCode limit_freq_by_spd(const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
- const std::vector<uint32_t>& i_hw_freqs,
- freq_scoreboard& io_scoreboard)
-{
- for( const auto& p : mss::find_targets<fapi2::TARGET_TYPE_MCA>(i_target) )
- {
- const auto l_port_pos = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(p);
-
- // Remove any frequencies that aren't in this port's list from the scoreboard
- io_scoreboard.remove_freqs_above_limit(l_port_pos, i_hw_freqs);
-
- uint32_t l_max_freq = 0;
- FAPI_TRY( io_scoreboard.max_supported_freq(l_port_pos, l_max_freq) );
- FAPI_INF("%s after processing SPD, max freq is %d", mss::c_str(p), l_max_freq);
- }// mca
-
- return fapi2::FAPI2_RC_SUCCESS;
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
-///
-/// @brief Remove frequencies above a limit from the scoreboard
-/// @param[in] i_port_pos position index of port within parent MCBIST
-/// @param[in] i_freq_limit upper limit for frequency
-/// @return FAPI2_RC_SUCCESS if successful
-///
-fapi2::ReturnCode freq_scoreboard::remove_freqs_above_limit(const uint64_t i_port_pos,
- const uint32_t i_freq_limit)
-{
- FAPI_ASSERT(i_port_pos < PORTS_PER_MCBIST,
- fapi2::MSS_INVALID_PORT_INDEX_PASSED()
- .set_INDEX(i_port_pos)
- .set_FUNCTION(ffdc_function_codes::FREQ_SCOREBOARD_REMOVE_FREQS_ABOVE_LIMIT),
- "Invalid port index passed to remove_freqs_above_limit (%d)",
- i_port_pos);
-
- {
- auto& l_port_supported_freqs = iv_freq_mca_supported[i_port_pos];
-
- // Can't do a ranged for loop here because we need the index to get the frequency out of NIMBUS_SUPPORTED_FREQS
- for ( size_t l_index = 0; l_index < l_port_supported_freqs.size(); ++l_index )
- {
- const auto l_scoreboard_freq = NIMBUS_SUPPORTED_FREQS[l_index];
-
- if ( l_scoreboard_freq > i_freq_limit )
- {
- FAPI_INF("Removing freq %d on port %d since it's above the limit %d", l_scoreboard_freq, i_port_pos, i_freq_limit);
- l_port_supported_freqs[l_index] = false;
- }
- }
- }
-
- return fapi2::FAPI2_RC_SUCCESS;
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
-///
-/// @brief Remove frequencies above a limit from the scoreboard
-/// @param[in] i_port_pos position index of port within parent MCBIST
-/// @param[in] i_freq_limits reference to vector of upper limits for frequency per port
-/// @return FAPI2_RC_SUCCESS if successful
-///
-fapi2::ReturnCode freq_scoreboard::remove_freqs_above_limit(const uint64_t i_port_pos,
- const std::vector<uint32_t> i_freq_limits)
-{
- FAPI_ASSERT(i_port_pos < PORTS_PER_MCBIST,
- fapi2::MSS_INVALID_PORT_INDEX_PASSED()
- .set_INDEX(i_port_pos)
- .set_FUNCTION(ffdc_function_codes::FREQ_SCOREBOARD_REMOVE_FREQS_ABOVE_LIMIT_VECTOR),
- "Invalid port index passed to remove_freqs_above_limit (%d)",
- i_port_pos);
-
- FAPI_ASSERT(i_freq_limits.size() == PORTS_PER_MCBIST,
- fapi2::MSS_INVALID_FREQ_LIST_PASSED()
- .set_SIZE(i_freq_limits.size())
- .set_EXPECTED(PORTS_PER_MCBIST),
- "Invalid frequency list passed to remove_freqs_above_limit (size should be %d but got %d)",
- PORTS_PER_MCBIST, i_freq_limits.size());
-
- {
- const auto l_freq_limit = i_freq_limits[i_port_pos];
- FAPI_TRY( this->remove_freqs_above_limit(i_port_pos, l_freq_limit) );
- }
-
- return fapi2::FAPI2_RC_SUCCESS;
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
-///
-/// @brief Remove frequencies not on a given list from the scoreboard
-/// @param[in] i_port_pos position index of port within parent MCBIST
-/// @param[in] i_freq_list vector of supported frequencies
-/// @return FAPI2_RC_SUCCESS if successful
-///
-fapi2::ReturnCode freq_scoreboard::remove_freqs_not_on_list(const uint64_t i_port_pos,
- const std::vector<uint32_t>& i_freq_list)
-{
- FAPI_ASSERT(i_port_pos < PORTS_PER_MCBIST,
- fapi2::MSS_INVALID_PORT_INDEX_PASSED()
- .set_INDEX(i_port_pos)
- .set_FUNCTION(ffdc_function_codes::FREQ_SCOREBOARD_REMOVE_FREQS_NOT_ON_LIST),
- "Invalid port index passed to remove_freqs_not_on_list (%d)",
- i_port_pos);
-
- for ( size_t l_index = 0; l_index < NIMBUS_SUPPORTED_FREQS.size(); ++l_index )
- {
- const auto l_it = std::find(i_freq_list.begin(), i_freq_list.end(), NIMBUS_SUPPORTED_FREQS[l_index]);
-
- if (l_it == i_freq_list.end())
- {
- FAPI_INF("Removing freq %d on port %d since it's not supported", NIMBUS_SUPPORTED_FREQS[l_index], i_port_pos);
- iv_freq_mca_supported[i_port_pos][l_index] = false;
- }
- }
-
- return fapi2::FAPI2_RC_SUCCESS;
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
-///
-/// @brief Return the maximum supported frequency for a given port
-/// @param[in] i_port_pos position index of port within parent MCBIST
-/// @param[out] o_freq max supported frequency
-/// @return FAPI2_RC_SUCCESS if successful
-///
-fapi2::ReturnCode freq_scoreboard::max_supported_freq(const uint64_t i_port_pos,
- uint32_t& o_freq) const
-{
- FAPI_ASSERT(i_port_pos < PORTS_PER_MCBIST,
- fapi2::MSS_INVALID_PORT_INDEX_PASSED()
- .set_INDEX(i_port_pos)
- .set_FUNCTION(ffdc_function_codes::FREQ_SCOREBOARD_MAX_SUPPORTED_FREQ),
- "Invalid port index passed to max_supported_freq (%d)",
- i_port_pos);
-
- {
- std::vector<uint32_t> l_supported_freqs;
- FAPI_TRY( this->supported_freqs(i_port_pos, l_supported_freqs) );
-
- o_freq = l_supported_freqs.empty() ? 0 : l_supported_freqs.back();
- }
-
- return fapi2::FAPI2_RC_SUCCESS;
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
-///
-/// @brief Return a list of supported frequencies for a given port
-/// @param[in] i_port_pos position index of port within parent MCBIST
-/// @param[out] o_freq vector of supported frequencies
-/// @return FAPI2_RC_SUCCESS if successful
-///
-fapi2::ReturnCode freq_scoreboard::supported_freqs(const uint64_t i_port_pos,
- std::vector<uint32_t>& o_freqs) const
-{
- FAPI_ASSERT(i_port_pos < PORTS_PER_MCBIST,
- fapi2::MSS_INVALID_PORT_INDEX_PASSED()
- .set_INDEX(i_port_pos)
- .set_FUNCTION(ffdc_function_codes::FREQ_SCOREBOARD_SUPPORTED_FREQS),
- "Invalid port index passed to supported_freqs (%d)",
- i_port_pos);
-
- {
- o_freqs.clear();
- auto& l_port_supported_freqs = iv_freq_mca_supported[i_port_pos];
-
- for ( size_t l_index = 0; l_index < NIMBUS_SUPPORTED_FREQS.size(); ++l_index )
- {
- if (l_port_supported_freqs[l_index])
- {
- o_freqs.push_back(NIMBUS_SUPPORTED_FREQS[l_index]);
- }
- }
- }
-
- return fapi2::FAPI2_RC_SUCCESS;
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
-///
-/// @brief Resolve frequency scoreboard by deconfiguring any non-conforming ports
-/// and return a list of the supported frequencies
-/// @param[in] i_target MCBIST target
-/// @param[in] i_req_sync_mode bool whether or not we're forced into sync mode
-/// @param[in] i_vpd_supported_freqs vector of hardware supported freqs -- from VPD
-/// @param[out] o_deconfigured vector of port positions that were deconfigured by this function
-/// @param[out] o_freqs vector of frequencies supported by all ports
-/// @return FAPI2_RC_SUCCESS if successful
-///
-fapi2::ReturnCode freq_scoreboard::resolve(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
- const bool i_req_sync_mode,
- const std::vector<std::vector<uint32_t>>& i_vpd_supported_freqs,
- std::vector<uint8_t>& o_deconfigured,
- std::vector<uint32_t>& o_freqs)
-{
- // This vector will hold the number of ports that support each frequency in NIMBUS_SUPPORTED_FREQS
- std::vector<uint64_t> l_support_counts(NIMBUS_SUPPORTED_FREQS.size(), 0);
-
- o_freqs.clear();
- FAPI_INF("%s Attribute required sync mode %d", mss::c_str(i_target), i_req_sync_mode);
-
- const auto l_mcas = mss::find_targets<fapi2::TARGET_TYPE_MCA>(i_target);
- const auto l_port_count = l_mcas.size();
-
- // empty_port_count is the number of MCA that are deconfigured
- // We use it later to make sure our common freq is supported by at least one configured port
- const auto l_empty_port_count = PORTS_PER_MCBIST - l_port_count;
-
- // Get a count of how many ports support each frequency
- for ( size_t l_index = 0; l_index < NIMBUS_SUPPORTED_FREQS.size(); ++l_index )
- {
- size_t l_pos = 0;
-
- for ( const auto& l_supported : iv_freq_mca_supported )
- {
- if (l_supported[l_index])
- {
- FAPI_INF("%s Frequency %d is supported by port%d", mss::c_str(i_target), NIMBUS_SUPPORTED_FREQS[l_index], l_pos);
- // Add this freq if we're not in sync mode, or, if we are, add it if it matches a nest freq
-
- if( i_req_sync_mode && !is_nest_freq_valid(NIMBUS_SUPPORTED_FREQS[l_index]) )
- {
- FAPI_INF("%s Frequency %d is not supported by the nest logic", mss::c_str(i_target), NIMBUS_SUPPORTED_FREQS[l_index]);
- ++l_pos;
- continue;
- }
-
- ++l_support_counts[l_index];
- }
-
- // Add any frequencies supported by all configured ports to our output list
- // Note that deconfigured ports will support all frequencies due to the way the scoreboard is built
- if (l_support_counts[l_index] == PORTS_PER_MCBIST)
- {
- FAPI_INF("%s Frequency %d is supported by all ports", mss::c_str(i_target), NIMBUS_SUPPORTED_FREQS[l_index]);
- o_freqs.push_back(NIMBUS_SUPPORTED_FREQS[l_index]);
- }
-
- ++l_pos;
- }
- }
-
- // If we have at least one common frequency, we're done
- if (!o_freqs.empty())
- {
- return fapi2::FAPI2_RC_SUCCESS;
- }
-
- // If we made it here, that means we don't have a common supported freq for all ports
- // So let's deconfigure the least number of ports to get a common freq
-
- // Find the last instance of the most ports that support a given frequency
- // That way we get the highest frequency supported by the most ports
- // Note: this may be inefficient, but this is a small vector and HB doesn't support reverse iterators
- uint64_t l_common_ports = 0;
- size_t l_best_freq_index = 0;
-
- for ( size_t l_index = 0; l_index < l_support_counts.size(); ++l_index )
- {
- if (l_support_counts[l_index] >= l_common_ports)
- {
- l_common_ports = l_support_counts[l_index];
- l_best_freq_index = l_index;
- }
- }
-
- FAPI_INF("%s Max ports supporting a common frequency is %d", mss::c_str(i_target), l_common_ports);
- FAPI_INF("%s Fastest common frequency is %d", mss::c_str(i_target), NIMBUS_SUPPORTED_FREQS[l_best_freq_index]);
-
- // Assert if we don't have any frequencies supported by at least one configured port
- // Note: we know max_allowed_dimm_freq is size 5 because we checked it in limit_freq_by_mrw
- std::vector<uint32_t> l_max_mrw_freqs(NUM_MAX_FREQS, 0);
- FAPI_TRY( mss::max_allowed_dimm_freq(l_max_mrw_freqs.data()) );
- FAPI_ASSERT(l_common_ports > l_empty_port_count,
- fapi2::MSS_NO_SUPPORTED_FREQ()
- .set_REQUIRED_SYNC_MODE(i_req_sync_mode)
- .set_MCBIST_TARGET(i_target)
- .set_NUM_PORTS(l_port_count)
- .set_MRW_MAX_FREQ_0(l_max_mrw_freqs[0])
- .set_MRW_MAX_FREQ_1(l_max_mrw_freqs[1])
- .set_MRW_MAX_FREQ_2(l_max_mrw_freqs[2])
- .set_MRW_MAX_FREQ_3(l_max_mrw_freqs[3])
- .set_MRW_MAX_FREQ_4(l_max_mrw_freqs[4]),
- "%s didn't find a frequency that was supported on any ports", mss::c_str(i_target));
-
- // Now find and deconfigure all ports that don't support our selected frequency
- o_deconfigured.clear();
-
- for ( size_t l_pos = 0; l_pos < PORTS_PER_MCBIST; ++l_pos )
- {
- // Find the MCA with this position
- const auto l_it_mca = std::find_if(l_mcas.begin(),
- l_mcas.end(),
- [l_pos]( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_rhs) -> bool
- {
- return (mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(i_rhs) != l_pos);
- });
-
- // If we didn't find an MCA for a given position, there wasn't one configured there
- if (l_it_mca == l_mcas.end())
- {
- continue;
- }
-
- // and call it out if it doesn't support the selected freq
- const auto& p = *l_it_mca;
- FAPI_INF("Checking if port %d (%s) supports common frequency", l_pos, mss::c_str(p));
-
- if (!iv_freq_mca_supported[l_pos][l_best_freq_index])
- {
- FAPI_INF("Port %d (%s) does not support the common frequency so will be deconfigured", l_pos, mss::c_str(p));
- auto& l_port_supported_freqs = iv_freq_mca_supported[l_pos];
-
- o_deconfigured.push_back(l_pos);
- FAPI_ASSERT_NOEXIT( false,
- fapi2::MSS_PORT_DOES_NOT_SUPPORT_MAJORITY_FREQ()
- .set_MCBIST_TARGET(i_target)
- .set_MCA_TARGET(p)
- .set_FREQUENCY(NIMBUS_SUPPORTED_FREQS[l_best_freq_index]),
- "%s does not support the majority frequency (%d) so will be deconfigured",
- mss::c_str(p), NIMBUS_SUPPORTED_FREQS[l_best_freq_index] );
-
- // Now mark all frequencies as supported by that port since it was deconfigured
- for ( size_t l_index = 0; l_index < l_port_supported_freqs.size(); ++l_index )
- {
- l_port_supported_freqs[l_index] = true;
- }
- }
- }
-
- // Now find all the frequencies supported by the ports that are left over
- FAPI_TRY(this->resolve(i_target, i_req_sync_mode, i_vpd_supported_freqs, o_deconfigured, o_freqs));
-
-#ifndef __HOSTBOOT_MODULE
-
- // Cronus doesn't deconfigure, so let's bail out if we didn't find a common frequency
- if (!o_deconfigured.empty())
- {
- std::vector<uint32_t> l_port_vpd_max_freq;
-
- {
- // Get the max freq supported on each port
- for ( const auto& l_port_supported_freqs : i_vpd_supported_freqs )
- {
- l_port_vpd_max_freq.push_back(l_port_supported_freqs.back());
- }
-
- FAPI_ASSERT(false,
- fapi2::MSS_MRW_FREQ_MAX_FREQ_EMPTY_SET()
- .set_MSS_VPD_FREQ_0(l_port_vpd_max_freq[0])
- .set_MSS_VPD_FREQ_1(l_port_vpd_max_freq[1])
- .set_MSS_VPD_FREQ_2(l_port_vpd_max_freq[2])
- .set_MSS_VPD_FREQ_3(l_port_vpd_max_freq[3])
- .set_MSS_MAX_FREQ_0(l_max_mrw_freqs[0])
- .set_MSS_MAX_FREQ_1(l_max_mrw_freqs[1])
- .set_MSS_MAX_FREQ_2(l_max_mrw_freqs[2])
- .set_MSS_MAX_FREQ_3(l_max_mrw_freqs[3])
- .set_MSS_MAX_FREQ_4(l_max_mrw_freqs[4])
- .set_MSS_NEST_FREQ_0(fapi2::ENUM_ATTR_FREQ_PB_MHZ_1600)
- .set_MSS_NEST_FREQ_1(fapi2::ENUM_ATTR_FREQ_PB_MHZ_1866)
- .set_MSS_NEST_FREQ_2(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2000)
- .set_MSS_NEST_FREQ_3(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2133)
- .set_MSS_NEST_FREQ_4(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2400)
- .set_REQUIRED_SYNC_MODE(i_req_sync_mode)
- .set_MCBIST_TARGET(i_target),
- "%s didn't find a common frequency for all ports", mss::c_str(i_target));
- }
- }
-
-#endif
-
- return fapi2::FAPI2_RC_SUCCESS;
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
}// mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.H b/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.H
index 4e46f0b1e..7a780c310 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.H
@@ -40,23 +40,21 @@
#include <fapi2.H>
#include <lib/shared/mss_const.H>
+#include <generic/memory/lib/utils/freq/mss_freq_scoreboard.H>
+#include <generic/memory/lib/utils/c_str.H>
namespace mss
{
-enum class speed_equality : uint8_t
-{
- NOT_EQUAL_DIMM_SPEEDS = 0, ///< denotes all DIMMs don't have the same speed
- EQUAL_DIMM_SPEEDS = 1, ///< denotes all DIMMs have the same speed
-};
-
-// DDR4 speed NIMBUS supports
-static const std::vector<uint32_t> NIMBUS_SUPPORTED_FREQS =
+// List of the nest frequencies for nimbus
+// Note: these need to be sorted so binary search works
+static const std::vector<uint64_t> NIMBUS_NEST_FREQS =
{
- fapi2::ENUM_ATTR_MSS_FREQ_MT1866,
- fapi2::ENUM_ATTR_MSS_FREQ_MT2133,
- fapi2::ENUM_ATTR_MSS_FREQ_MT2400,
- fapi2::ENUM_ATTR_MSS_FREQ_MT2666,
+ fapi2::ENUM_ATTR_FREQ_PB_MHZ_1600,
+ fapi2::ENUM_ATTR_FREQ_PB_MHZ_1866,
+ fapi2::ENUM_ATTR_FREQ_PB_MHZ_2000,
+ fapi2::ENUM_ATTR_FREQ_PB_MHZ_2133,
+ fapi2::ENUM_ATTR_FREQ_PB_MHZ_2400
};
///
@@ -66,102 +64,13 @@ static const std::vector<uint32_t> NIMBUS_SUPPORTED_FREQS =
///
inline bool is_nest_freq_valid (const uint64_t i_proposed_freq)
{
- std::vector<uint64_t> l_nest_freqs_supported = { fapi2::ENUM_ATTR_FREQ_PB_MHZ_1600,
- fapi2::ENUM_ATTR_FREQ_PB_MHZ_1866,
- fapi2::ENUM_ATTR_FREQ_PB_MHZ_2000,
- fapi2::ENUM_ATTR_FREQ_PB_MHZ_2133,
- fapi2::ENUM_ATTR_FREQ_PB_MHZ_2400
- };
-
- std::sort(l_nest_freqs_supported.begin(), l_nest_freqs_supported.end());
- return ( std::binary_search(l_nest_freqs_supported.begin(), l_nest_freqs_supported.end(), i_proposed_freq) );
+ return ( std::binary_search(NIMBUS_NEST_FREQS.begin(), NIMBUS_NEST_FREQS.end(), i_proposed_freq) );
}
-///
-/// @class freq_scoreboard
-/// @brief class that encapsulates MCA supported frequencies
-///
-class freq_scoreboard
+enum class speed_equality : uint8_t
{
- public:
- ///
- /// @brief Create a new frequency scoreboard
- ///
- freq_scoreboard()
- {
- iv_freq_mca_supported = std::vector<std::vector<bool>>(PORTS_PER_MCBIST,
- std::vector<bool>(NIMBUS_SUPPORTED_FREQS.size(), true));
- }
-
- ///
- /// @brief default destructor
- ///
- ~freq_scoreboard() = default;
-
- ///
- /// @brief Remove frequencies above a limit from the scoreboard
- /// @param[in] i_port_pos position index of port within parent MCBIST
- /// @param[in] i_freq_limit upper limit for frequency
- /// @return FAPI2_RC_SUCCESS if successful
- ///
- fapi2::ReturnCode remove_freqs_above_limit(const uint64_t i_port_pos,
- const uint32_t i_freq_limit);
-
- ///
- /// @brief Remove frequencies above a limit from the scoreboard
- /// @param[in] i_port_pos position index of port within parent MCBIST
- /// @param[in] i_freq_limits reference to vector of upper limits for frequency per port
- /// @return FAPI2_RC_SUCCESS if successful
- ///
- fapi2::ReturnCode remove_freqs_above_limit(const uint64_t i_port_pos,
- const std::vector<uint32_t> i_freq_limits);
-
- ///
- /// @brief Remove frequencies not on a given list from the scoreboard
- /// @param[in] i_port_pos position index of port within parent MCBIST
- /// @param[in] i_freq_list vector of supported frequencies
- /// @return FAPI2_RC_SUCCESS if successful
- ///
- fapi2::ReturnCode remove_freqs_not_on_list(const uint64_t i_port_pos,
- const std::vector<uint32_t>& i_freq_list);
-
- ///
- /// @brief Return the maximum supported frequency for a given port
- /// @param[in] i_port_pos position index of port within parent MCBIST
- /// @param[out] o_freq max supported frequency
- /// @return FAPI2_RC_SUCCESS if successful
- ///
- fapi2::ReturnCode max_supported_freq(const uint64_t i_port_pos,
- uint32_t& o_freq) const;
-
- ///
- /// @brief Return a list of supported frequencies for a given port
- /// @param[in] i_port_pos position index of port within parent MCBIST
- /// @param[out] o_freq vector of supported frequencies
- /// @return FAPI2_RC_SUCCESS if successful
- ///
- fapi2::ReturnCode supported_freqs(const uint64_t i_port_pos,
- std::vector<uint32_t>& o_freqs) const;
-
- ///
- /// @brief Resolve frequency scoreboard by deconfiguring any non-conforming ports
- /// and return a list of the supported frequencies
- /// @param[in] i_target MCBIST target
- /// @param[in] i_req_sync_mode bool whether or not we're forced into sync mode
- /// @param[in] i_vpd_supported_freqs vector of hardware supported freqs -- from VPD
- /// @param[out] o_deconfigured vector of port positions that were deconfigured by this function
- /// @param[out] o_freqs vector of frequencies supported by all ports
- /// @return FAPI2_RC_SUCCESS if successful
- ///
- fapi2::ReturnCode resolve(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
- const bool i_req_sync_mode,
- const std::vector<std::vector<uint32_t>>& i_vpd_supported_freqs,
- std::vector<uint8_t>& o_deconfigured,
- std::vector<uint32_t>& o_freqs);
-
- private:
- std::vector<std::vector<bool>> iv_freq_mca_supported;
-
+ NOT_EQUAL_DIMM_SPEEDS = 0, ///< denotes all DIMMs don't have the same speed
+ EQUAL_DIMM_SPEEDS = 1, ///< denotes all DIMMs have the same speed
};
///
@@ -204,76 +113,36 @@ fapi2::ReturnCode select_sync_mode(const std::map< fapi2::Target<fapi2::TARGET_T
uint64_t& o_selected_freq);
///
-/// @brief Create a vector of support freq based on VPD config
-/// @param[in] i_target MCBIST target for which to get the DIMM configs
-/// @param[out] reference to a 2 dimensional std::vector of supported VPD frequencies for each MCA
-/// @return FAPI2_RC_SUCCESS iff ok
-///
-fapi2::ReturnCode vpd_supported_freqs( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
- std::vector<std::vector<uint32_t>>& o_vpd_supported_freqs);
-
-///
-/// @brief Retrieves max frequency each port supports due to DIMM SPD
-/// @param[in] i_target the MCBIST target
-/// @param[out] o_supported_freqs reference to vector of max SPD supported freq for each port
-/// @return FAPI2_RC_SUCCESS iff okay
-///
-fapi2::ReturnCode spd_supported_freq(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
- std::vector<uint32_t>& o_supported_freqs);
-
-///
-/// @brief Create and sort a vector of supported MT/s (freq)
-/// @param[in] i_target MCA target for which to get the DIMM configs
-/// @param[out] o_freqs reference to a std::vector to put the sorted vector
-/// @return FAPI2_RC_SUCCESS iff ok
-/// @note Taken from VPD supported freqs. The result is sorted so such that the min
-/// supported freq is std::vector<>.begin and the max is std::vector<>.end - 1. You can
-/// search the resulting vector for valid frequencies as it is sorted.
-///
-fapi2::ReturnCode supported_freqs(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
- std::vector<uint32_t>& o_freqs);
-
-///
-/// @brief Update supported frequency scoreboard according to MRW/config limits
-/// @param[in] i_target MCBIST target for which to get the DIMM configs
-/// @param[in] i_max_mrw_freqs vector of max allowed freqs
-/// @param[in,out] io_scoreboard scoreboard of MCA targets supporting each frequency
-/// @return FAPI2_RC_SUCCESS iff ok
-/// @note the attributes which drive this are read-only so they're hard to change when
-/// testing. So this helper allows us to use the attributes for the main path but
-/// have a path for testing
-///
-fapi2::ReturnCode limit_freq_by_mrw(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
- const std::vector<uint32_t>& i_max_mrw_freqs,
- freq_scoreboard& io_scoreboard);
-
-///
-/// @brief Update supported frequency scoreboard according to VPD limits
-/// @param[in] i_target MCBIST target for which to get the DIMM configs
-/// @param[in] i_hw_freqs vector of hardware supported freqs -- from VPD
-/// @param[in,out] io_scoreboard scoreboard of MCA targets supporting each frequency
-/// @return FAPI2_RC_SUCCESS iff ok
-/// @note the attributes which drive this are read-only so they're hard to change when
-/// testing. So this helper allows us to use the attributes for the main path but
-/// have a path for testing
-///
-fapi2::ReturnCode limit_freq_by_vpd(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
- const std::vector<std::vector<uint32_t>>& i_hw_freqs,
- freq_scoreboard& io_scoreboard);
-
-///
-/// @brief Update supported frequency scoreboard according to SPD limits
-/// @param[in] i_target MCBIST target for which to get the DIMM configs
-/// @param[in] i_hw_freqs vector of hardware supported freqs -- from SPD
-/// @param[in,out] io_scoreboard scoreboard of MCA targets supporting each frequency
+/// @brief Update supported frequency scoreboard according to whether the processor is in sync mode or not
+/// @param[in] i_target processor frequency domain
+/// @param[in,out] io_scoreboard scoreboard of port targets supporting each frequency
/// @return FAPI2_RC_SUCCESS iff ok
/// @note the attributes which drive this are read-only so they're hard to change when
/// testing. So this helper allows us to use the attributes for the main path but
/// have a path for testing
///
-fapi2::ReturnCode limit_freq_by_spd(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
- const std::vector<uint32_t>& i_hw_freqs,
- freq_scoreboard& io_scoreboard);
+inline fapi2::ReturnCode limit_freq_by_processor(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
+ const bool i_sync_mode,
+ freq_scoreboard& io_scoreboard)
+{
+ // If we're not in sync mode, just exit
+ if(!i_sync_mode)
+ {
+ FAPI_INF("%s is not in sync mode, skipping the sync mode check", mss::c_str(i_target));
+ return fapi2::FAPI2_RC_SUCCESS;
+ }
+
+ // Loop through all potential ports
+ for(uint64_t l_port_pos = 0; l_port_pos < PORTS_PER_MCBIST; ++l_port_pos)
+ {
+ FAPI_TRY(io_scoreboard.remove_freqs_not_on_list(l_port_pos, NIMBUS_NEST_FREQS));
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
}// mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H b/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H
index 04c84f68c..8238a888c 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H
@@ -69,7 +69,6 @@ enum sizes
MAX_DRAMS_X4 = MAX_DQ_BITS / BITS_PER_NIBBLE, ///< For x4's there are 18 DRAM for 72 bits
NUM_MRW_FREQS = 4, ///< Used for ATTR_MSS_MRW_SUPPORTED_FREQ
- NUM_MAX_FREQS = 5, ///< Used for ATTR_MAX_ALLOWED_DIMM_FREQ
MARK_STORE_COUNT = 8, ///< Elements in a VPD mark/store array
@@ -195,14 +194,6 @@ enum ffdc_function_codes
// WR VREF functions
DRAM_TO_RP_REG = 101,
- // mss_freq functions
- FREQ_SCOREBOARD_REMOVE_FREQS_ABOVE_LIMIT = 110,
- FREQ_SCOREBOARD_REMOVE_FREQS_ABOVE_LIMIT_VECTOR = 111,
- FREQ_SCOREBOARD_REMOVE_FREQS_NOT_ON_LIST = 112,
- FREQ_SCOREBOARD_MAX_SUPPORTED_FREQ = 113,
- FREQ_SCOREBOARD_SUPPORTED_FREQS = 114,
- LIMIT_FREQ_BY_VPD = 115,
-
// eff_dimm.C
PRIMARY_STACK_TYPE = 116,
};
diff --git a/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C b/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C
index d66924504..34eae3e9b 100644
--- a/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C
+++ b/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C
@@ -45,16 +45,8 @@
#include <fapi2.H>
// mss lib
-#include <generic/memory/lib/spd/spd_facade.H>
-#include <generic/memory/lib/utils/freq/cas_latency.H>
-#include <lib/freq/sync.H>
-#include <lib/workarounds/freq_workarounds.H>
-#include <generic/memory/lib/utils/c_str.H>
-#include <generic/memory/lib/utils/find.H>
#include <generic/memory/lib/utils/count_dimm.H>
-#include <generic/memory/lib/utils/index.H>
-#include <lib/shared/mss_const.H>
-#include <lib/eff_config/attr_setters.H>
+#include <generic/memory/lib/utils/freq/gen_mss_freq.H>
using fapi2::TARGET_TYPE_MCS;
using fapi2::TARGET_TYPE_MCA;
@@ -81,11 +73,6 @@ extern "C"
// twice for every MC. However, attribute access is cheap so this will suffice for
// the time being.
const auto l_mcbist = mss::find_target<fapi2::TARGET_TYPE_MCBIST>(i_target);
- std::vector< std::vector<uint64_t> > l_min_dimm_freq(mss::MCS_PER_MC, std::vector<uint64_t> (mss::PORTS_PER_MCS, 0) );
- std::vector<uint32_t> l_supported_freqs;
-
- uint64_t l_mss_freq = 0;
- uint32_t l_nest_freq = 0;
// If there are no DIMM, we can just get out.
if (mss::count_dimm(l_mcbist) == 0)
@@ -94,98 +81,7 @@ extern "C"
return FAPI2_RC_SUCCESS;
}
- // We will first set pre-eff_config attributes
- for( const auto& d : mss::find_targets<fapi2::TARGET_TYPE_DIMM>(l_mcbist))
- {
- std::vector<uint8_t> l_raw_spd;
- FAPI_TRY(mss::spd::get_raw_data(d, l_raw_spd));
-
- {
- fapi2::ReturnCode l_rc(fapi2::FAPI2_RC_SUCCESS);
- mss::spd::facade l_spd_decoder(d, l_raw_spd, l_rc);
-
- FAPI_TRY(l_rc, "Failed to initialize SPD facade for %s", mss::spd::c_str(d));
- FAPI_TRY(mss::set_pre_init_attrs(d, l_spd_decoder), "%s failed to set pre init attrs", mss::c_str(d) );
- }
- }
-
- // Get supported freqs for this MCBIST
- FAPI_TRY( mss::supported_freqs(l_mcbist, l_supported_freqs), "%s failed to get supported frequencies",
- mss::c_str(i_target) );
-
- for (const auto& l_mcs : mss::find_targets<TARGET_TYPE_MCS>(l_mcbist))
- {
- const auto l_mcs_index = mss::index(l_mcs);
-
- std::vector< std::pair< uint64_t, fapi2::Target<fapi2::TARGET_TYPE_MCA>> > l_desired_cas_latency;
-
- for (const auto& l_mca : mss::find_targets<TARGET_TYPE_MCA>(l_mcs) )
- {
- const auto l_mca_index = mss::index(l_mca);
- fapi2::ReturnCode l_rc;
-
- // Get cached decoder
- std::vector< mss::spd::facade > l_spd_facades;
- FAPI_TRY( get_spd_decoder_list(l_mca, l_spd_facades) );
-
- // Instantiation of class that calculates CL algorithm
- mss::cas_latency<mss::mc_type::NIMBUS> l_cas_latency( l_mca, l_spd_facades, l_supported_freqs, l_rc );
-
- FAPI_TRY( l_rc, "%s. Failed to initialize cas_latency ctor", mss::c_str(l_mca) );
-
- if(l_cas_latency.iv_dimm_list_empty)
- {
- // Cannot fail out for an empty DIMM configuration, so default values are set
- FAPI_INF("%s. DIMM list is empty! Setting default values for CAS latency and DIMM speed.",
- mss::c_str(l_mca) );
- }
-
- else
- {
- // We set this to a non-0 so we avoid divide-by-zero errors in the conversions which
- // go from clocks to time (and vice versa.) We have other bugs if there was really
- // no MT/s determined and there really is a DIMM installed, so this is ok.
- // We pick the maximum frequency supported by the system as the default.
- uint64_t l_desired_cl = 0;
-
- l_min_dimm_freq[l_mcs_index][l_mca_index] = fapi2::ENUM_ATTR_MSS_FREQ_MT2666;
-
- uint64_t l_tCKmin = 0;
-
- // Find CAS latency using JEDEC algorithm
- FAPI_TRY( l_cas_latency.find_cl(l_desired_cl, l_tCKmin), "%s failed to find a cas latency", mss::c_str(i_target) );
-
- FAPI_INF("%s. Result from CL algorithm, CL (nck): %d, tCK (ps): %d",
- mss::c_str(l_mca), l_desired_cl, l_tCKmin);
-
- l_desired_cas_latency.push_back(std::make_pair(l_desired_cl, l_mca) );
-
- // Find dimm transfer speed from selected tCK
- FAPI_TRY( mss::ps_to_freq(l_tCKmin, l_min_dimm_freq[l_mcs_index][l_mca_index]),
- "%s. Failed ps_to_freq()", mss::c_str(l_mca) );
-
- FAPI_INF("DIMM speed from selected tCK (ps): %d for %s",
- l_min_dimm_freq[l_mcs_index][l_mca_index],
- mss::c_str(l_mca));
-
- FAPI_INF("%s. Selected DIMM speed from supported speeds: %d",
- mss::c_str(l_mca), l_min_dimm_freq[l_mcs_index][l_mca_index]);
-
- }// end else
- } // mca
-
- FAPI_TRY(mss::set_CL_attr(l_mcs, l_desired_cas_latency),
- "%s. Failed set_CL_attr()", mss::c_str(i_target) );
-
- } // close for each mcs
-
- FAPI_TRY(mss::set_freq_attrs(l_mcbist, l_min_dimm_freq),
- "%s. Failed set_freq_attrs()", mss::c_str(i_target) );
-
- // Check MEM/NEST frequency ratio
- FAPI_TRY( mss::freq_pb_mhz(l_nest_freq) );
- FAPI_TRY( mss::freq(l_mcbist, l_mss_freq) );
- FAPI_TRY( mss::workarounds::check_dimm_nest_freq_ratio(l_mcbist, l_mss_freq, l_nest_freq) );
+ FAPI_TRY(mss::generate_freq<mss::proc_type::NIMBUS>(l_mcbist));
fapi_try_exit:
return fapi2::current_err;
diff --git a/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H b/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H
index 3131dc541..f66257ae0 100644
--- a/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H
+++ b/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H
@@ -37,123 +37,6 @@
#define MSS_FREQ_H_
#include <utility>
#include <fapi2.H>
-#include <lib/shared/mss_const.H>
-#include <lib/utils/mss_nimbus_conversions.H>
-
-namespace mss
-{
-
-///
-/// @brief Sets DRAM CAS latency attributes
-/// @param[in] i_target the controller target the cas_latency vector is for
-/// @param[in] i_cas_latency vector of pairs. Contains the two final selected CAS latencies
-/// @return FAPI2_RC_SUCCESS iff ok
-///
-inline fapi2::ReturnCode set_CL_attr(const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target,
- const std::vector< std::pair< uint64_t, fapi2::Target<fapi2::TARGET_TYPE_MCA>> >& i_cas_latency)
-{
- // I wish I could do the reinterpret cast or set the pointer to the vector :(
- // But no can do, manual copy pasta
- uint8_t l_temp [mss::PORTS_PER_MCS] = {0};
-
- for( const auto& cl : i_cas_latency )
- {
- // Local variable instead of calling it three times. Hopefully compiler can optimize this better
- const auto l_index = mss::index(cl.second);
-
- if ( l_index >= PORTS_PER_MCS)
- {
- FAPI_ERR("%s mss::index returned a value greater than PORTS_PER_MCS", mss::c_str(i_target) );
- fapi2::Assert(false);
- }
-
- l_temp[l_index] = cl.first;
-
- //Check for rounding issues. Going from a uint64_t to a uint8_t
- FAPI_ASSERT( l_temp[l_index] == cl.first,
- fapi2::MSS_BAD_CL_CAST()
- .set_CL(cl.first)
- .set_MCA_TARGET(cl.second),
- "%s bad cast for cas latency from %d to %d",
- mss::c_str(cl.second),
- cl.first,
- l_temp[l_index]);
-
- FAPI_INF( "Final Chosen CL: %d for %s", l_temp[l_index], mss::c_str(cl.second));
- }
-
- // set CAS latency attribute
- // casts vector into the type FAPI_ATTR_SET is expecting by deduction
- FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_CL,
- i_target,
- l_temp) ,
- "Failed to set CAS latency attribute");
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
-///
-/// @brief Sets frequency attributes
-/// @param[in] i_target the controller target
-/// @param[in] i_dimm_freq vector of freqs selected dimm freq in MT/s
-/// @return FAPI2_RC_SUCCESS iff ok
-///
-inline fapi2::ReturnCode set_freq_attrs(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
- const std::vector< std::vector<uint64_t> >& i_dimm_freq)
-{
- // Find the minimum (but non-0) freq in the vector. If we see all 0's we'll write a 0. However,
- // we shouldn't as the caller should have been dealing with no DIMM before we got here.
- uint64_t l_final_freq = UINT64_MAX;
-
- // DDR4 speed NIMBUS supports
- std::vector<uint64_t> l_supported = { 0,
- fapi2::ENUM_ATTR_MSS_FREQ_MT1866,
- fapi2::ENUM_ATTR_MSS_FREQ_MT2133,
- fapi2::ENUM_ATTR_MSS_FREQ_MT2400,
- fapi2::ENUM_ATTR_MSS_FREQ_MT2666,
- };
-
- std::sort( l_supported.begin(), l_supported.end() );
-
- for (const auto l_vec : i_dimm_freq)
- {
- for (const auto l_freq : l_vec)
- {
- if (l_freq != 0)
- {
- l_final_freq = std::min(l_final_freq, l_freq);
- }
- }
- }
-
- // If we saw all 0's, write a 0.
- l_final_freq = (l_final_freq == UINT64_MAX) ? 0 : l_final_freq;
-
- // Shouldn't be getting 0 here. There have to be DIMMs installed for this code to be executed
- // The code would have errored out before if a frequency wasn't found.
- FAPI_ASSERT( std::binary_search(l_supported.begin(), l_supported.end(), l_final_freq),
- fapi2::MSS_BAD_FREQ_CALCULATED()
- .set_MSS_FREQ(l_final_freq)
- .set_MCBIST_TARGET(i_target)
- .set_SUPPORTED_FREQ_0(fapi2::ENUM_ATTR_MSS_FREQ_MT1866)
- .set_SUPPORTED_FREQ_1(fapi2::ENUM_ATTR_MSS_FREQ_MT2133)
- .set_SUPPORTED_FREQ_2(fapi2::ENUM_ATTR_MSS_FREQ_MT2400)
- .set_SUPPORTED_FREQ_3(fapi2::ENUM_ATTR_MSS_FREQ_MT2666),
- "%s: Calculated FREQ (%d) isn't supported",
- mss::c_str(i_target),
- l_final_freq);
-
- FAPI_INF( "Final Chosen Frequency: %d (%s)", l_final_freq, mss::c_str(i_target) );
-
- FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_MSS_FREQ, i_target, l_final_freq),
- "Failed to set mss freq attribute");
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
-}// mss namespace
typedef fapi2::ReturnCode (*p9_mss_freq_FP_t) (const fapi2::Target<fapi2::TARGET_TYPE_MCS>&);
diff --git a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_freq.xml b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_freq.xml
index eeb104b2a..8eac08abd 100644
--- a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_freq.xml
+++ b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_freq.xml
@@ -81,24 +81,6 @@
</deconfigure>
</hwpError>
- <hwpError>
- <rc>RC_MSS_BAD_FREQ_CALCULATED</rc>
- <description>
- No frequency found for mbist. Either bad mrw attribute or no DIMMS installed?
- Should be a code bug if we get here
- </description>
- <ffdc>MSS_FREQ</ffdc>
- <ffdc>SUPPORTED_FREQ_0</ffdc>
- <ffdc>SUPPORTED_FREQ_1</ffdc>
- <ffdc>SUPPORTED_FREQ_2</ffdc>
- <ffdc>SUPPORTED_FREQ_3</ffdc>
- <ffdc>MCBIST_TARGET</ffdc>
- <callout>
- <procedure>CODE</procedure>
- <priority>HIGH</priority>
- </callout>
- </hwpError>
-
<!-- Cronus only error when we can't match DIMM speeds to sync mode -->
<hwpError>
<rc>RC_MSS_FAILED_SYNC_MODE</rc>
@@ -284,25 +266,6 @@
</hwpError>
<hwpError>
- <rc>RC_MSS_PORT_DOES_NOT_SUPPORT_MAJORITY_FREQ</rc>
- <description>
- When considering the frequencies in the MRW and the max supported
- frequencies based on DIMM config, the indicated port's DIMM do not support
- the frequency of the majority of other ports' DIMM, so it will be deconfigured
- </description>
- <ffdc>MCBIST_TARGET</ffdc>
- <ffdc>MCA_TARGET</ffdc>
- <ffdc>FREQUENCY</ffdc>
- <callout>
- <childTargets>
- <parent>MCA_TARGET</parent>
- <childType>TARGET_TYPE_DIMM</childType>
- </childTargets>
- <priority>MEDIUM</priority>
- </callout>
- </hwpError>
-
- <hwpError>
<rc>RC_MSS_TOO_MANY_DIMMS_ON_PORT</rc>
<description>There seem to be too many dimms on the port</description>
<ffdc>DIMM_COUNT</ffdc>
diff --git a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_general_errors.xml b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_general_errors.xml
index 4460b4008..7264ed78f 100644
--- a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_general_errors.xml
+++ b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_general_errors.xml
@@ -36,23 +36,6 @@
<hwpErrors>
- <hwpError>
- <rc>RC_MSS_LOOKUP_FAILED</rc>
- <description>
- Conditional that tests whether a certain key value is located in a map.
- </description>
- <ffdc>KEY</ffdc>
- <ffdc>DATA</ffdc>
- <ffdc>FUNCTION</ffdc>
- <callout>
- <target>TARGET</target>
- <priority>MEDIUM</priority>
- </callout>
- <deconfigure>
- <target>TARGET</target>
- </deconfigure>
- </hwpError>
-
<hwpError>
<rc>RC_MSS_INVALID_RTT_WR_ENCODING</rc>
<description>
diff --git a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_lib.xml b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_lib.xml
index 3fded77c7..2ac4628c8 100644
--- a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_lib.xml
+++ b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_lib.xml
@@ -496,17 +496,6 @@
</hwpError>
<hwpError>
- <rc>RC_MSS_INVALID_PORT_INDEX_PASSED</rc>
- <description>An invalid port index was passed into an MSS function</description>
- <ffdc>INDEX</ffdc>
- <ffdc>FUNCTION</ffdc>
- <callout>
- <procedure>CODE</procedure>
- <priority>HIGH</priority>
- </callout>
- </hwpError>
-
- <hwpError>
<rc>RC_MSS_C4_PIN_OUT_OF_RANGE</rc>
<description>Indicates a fail when attempting to get a PHY mapping for an out-of-bounds module C4 pin index</description>
<ffdc>MCA_TARGET</ffdc>
diff --git a/src/import/generic/memory/lib/data_engine/pre_data_init.H b/src/import/generic/memory/lib/data_engine/pre_data_init.H
index aa061a530..2daea4c15 100644
--- a/src/import/generic/memory/lib/data_engine/pre_data_init.H
+++ b/src/import/generic/memory/lib/data_engine/pre_data_init.H
@@ -68,281 +68,6 @@ template< proc_type T, pre_data_init_fields TT >
class preDataInitTraits;
///
-/// @brief Traits for pre_data_engine
-/// @class preDataInitTraits
-/// @note NIMBUS, DIMM_TYPE specialization
-///
-template<>
-class preDataInitTraits<NIMBUS, DIMM_TYPE>
-{
- public:
- using attr_type = fapi2::ATTR_EFF_DIMM_TYPE_Type;
- static const fapi2::TargetType TARGET_TYPE = fapi2::ATTR_EFF_DIMM_TYPE_TargetType;
-
- ///
- /// @brief attribute getter
- /// @param[in] i_target the MCS target
- /// @param[out] o_setting array to populate
- /// @return FAPI2_RC_SUCCESS iff okay
- ///
- static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
- attr_type& o_setting)
- {
- FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_EFF_DIMM_TYPE, i_target, o_setting) );
-
- fapi_try_exit:
- return fapi2::current_err;
- }
-
- ///
- /// @brief attribute setter
- /// @param[in] i_target the MCS target
- /// @param[in] i_setting array to set
- /// @return FAPI2_RC_SUCCESS iff okay
- ///
- static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
- const attr_type& i_setting)
- {
- attr_type l_data = {};
- memcpy(l_data, i_setting, sizeof(l_data));
- FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_TYPE, i_target, l_data) );
-
- fapi_try_exit:
- return fapi2::current_err;
- }
-};
-
-///
-/// @brief Traits for pre_data_engine
-/// @class preDataInitTraits
-/// @note NIMBUS, DRAM_GEN specialization
-///
-template<>
-class preDataInitTraits<NIMBUS, DRAM_GEN>
-{
- public:
- using attr_type = fapi2::ATTR_EFF_DRAM_GEN_Type;
- static const fapi2::TargetType TARGET_TYPE = fapi2::ATTR_EFF_DRAM_GEN_TargetType;
-
- ///
- /// @brief attribute getter
- /// @param[in] i_target the MCS target
- /// @param[out] o_setting array to populate
- /// @return FAPI2_RC_SUCCESS iff okay
- ///
- static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
- attr_type& o_setting)
- {
- FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_EFF_DRAM_GEN, i_target, o_setting) );
-
- fapi_try_exit:
- return fapi2::current_err;
- }
-
- ///
- /// @brief attribute setter
- /// @param[in] i_target the MCS target
- /// @param[in] i_setting array to set
- /// @return FAPI2_RC_SUCCESS iff okay
- ///
- static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
- const attr_type& i_setting)
- {
- attr_type l_data = {};
- memcpy(l_data, i_setting, sizeof(l_data));
-
- FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_GEN, i_target, l_data) );
-
- fapi_try_exit:
- return fapi2::current_err;
- }
-};
-
-///
-/// @brief Traits for pre_data_engine
-/// @class preDataInitTraits
-/// @note NIMBUS, HYBRID specialization
-///
-template<>
-class preDataInitTraits<NIMBUS, HYBRID>
-{
- public:
- using attr_type = fapi2::ATTR_EFF_HYBRID_Type;
- static const fapi2::TargetType TARGET_TYPE = fapi2::ATTR_EFF_HYBRID_TargetType;
-
- ///
- /// @brief attribute getter
- /// @param[in] i_target the MCS target
- /// @param[out] o_setting array to populate
- /// @return FAPI2_RC_SUCCESS iff okay
- ///
- static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
- attr_type& o_setting)
- {
- FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_EFF_HYBRID, i_target, o_setting) );
-
- fapi_try_exit:
- return fapi2::current_err;
- }
-
- ///
- /// @brief attribute setter
- /// @param[in] i_target the MCS target
- /// @param[in] i_setting array to set
- /// @return FAPI2_RC_SUCCESS iff okay
- ///
- static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
- const attr_type& i_setting)
- {
- attr_type l_data = {};
- memcpy(l_data, i_setting, sizeof(l_data));
-
- FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_HYBRID, i_target, l_data) );
-
- fapi_try_exit:
- return fapi2::current_err;
- }
-};
-
-///
-/// @brief Traits for pre_data_engine
-/// @class preDataInitTraits
-/// @note NIMBUS, HYBRID_MEDIA specialization
-///
-template<>
-class preDataInitTraits<NIMBUS, HYBRID_MEDIA>
-{
- public:
- using attr_type = fapi2::ATTR_EFF_HYBRID_MEMORY_TYPE_Type;
- static const fapi2::TargetType TARGET_TYPE = fapi2::ATTR_EFF_HYBRID_MEMORY_TYPE_TargetType;
-
- ///
- /// @brief attribute getter
- /// @param[in] i_target the MCS target
- /// @param[out] o_setting array to populate
- /// @return FAPI2_RC_SUCCESS iff okay
- ///
- static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
- attr_type& o_setting)
- {
- FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_EFF_HYBRID_MEMORY_TYPE, i_target, o_setting) );
-
- fapi_try_exit:
- return fapi2::current_err;
- }
-
- ///
- /// @brief attribute setter
- /// @param[in] i_target the MCS target
- /// @param[in] i_setting array to set
- /// @return FAPI2_RC_SUCCESS iff okay
- ///
- static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
- const attr_type& i_setting)
- {
- attr_type l_data = {};
- memcpy(l_data, i_setting, sizeof(l_data));
-
- FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_HYBRID_MEMORY_TYPE, i_target, l_data) );
-
- fapi_try_exit:
- return fapi2::current_err;
- }
-};
-
-///
-/// @brief Traits for pre_data_engine
-/// @class preDataInitTraits
-/// @note NIMBUS, MRANKS specialization
-///
-template<>
-class preDataInitTraits<NIMBUS, MRANKS>
-{
- public:
- using attr_type = fapi2::ATTR_EFF_NUM_MASTER_RANKS_PER_DIMM_Type;
- static const fapi2::TargetType TARGET_TYPE = fapi2::ATTR_EFF_NUM_MASTER_RANKS_PER_DIMM_TargetType;
-
- ///
- /// @brief attribute getter
- /// @param[in] i_target the MCS target
- /// @param[out] o_setting array to populate
- /// @return FAPI2_RC_SUCCESS iff okay
- ///
- static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
- attr_type& o_setting)
- {
- FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_EFF_NUM_MASTER_RANKS_PER_DIMM, i_target, o_setting) );
-
- fapi_try_exit:
- return fapi2::current_err;
- }
-
- ///
- /// @brief attribute setter
- /// @param[in] i_target the MCS target
- /// @param[in] i_setting array to set
- /// @return FAPI2_RC_SUCCESS iff okay
- ///
- static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
- const attr_type& i_setting)
- {
- attr_type l_data = {};
- memcpy(l_data, i_setting, sizeof(l_data));
-
- FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_NUM_MASTER_RANKS_PER_DIMM, i_target, l_data) );
-
- fapi_try_exit:
- return fapi2::current_err;
- }
-};
-
-///
-/// @brief Traits for pre_data_engine
-/// @class preDataInitTraits
-/// @note NIMBUS, DIMM_RANKS_CNFG specialization
-///
-template<>
-class preDataInitTraits<NIMBUS, DIMM_RANKS_CNFG>
-{
- public:
- using attr_type = fapi2::ATTR_EFF_DIMM_RANKS_CONFIGED_Type;
- static const fapi2::TargetType TARGET_TYPE = fapi2::ATTR_EFF_NUM_MASTER_RANKS_PER_DIMM_TargetType;
-
- ///
- /// @brief attribute getter
- /// @param[in] i_target the MCS target
- /// @param[out] o_setting array to populate
- /// @return FAPI2_RC_SUCCESS iff okay
- ///
- static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target,
- attr_type& o_setting)
- {
- FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_EFF_DIMM_RANKS_CONFIGED, i_target, o_setting) );
-
- fapi_try_exit:
- return fapi2::current_err;
- }
-
- ///
- /// @brief attribute setter
- /// @param[in] i_target the MCS target
- /// @param[in] i_setting array to set
- /// @return FAPI2_RC_SUCCESS iff okay
- ///
- static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target,
- const attr_type& i_setting)
- {
- attr_type l_data = {};
- memcpy(l_data, i_setting, sizeof(l_data));
-
- FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DIMM_RANKS_CONFIGED, i_target, l_data) );
-
- fapi_try_exit:
- return fapi2::current_err;
- }
-};
-
-///
/// @brief Helper function for attribute setting
/// @tparam T processor type (e.g. NIMBUS, AXONE, etc.)
/// defaulted to NIMBUS
@@ -393,7 +118,7 @@ fapi2::ReturnCode lookup_table_check(const fapi2::Target<T>& i_target,
.set_TARGET(i_target),
"Failed to find a mapped value for %d on %s",
i_key,
- spd::c_str(i_target) );
+ mss::spd::c_str(i_target) );
fapi_try_exit:
return fapi2::current_err;
}
@@ -437,23 +162,12 @@ fapi_try_exit:
/// @tparam T supported processor type (e.g. Nimbus, Axone, etc.)
///
template< proc_type T >
-class pre_data_engine;
-
-///
-/// @brief Data structure to set pre-effective config data
-/// @class pre_data_engine
-/// @note NIMBUS specialization
-///
-template< >
-class pre_data_engine< NIMBUS >
+class pre_data_engine
{
private:
fapi2::Target<fapi2::TARGET_TYPE_DIMM> iv_dimm;
- uint8_t iv_master_ranks;
spd::facade iv_spd_data;
- size_t iv_port_index;
- size_t iv_dimm_index;
public:
@@ -467,11 +181,12 @@ class pre_data_engine< NIMBUS >
/// @brief ctor
/// @param[in] i_target the DIMM target
/// @param[in] i_spd_data SPD decoder
- /// @param[out] o_rc ReturnCode for failure to init object
///
pre_data_engine(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
- const spd::facade& i_spd_data,
- fapi2::ReturnCode& o_rc);
+ const spd::facade& i_spd_data):
+ iv_dimm(i_target),
+ iv_spd_data(i_spd_data)
+ {}
///
/// @brief default dtor
@@ -515,6 +230,69 @@ class pre_data_engine< NIMBUS >
fapi2::ReturnCode set_dimm_ranks_configured();
};
+///
+/// @brief Sets pre_eff_config attributes
+/// @tparam P processor type
+/// @param[in] i_target the DIMM target
+/// @param[in] i_spd_decoder SPD decoder
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template <mss::proc_type P>
+fapi2::ReturnCode set_pre_init_attrs( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ const spd::facade& i_spd_decoder )
+{
+ mss::pre_data_engine<P> l_data_engine(i_target, i_spd_decoder);
+
+ // Set attributes needed before eff_config
+ // DIMM type and DRAM gen are needed for c_str to aid debugging
+ FAPI_TRY(l_data_engine.set_dimm_type(), "Failed to set DIMM type %s", mss::spd::c_str(i_target) );
+ FAPI_TRY(l_data_engine.set_dram_gen(), "Failed to set DRAM gen %s", mss::spd::c_str(i_target) );
+
+ // Hybrid and hybrid media help detect hybrid modules, specifically NVDIMMs for Nimbus
+ FAPI_TRY(l_data_engine.set_hybrid(), "Failed to set Hybrid %s", mss::spd::c_str(i_target) );
+ FAPI_TRY(l_data_engine.set_hybrid_media(), "Failed to set Hybrid Media %s", mss::spd::c_str(i_target) );
+
+ // Number of master ranks needed for VPD decoding
+ // and dimm_ranks_configured is a PRD attr...
+ FAPI_TRY(l_data_engine.set_master_ranks(), "Failed to set Master ranks %s", mss::spd::c_str(i_target) );
+ FAPI_TRY(l_data_engine.set_dimm_ranks_configured(), "Failed to set DIMM ranks configured %s",
+ mss::spd::c_str(i_target) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Sets pre_eff_config attributes
+/// @tparam P processor type
+/// @tparam T fapi2::TargetType
+/// @param[in] i_target the target on which to operate
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template <mss::proc_type P, fapi2::TargetType T>
+fapi2::ReturnCode set_pre_init_attrs( const fapi2::Target<T>& i_target )
+{
+ for( const auto& d : mss::find_targets<fapi2::TARGET_TYPE_DIMM>(i_target))
+ {
+ std::vector<uint8_t> l_raw_spd;
+ FAPI_TRY(mss::spd::get_raw_data(d, l_raw_spd));
+ {
+ // Gets the SPD facade
+ fapi2::ReturnCode l_rc(fapi2::FAPI2_RC_SUCCESS);
+ mss::spd::facade l_spd_decoder(d, l_raw_spd, l_rc);
+
+ // Checks that the facade was setup correctly
+ FAPI_TRY(l_rc, "Failed to initialize SPD facade for %s", mss::spd::c_str(d));
+
+ // Sets pre-init attributes
+ FAPI_TRY(mss::set_pre_init_attrs<P>(d, l_spd_decoder), "%s failed to set pre init attrs", mss::spd::c_str(d) );
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
}//mss
#endif
diff --git a/src/import/generic/memory/lib/utils/freq/gen_mss_freq.H b/src/import/generic/memory/lib/utils/freq/gen_mss_freq.H
index 058b1f93b..655146f87 100644
--- a/src/import/generic/memory/lib/utils/freq/gen_mss_freq.H
+++ b/src/import/generic/memory/lib/utils/freq/gen_mss_freq.H
@@ -22,3 +22,488 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
+
+///
+/// @file gen_mss_freq.H
+/// @brief Contains frequency traits information
+///
+// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com>
+// *HWP FW Owner: Andre Marin <aamarin@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: CI
+
+#ifndef _GEN_MSS_FREQ_H_
+#define _GEN_MSS_FREQ_H_
+
+#include <generic/memory/lib/utils/freq/gen_mss_freq_traits.H>
+#include <generic/memory/lib/utils/find.H>
+#include <generic/memory/lib/spd/spd_facade.H>
+#include <generic/memory/lib/spd/spd_utils.H>
+#include <generic/memory/lib/utils/freq/cas_latency.H>
+#include <generic/memory/lib/utils/freq/mss_freq_scoreboard.H>
+#include <generic/memory/lib/data_engine/pre_data_init.H>
+#include <vpd_access.H>
+
+namespace mss
+{
+///
+/// @brief Sets DRAM CAS latency attributes
+/// @tparam P mss::proc_type on which to operate
+/// @tparam T fapi2::TargetType on which to set the frequency
+/// @param[in] i_target the controller target the cas_latency value
+/// @param[in] i_cas_latency cas latency to update
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<mss::proc_type P, fapi2::TargetType T>
+fapi2::ReturnCode set_CL_attr(const fapi2::Target<T>& i_target,
+ const uint64_t i_cas_latency);
+
+///
+/// @brief Sets the frequency value
+/// @tparam P mss::proc_type on which to operate
+/// @tparam T fapi2::TargetType on which to set the frequency
+/// @param[in] i_target the target on which to set the frequency values
+/// @param[in] i_freq frequency value to set
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<mss::proc_type P, fapi2::TargetType T>
+fapi2::ReturnCode set_freq(const fapi2::Target<T>& i_target,
+ const uint64_t i_freq);
+
+///
+/// @brief Gets the number of master ranks per DIMM
+/// @tparam P mss::proc_type on which to operate
+/// @tparam T fapi2::TargetType on which to set the frequency
+/// @param[in] i_target the target on which to set the frequency values
+/// @param[out] o_master_ranks number of master ranks per DIMM
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<mss::proc_type P, fapi2::TargetType T>
+fapi2::ReturnCode get_master_rank_per_dimm(const fapi2::Target<T>& i_target,
+ uint8_t* o_master_ranks);
+
+///
+/// @brief Sets frequency attributes
+/// @tparam P mss::proc_type on which to operate
+/// @tparam TT Traits associated with the processor type
+/// @param[in] i_target the controller target
+/// @param[in] i_dimm_freq vector of freqs selected dimm freq in MT/s
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+inline fapi2::ReturnCode set_freq_attrs(const fapi2::Target<TT::FREQ_TARGET_TYPE>& i_target,
+ const std::vector<uint64_t>& i_dimm_freq)
+{
+ // Find the minimum (but non-0) freq in the vector. If we see all 0's we'll write a 0. However,
+ // we shouldn't as the caller should have been dealing with no DIMM before we got here.
+ uint64_t l_final_freq = UINT64_MAX;
+
+ for (const auto l_freq : i_dimm_freq)
+ {
+ if (l_freq != 0)
+ {
+ l_final_freq = std::min(l_final_freq, l_freq);
+ }
+ }
+
+ // If we saw all 0's, write a 0.
+ l_final_freq = (l_final_freq == UINT64_MAX) ? 0 : l_final_freq;
+
+ {
+ // Declaring temporary variables to avoid linker errors associated with FAPI_ASSERT
+ const auto FREQ0 = TT::SUPPORTED_FREQ0;
+ const auto FREQ1 = TT::SUPPORTED_FREQ1;
+ const auto FREQ2 = TT::SUPPORTED_FREQ2;
+ const auto FREQ3 = TT::SUPPORTED_FREQ3;
+
+ // If we don't find a valid frequency OR don't get a 0 (nothing configured on this clock domain), then error out
+ FAPI_ASSERT( std::binary_search(TT::SUPPORTED_FREQS.begin(), TT::SUPPORTED_FREQS.end(), l_final_freq) ||
+ l_final_freq == 0,
+ fapi2::MSS_BAD_FREQ_CALCULATED()
+ .set_MSS_FREQ(l_final_freq)
+ .set_TARGET(i_target)
+ .set_PROC_TYPE(P)
+ .set_SUPPORTED_FREQ_0(FREQ0)
+ .set_SUPPORTED_FREQ_1(FREQ1)
+ .set_SUPPORTED_FREQ_2(FREQ2)
+ .set_SUPPORTED_FREQ_3(FREQ3),
+ "%s: Calculated FREQ (%d) isn't supported",
+ mss::c_str(i_target),
+ l_final_freq);
+ }
+
+ FAPI_INF( "Final Chosen Frequency: %d (%s)", l_final_freq, mss::c_str(i_target) );
+
+ FAPI_TRY(set_freq<P>(i_target, l_final_freq), "%s Failed to set mss freq attribute", mss::c_str(i_target));
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Retrieves max frequency each port supports due to DIMM SPD
+/// @tparam P mss::proc_type on which to operate
+/// @tparam TT Traits associated with the processor type
+/// @param[in] i_target the target on which to operate
+/// @param[out] o_supported_freqs reference to vector of max SPD supported freq for each port
+/// @return FAPI2_RC_SUCCESS iff okay
+///
+template<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+inline fapi2::ReturnCode spd_supported_freq(const fapi2::Target<TT::FREQ_TARGET_TYPE>& i_target,
+ std::vector<uint32_t>& o_supported_freqs)
+{
+ uint64_t l_largest_tck = 0;
+
+ // Start with a really high value so we can use std::min to reduce it below
+ o_supported_freqs = std::vector<uint32_t>(TT::PORTS_PER_FREQ_DOMAIN, ~(0));
+
+ // Get cached decoder
+ std::vector< mss::spd::facade > l_spd_facades;
+ FAPI_TRY( get_spd_decoder_list(i_target, l_spd_facades), "%s get decoder - spd", mss::c_str(i_target) );
+
+ // Looking for the biggest application period on an MC.
+ // This will further reduce supported frequencies the system can run on.
+ for ( const auto& l_cache : l_spd_facades )
+ {
+ const auto l_dimm = l_cache.get_dimm_target();
+ const auto l_port = mss::find_target<TT::PORT_TARGET_TYPE>(l_dimm);
+ const auto l_port_pos = mss::relative_pos<TT::FREQ_TARGET_TYPE>(l_port);
+ uint64_t l_tckmax_in_ps = 0;
+ uint64_t l_tck_min_in_ps = 0;
+ uint32_t l_dimm_freq = 0;
+
+ FAPI_TRY( spd::get_tckmax(l_cache, l_tckmax_in_ps),
+ "%s. Failed to get tCKmax", mss::c_str(l_dimm) );
+ FAPI_TRY( spd::get_tckmin(l_cache, l_tck_min_in_ps),
+ "%s. Failed to get tCKmin", mss::c_str(l_dimm) );
+
+ // Determine a proposed tCK value that is greater than or equal tCKmin
+ // But less than tCKmax
+ l_largest_tck = std::max(l_largest_tck, l_tck_min_in_ps);
+ l_largest_tck = std::min(l_largest_tck, l_tckmax_in_ps);
+
+ FAPI_TRY( mss::ps_to_freq(l_largest_tck, l_dimm_freq), "%s ps to freq %lu", mss::c_str(i_target), l_largest_tck );
+ FAPI_INF("Biggest freq supported from SPD %d MT/s for %s",
+ l_dimm_freq, mss::c_str(l_dimm));
+
+ o_supported_freqs[l_port_pos] = std::min(l_dimm_freq, o_supported_freqs[l_port_pos]);
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Create a vector of support freq based on VPD config
+/// @tparam P mss::proc_type on which to operate
+/// @tparam TT Traits associated with the processor type
+/// @param[in] i_target the target on which to operate
+/// @param[in] i_target target on which to operate for which to get the DIMM configs
+/// @param[out] o_vpd_supported_freqs reference to a 2 dimensional vector of supported VPD frequencies for each MCA
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+// Pass in the syncronous target
+template<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+fapi2::ReturnCode vpd_supported_freqs( const fapi2::Target<TT::FREQ_TARGET_TYPE>& i_target,
+ std::vector<std::vector<uint32_t>>& o_vpd_supported_freqs)
+{
+ uint8_t l_rank_count_dimm[TT::MAX_DIMM_PER_PORT] = {};
+ uint8_t l_vpd_blob[TT::VPD_KEYWORD_MAX] = {};
+
+ // This bitmap will keep track of the ports we visit.
+ // Any we don't are not configured, so will support all frequencies in the scoreboard
+ fapi2::buffer<uint8_t> configured_ports;
+
+ // Clearing output Just.In.Case
+ o_vpd_supported_freqs.clear();
+
+ for ( size_t l_index = 0; l_index < TT::PORTS_PER_FREQ_DOMAIN; ++l_index )
+ {
+ o_vpd_supported_freqs.push_back(std::vector<uint32_t>());
+ }
+
+ fapi2::VPDInfo<TT::VPD_TARGET_TYPE> l_vpd_info(TT::VPD_BLOB);
+
+ // Just go to find target for the port level
+ for( const auto& p : mss::find_targets<TT::PORT_TARGET_TYPE>(i_target) )
+ {
+ const auto& l_vpd_target = mss::find_target<TT::VPD_TARGET_TYPE>(p);
+ const auto l_port_pos = mss::relative_pos<TT::FREQ_TARGET_TYPE>(p);
+ FAPI_TRY( configured_ports.setBit(l_port_pos) );
+
+ if( mss::count_dimm(p) == 0 )
+ {
+ // Cronus lets you have a port w/no DIMMs. In this case, we say the port supports all frequencies
+ // TK should this be the processor type OR the MC type?? - SPG
+ for( const auto& freq : TT::SUPPORTED_FREQS )
+ {
+ o_vpd_supported_freqs[l_port_pos].push_back(freq);
+ }
+
+ continue;
+ }
+
+ // ATTR to update
+ // Note: this flat out assumes that we have two DIMM per port max. This goes against the directive to have arrays be dynamic in length and derived from ATTR's
+ FAPI_TRY( get_master_rank_per_dimm<P>(p, &(l_rank_count_dimm[0])) );
+
+ l_vpd_info.iv_rank_count_dimm_0 = l_rank_count_dimm[0];
+ l_vpd_info.iv_rank_count_dimm_1 = l_rank_count_dimm[1];
+ l_vpd_info.iv_is_config_ffdc_enabled = false;
+
+ // Iterate through all supported memory freqs
+ for( const auto& freq : TT::SUPPORTED_FREQS )
+ {
+ l_vpd_info.iv_freq_mhz = freq;
+
+ FAPI_INF("%s. VPD info - frequency: %d MT/s, rank count for dimm_0: %d, dimm_1: %d",
+ mss::c_str(p), l_vpd_info.iv_freq_mhz, l_vpd_info.iv_rank_count_dimm_0, l_vpd_info.iv_rank_count_dimm_1);
+
+ // In order to retrieve the VPD contents we first need the keyword size.
+ // If we are unable to retrieve the keyword size then this speed isn't
+ // supported in the VPD in Cronus (but not FW) and we skip to the next
+ // possible speed bin.
+
+ // So, we'll use VPD access for the IBM specific product data (assuming the vendor of the OCMB's side as well)
+ if( fapi2::getVPD(l_vpd_target, l_vpd_info, nullptr) != fapi2::FAPI2_RC_SUCCESS )
+ {
+ FAPI_INF("Couldn't retrieve MR size from VPD for this config %s -- skipping freq %d MT/s", mss::c_str(p), freq );
+
+ fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
+ continue;
+ }
+
+ // Need temporary variables to avoid issues with FAPI_ASSERT and templated variables
+ {
+ const auto VPD_KW_MAX = TT::VPD_KEYWORD_MAX;
+ const auto VPD_BLOB = TT::VPD_BLOB;
+ FAPI_ASSERT( l_vpd_info.iv_size <= TT::VPD_KEYWORD_MAX,
+ fapi2::MSS_INVALID_VPD_KEYWORD_MAX().
+ set_MAX(VPD_KW_MAX).
+ set_ACTUAL(l_vpd_info.iv_size).
+ set_KEYWORD(VPD_BLOB).
+ set_MCS_TARGET(i_target),
+ "VPD MR keyword size retrieved: %d, is larger than max: %d for %s",
+ l_vpd_info.iv_size, TT::VPD_KEYWORD_MAX, mss::c_str(i_target));
+ }
+
+ // Firmware doesn't do the VPD lookup in the size check so repeat the logic here
+ if( fapi2::getVPD(l_vpd_target, l_vpd_info, &(l_vpd_blob[0])) != fapi2::FAPI2_RC_SUCCESS )
+ {
+ FAPI_INF("Couldn't retrieve %s data from VPD for this config %s -- skipping freq %d MT/s", TT::VPD_BLOB_NAME,
+ mss::c_str(p), freq );
+
+ fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
+ continue;
+ }
+
+ // Add supported freqs to our output
+ FAPI_INF("VPD supported freq added: %d for %s", freq, mss::c_str(p) );
+ o_vpd_supported_freqs[l_port_pos].push_back(freq);
+ }// freqs
+ }// mca
+
+ // Mark any ports we didn't visit as supporting all frequencies
+ for ( uint64_t l_port_pos = 0; l_port_pos < TT::PORTS_PER_FREQ_DOMAIN; ++l_port_pos )
+ {
+ if ( !configured_ports.getBit(l_port_pos) )
+ {
+ for ( const auto l_freq : TT::SUPPORTED_FREQS )
+ {
+ o_vpd_supported_freqs[l_port_pos].push_back(l_freq);
+ }
+ }
+ }
+
+ for ( auto& l_freqs : o_vpd_supported_freqs )
+ {
+ std::sort( l_freqs.begin(), l_freqs.end() );
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Finds the minimum dimm frequencies
+/// @tparam P mss::proc_type on which to operate
+/// @tparam TT Traits associated with the processor type
+/// @param[in] i_target the target on which to operate
+/// @param[in] i_supported_freqs reference to vector of supported frequencies for each port
+/// @param[out] o_supported_freqs reference to vector of supported frequencies for each port
+/// @return FAPI2_RC_SUCCESS iff okay
+///
+template<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+inline fapi2::ReturnCode find_min_dimm_freq(const fapi2::Target<TT::FREQ_TARGET_TYPE>& i_target,
+ const std::vector<uint32_t>& i_supported_freqs,
+ std::vector<uint64_t>& o_min_dimm_freq)
+{
+ for (const auto& l_port : mss::find_targets<TT::PORT_TARGET_TYPE>(i_target) )
+ {
+ fapi2::ReturnCode l_rc;
+ uint64_t l_desired_cl = 0;
+
+ // Get cached decoder
+ std::vector< mss::spd::facade > l_spd_facades;
+ FAPI_TRY( get_spd_decoder_list(l_port, l_spd_facades) );
+
+ // Instantiation of class that calculates CL algorithm
+ mss::cas_latency<TT::MC> l_cas_latency( l_port, l_spd_facades, i_supported_freqs, l_rc );
+
+ FAPI_TRY( l_rc, "%s. Failed to initialize cas_latency ctor", mss::c_str(l_port) );
+
+ if(l_cas_latency.iv_dimm_list_empty)
+ {
+ // Cannot fail out for an empty DIMM configuration, so default values are set
+ FAPI_INF("%s. DIMM list is empty! Setting default values for CAS latency and DIMM speed.",
+ mss::c_str(l_port) );
+ l_desired_cl = 0;
+ }
+
+ else
+ {
+ // We set this to a non-0 so we avoid divide-by-zero errors in the conversions which
+ // go from clocks to time (and vice versa.) We have other bugs if there was really
+ // no MT/s determined and there really is a DIMM installed, so this is ok.
+ // We pick the maximum frequency supported by the system as the default.
+
+ uint64_t l_desired_freq = TT::SUPPORTED_FREQS.back();
+ uint64_t l_tCKmin = 0;
+
+ // Find CAS latency using JEDEC algorithm
+ FAPI_TRY( l_cas_latency.find_cl(l_desired_cl, l_tCKmin), "%s failed to find a cas latency", mss::c_str(i_target) );
+
+ FAPI_INF("%s. Result from CL algorithm, CL (nck): %d, tCK (ps): %d",
+ mss::c_str(l_port), l_desired_cl, l_tCKmin);
+
+ // Find dimm transfer speed from selected tCK
+ FAPI_TRY( mss::ps_to_freq(l_tCKmin, l_desired_freq),
+ "%s. Failed ps_to_freq()", mss::c_str(l_port) );
+
+ FAPI_INF("DIMM speed %d from selected tCK (ps): %d for %s",
+ l_desired_freq,
+ l_tCKmin,
+ mss::c_str(l_port));
+
+ o_min_dimm_freq.push_back(l_desired_freq);
+
+ }// end else
+
+ FAPI_TRY(set_CL_attr<P>(l_port, l_desired_cl), "%s. Failed set_CL_attr()", mss::c_str(l_port) );
+ } // mca
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Find a list of all supported frequencies
+/// @tparam P mss::proc_type on which to operate
+/// @tparam TT Traits associated with the processor type
+/// @param[in] i_target the target on which to operate
+/// @param[out] o_supported_freqs reference to vector of supported frequencies for each port
+/// @return FAPI2_RC_SUCCESS iff okay
+///
+template<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+inline fapi2::ReturnCode supported_freqs(const fapi2::Target<TT::FREQ_TARGET_TYPE>& i_target,
+ std::vector<uint32_t>& o_freqs)
+{
+ o_freqs.clear();
+
+ freq_scoreboard l_scoreboard(TT::PORTS_PER_FREQ_DOMAIN, TT::SUPPORTED_FREQS);
+ std::vector<uint32_t> l_max_freqs(NUM_MAX_FREQS, 0);
+ std::vector<std::vector<uint32_t>> l_vpd_supported_freqs;
+ std::vector<uint32_t> l_spd_supported_freq;
+ std::vector<uint8_t> l_deconfigured = {0};
+
+ // Retrieve system MRW, SPD, and VPD constraints
+ FAPI_TRY( max_allowed_dimm_freq<P>(l_max_freqs.data()), "%s max_allowed_dimm_freq", mss::c_str(i_target) );
+ FAPI_TRY( spd_supported_freq<P>(i_target, l_spd_supported_freq),
+ "%s spd supported freqs", mss::c_str(i_target) );
+ FAPI_TRY( vpd_supported_freqs<P>(i_target, l_vpd_supported_freqs),
+ "%s vpd supported freqs", mss::c_str(i_target) );
+
+ // Limits the frequency by the Nimbus processor constraints (sync mode)
+ FAPI_TRY( limit_freq_by_processor<P>(i_target, l_scoreboard) );
+
+ // Limit frequency scoreboard according to MRW constraints
+ FAPI_TRY( limit_freq_by_mrw<P>(i_target, l_max_freqs, l_scoreboard) );
+
+ // Limit frequency scoreboard according to VPD constraints
+ FAPI_TRY( limit_freq_by_vpd<P>(i_target, l_vpd_supported_freqs, l_scoreboard) );
+
+ // Limit frequency scoreboard according to SPD (DIMM) constraints
+ FAPI_TRY( limit_freq_by_spd<P>(i_target, l_spd_supported_freq, l_scoreboard) );
+
+ // Callout the fewest number of ports to achieve a common shared freq
+ FAPI_TRY( l_scoreboard.template resolve<P>(i_target,
+ l_vpd_supported_freqs,
+ l_deconfigured,
+ o_freqs) );
+
+ FAPI_INF("%s supported freqs:", mss::c_str(i_target));
+
+ for (const auto l_freq : o_freqs)
+ {
+ FAPI_INF("%s %d", mss::c_str(i_target), l_freq);
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+namespace check
+{
+
+///
+/// @brief Checks the final frequency for the system type
+/// @tparam P mss::proc_type on which to operate
+/// @tparam TT Traits associated with the processor type
+/// @param[in] i_target the target on which to operate
+/// @return FAPI2_RC_SUCCESS iff okay
+///
+template<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+fapi2::ReturnCode final_freq(const fapi2::Target<TT::FREQ_TARGET_TYPE>& i_target);
+
+} // check nameespace
+
+///
+/// @brief Generates the memory frequency for one frequency domain
+/// @tparam P mss::proc_type on which to operate
+/// @tparam TT Traits associated with the processor type
+/// @param[in] i_target the target on which to operate
+/// @return FAPI2_RC_SUCCESS iff okay
+///
+template<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+fapi2::ReturnCode generate_freq(const fapi2::Target<TT::FREQ_TARGET_TYPE>& i_target)
+{
+ std::vector<uint64_t> l_min_dimm_freq;
+ std::vector<uint32_t> l_supported_freqs;
+
+ // We will first set pre-eff_config attributes
+ FAPI_TRY( mss::set_pre_init_attrs<P>(i_target));
+
+ // Get supported freqs for this MCBIST
+ FAPI_TRY( mss::supported_freqs<P>(i_target, l_supported_freqs), "%s failed to get supported frequencies",
+ mss::c_str(i_target) );
+
+ // Finds the minimum supported DIMM frequencies for this MCBIST
+ FAPI_TRY(mss::find_min_dimm_freq<P>(i_target, l_supported_freqs, l_min_dimm_freq),
+ "%s. Failed find_min_dimm_freq()", mss::c_str(i_target) );
+
+ FAPI_TRY(mss::set_freq_attrs<P>(i_target, l_min_dimm_freq),
+ "%s. Failed set_freq_attrs()", mss::c_str(i_target) );
+
+ // Check MEM/NEST frequency ratio
+ FAPI_TRY(mss::check::final_freq<P>(i_target));
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+}// mss namespace
+
+#endif
diff --git a/src/import/generic/memory/lib/utils/freq/gen_mss_freq_traits.H b/src/import/generic/memory/lib/utils/freq/gen_mss_freq_traits.H
index 863951401..ba63170ed 100644
--- a/src/import/generic/memory/lib/utils/freq/gen_mss_freq_traits.H
+++ b/src/import/generic/memory/lib/utils/freq/gen_mss_freq_traits.H
@@ -22,3 +22,79 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
+
+///
+/// @file gen_mss_freq_traits.H
+/// @brief Contains frequency traits information
+///
+// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com>
+// *HWP FW Owner: Andre Marin <aamarin@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: CI
+
+#ifndef _GEN_MSS_FREQ_TRAITS_H_
+#define _GEN_MSS_FREQ_TRAITS_H_
+
+#include <fapi2.H>
+#include <generic/memory/lib/utils/shared/mss_generic_consts.H>
+#include <vpd_access.H>
+
+namespace mss
+{
+
+///
+/// @class Traits and policy class for frequency and synchronous code
+/// @tparam P mss::proc_type processor type
+///
+template< mss::proc_type P >
+class frequency_traits;
+
+///
+/// @class Traits and policy class for frequency and synchronous code - specialization for the NIMBUS processor type
+///
+template<>
+class frequency_traits<mss::proc_type::NIMBUS>
+{
+ public:
+ //////////////////////////////////////////////////////////////
+ // Target types
+ //////////////////////////////////////////////////////////////
+ static constexpr fapi2::TargetType PORT_TARGET_TYPE = fapi2::TARGET_TYPE_MCA;
+ static constexpr fapi2::TargetType FREQ_TARGET_TYPE = fapi2::TARGET_TYPE_MCBIST;
+ static constexpr fapi2::TargetType VPD_TARGET_TYPE = fapi2::TARGET_TYPE_MCS;
+
+ //////////////////////////////////////////////////////////////
+ // Traits values
+ //////////////////////////////////////////////////////////////
+ static const std::vector<uint64_t> SUPPORTED_FREQS;
+ // MCBIST is our frequency domain. So 4 ports per MCBIST
+ static constexpr uint64_t PORTS_PER_FREQ_DOMAIN = 4;
+ // Max DIMM's per port
+ static constexpr uint64_t MAX_DIMM_PER_PORT = 2;
+ // Maxium number of primary ranks on a DIMM
+ static constexpr uint64_t MAX_PRIMARY_RANK_PER_DIMM = 4;
+ // MC type for Nimbus is constant - NIMBUS
+ static constexpr mss::mc_type MC = mss::mc_type::NIMBUS;
+ static constexpr const char* PROC_STR = "NIMBUS";
+
+ // VPD traits values
+ // VPD keyword max is slightly repeated (it's in NIMBUS consts too)
+ static constexpr uint64_t VPD_KEYWORD_MAX = 255;
+ static constexpr const char* VPD_BLOB_NAME = "MR";
+ static constexpr auto VPD_BLOB = fapi2::MemVpdData::MR;
+
+ // Coding minion, why have these explicitly defined frequency values?
+ // Isn't the supported frequency vector used for this purpose?
+ // Well, we need to callout the specific frequency values that are allowed on a given system
+ // As we can't callout a vector in error callouts and each traits might have a different number of allowable traits,
+ // the below values are hardcoded specifically for the error callouts
+ static constexpr uint64_t SUPPORTED_FREQ0 = DIMM_SPEED_1866;
+ static constexpr uint64_t SUPPORTED_FREQ1 = DIMM_SPEED_2133;
+ static constexpr uint64_t SUPPORTED_FREQ2 = DIMM_SPEED_2400;
+ static constexpr uint64_t SUPPORTED_FREQ3 = DIMM_SPEED_2666;
+};
+
+
+} // ns mss
+#endif
diff --git a/src/import/generic/memory/lib/utils/freq/mss_freq_scoreboard.C b/src/import/generic/memory/lib/utils/freq/mss_freq_scoreboard.C
index a648fdadc..6ee1e8056 100644
--- a/src/import/generic/memory/lib/utils/freq/mss_freq_scoreboard.C
+++ b/src/import/generic/memory/lib/utils/freq/mss_freq_scoreboard.C
@@ -22,3 +22,153 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
+
+///
+/// @file mss_freq_scoreboard.C
+/// @brief Frequency scoreboard class definitions
+///
+// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com>
+// *HWP HWP Backup: Louis Stermole <stermole@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 3
+// *HWP Consumed by: HB:FSP
+
+#include <vector>
+#include <fapi2.H>
+#include <generic/memory/lib/utils/freq/mss_freq_scoreboard.H>
+#include <generic/memory/lib/utils/c_str.H>
+#include <generic/memory/lib/utils/find.H>
+#include <generic/memory/lib/utils/shared/mss_generic_consts.H>
+
+namespace mss
+{
+
+///
+/// @brief Remove frequencies above a limit from the scoreboard
+/// @param[in] i_port_pos position index of port within parent MCBIST
+/// @param[in] i_freq_limit upper limit for frequency
+/// @return FAPI2_RC_SUCCESS if successful
+///
+fapi2::ReturnCode freq_scoreboard::remove_freqs_above_limit(const uint64_t i_port_pos,
+ const uint32_t i_freq_limit)
+{
+ FAPI_TRY( check_port_position(i_port_pos,
+ generic_ffdc_codes::FREQ_SCOREBOARD_REMOVE_FREQS_ABOVE_LIMIT),
+ "Invalid port index passed to remove_freqs_above_limit (%d)",
+ i_port_pos);
+
+ {
+ auto& l_port_supported_freqs = iv_supported_port_freqs[i_port_pos];
+
+ // Can't do a ranged for loop here because we need the index to get the frequency out of iv_freq_values
+ for ( size_t l_index = 0; l_index < l_port_supported_freqs.size(); ++l_index )
+ {
+ const auto l_scoreboard_freq = iv_freq_values[l_index];
+
+ if ( l_scoreboard_freq > i_freq_limit )
+ {
+ FAPI_INF("Removing freq %d on port %d since it's above the limit %d", l_scoreboard_freq, i_port_pos, i_freq_limit);
+ l_port_supported_freqs[l_index] = false;
+ }
+ }
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Remove frequencies above a limit from the scoreboard
+/// @param[in] i_port_pos position index of port within parent MCBIST
+/// @param[in] i_freq_limits reference to vector of upper limits for frequency per port
+/// @return FAPI2_RC_SUCCESS if successful
+///
+fapi2::ReturnCode freq_scoreboard::remove_freqs_above_limit(const uint64_t i_port_pos,
+ const std::vector<uint32_t> i_freq_limits)
+{
+ FAPI_TRY( check_port_position(i_port_pos,
+ generic_ffdc_codes::FREQ_SCOREBOARD_REMOVE_FREQS_ABOVE_LIMIT_VECTOR),
+ "Invalid port index passed to remove_freqs_above_limit (%d)",
+ i_port_pos);
+
+ FAPI_ASSERT(i_freq_limits.size() == iv_num_ports,
+ fapi2::MSS_INVALID_FREQ_LIST_PASSED()
+ .set_SIZE(i_freq_limits.size())
+ .set_EXPECTED(iv_num_ports),
+ "Invalid frequency list passed to remove_freqs_above_limit (size should be %d but got %d)",
+ iv_num_ports, i_freq_limits.size());
+
+ {
+ const auto l_freq_limit = i_freq_limits[i_port_pos];
+ FAPI_TRY( this->remove_freqs_above_limit(i_port_pos, l_freq_limit) );
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Return the maximum supported frequency for a given port
+/// @param[in] i_port_pos position index of port within parent MCBIST
+/// @param[out] o_freq max supported frequency
+/// @return FAPI2_RC_SUCCESS if successful
+///
+fapi2::ReturnCode freq_scoreboard::max_supported_freq(const uint64_t i_port_pos,
+ uint32_t& o_freq) const
+{
+ FAPI_TRY( this->check_port_position(i_port_pos,
+ generic_ffdc_codes::FREQ_SCOREBOARD_MAX_SUPPORTED_FREQ),
+ "Invalid port index passed to max_supported_freq (%d)",
+ i_port_pos);
+
+ {
+ std::vector<uint32_t> l_supported_freqs;
+ FAPI_TRY( this->supported_freqs(i_port_pos, l_supported_freqs) );
+
+ o_freq = l_supported_freqs.empty() ? 0 : l_supported_freqs.back();
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Return a list of supported frequencies for a given port
+/// @param[in] i_port_pos position index of port within parent MCBIST
+/// @param[out] o_freq vector of supported frequencies
+/// @return FAPI2_RC_SUCCESS if successful
+///
+fapi2::ReturnCode freq_scoreboard::supported_freqs(const uint64_t i_port_pos,
+ std::vector<uint32_t>& o_freqs) const
+{
+ FAPI_TRY( check_port_position(i_port_pos,
+ generic_ffdc_codes::FREQ_SCOREBOARD_SUPPORTED_FREQS),
+ "Invalid port index passed to supported_freqs (%d)",
+ i_port_pos);
+
+ {
+ o_freqs.clear();
+ auto& l_port_supported_freqs = iv_supported_port_freqs[i_port_pos];
+
+ for ( size_t l_index = 0; l_index < iv_freq_values.size(); ++l_index )
+ {
+ if (l_port_supported_freqs[l_index])
+ {
+ o_freqs.push_back(iv_freq_values[l_index]);
+ }
+ }
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+} // ns mss
diff --git a/src/import/generic/memory/lib/utils/freq/mss_freq_scoreboard.H b/src/import/generic/memory/lib/utils/freq/mss_freq_scoreboard.H
index 2dc3bfe8f..7b9adacdc 100644
--- a/src/import/generic/memory/lib/utils/freq/mss_freq_scoreboard.H
+++ b/src/import/generic/memory/lib/utils/freq/mss_freq_scoreboard.H
@@ -22,3 +22,603 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
+
+///
+/// @file mss_freq_scoreboard.H
+/// @brief Frequency scoreboard class declaration
+///
+// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com>
+// *HWP HWP Backup: Louis Stermole <stermole@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 3
+// *HWP Consumed by: HB:FSP
+
+#ifndef MSS_FREQ_SCOREBOARD_H
+#define MSS_FREQ_SCOREBOARD_H
+
+#include <vector>
+#include <fapi2.H>
+#include <generic/memory/lib/utils/freq/gen_mss_freq_traits.H>
+#include <generic/memory/lib/utils/c_str.H>
+#include <generic/memory/lib/utils/find.H>
+
+namespace mss
+{
+
+///////////////////////////////////////////////////////////////////////
+/// Helper functions first
+///////////////////////////////////////////////////////////////////////
+
+///
+/// @brief Gets the number of master ranks on each DIMM
+/// @tparam P mss::proc_type on which to operate
+/// @param[in] i_target DIMM target
+/// @param[out] o_master_ranks number of master ranks
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<mss::proc_type P>
+fapi2::ReturnCode num_master_ranks_per_dimm(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ uint8_t& o_master_ranks);
+
+///
+/// @brief Gets the attribute for the maximum allowed dimm frequency
+/// @tparam P mss::proc_type on which to operate
+/// @param[out] o_allowed_dimm_freq allowed dimm frequency
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<mss::proc_type P>
+fapi2::ReturnCode max_allowed_dimm_freq(uint32_t* o_allowed_dimm_freq);
+
+///
+/// @brief Calls out the target if no DIMM frequencies are supported
+/// @tparam P mss::proc_type on which to operate
+/// @tparam T fapi2::TargetType on which to set the frequency
+/// @param[in] i_target target on which to operate
+/// @param[in] i_supported_freq true if any FREQ's are supported
+/// @param[in] i_num_ports number of ports on the frequency domain
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<mss::proc_type P, fapi2::TargetType T>
+fapi2::ReturnCode callout_no_common_freq(const fapi2::Target<T>& i_target,
+ const bool l_supported_freq,
+ const uint64_t i_num_ports);
+
+///
+/// @brief Calls out the target if no DIMM frequencies are supported
+/// @tparam P mss::proc_type on which to operate
+/// @tparam T fapi2::TargetType on which to set the frequency
+/// @param[in] i_target target on which to operate
+/// @param[in] i_vpd_supported_freqs VPD supported frequencies for the callout
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<mss::proc_type P, fapi2::TargetType T>
+fapi2::ReturnCode callout_max_freq_empty_set(const fapi2::Target<T>& i_target,
+ const std::vector<std::vector<uint32_t>>& i_vpd_supported_freqs);
+
+///
+/// @class freq_scoreboard
+/// @brief class that encapsulates port supported frequencies
+///
+class freq_scoreboard
+{
+ public:
+ // We need to know the number of ports on each frequency domain and how many frequencies are available for a given processor
+ // Therefor, the base constructor is not allowed
+ freq_scoreboard() = delete;
+
+ ///
+ /// @brief Create a new frequency scoreboard
+ /// @param[in] i_num_ports number of ports on this frequency domain
+ /// @param[in] i_freq_values the list of allowed frequencis for this system
+ ///
+ freq_scoreboard(const uint64_t i_num_ports, const std::vector<uint64_t>& i_freq_values) :
+ iv_num_ports(i_num_ports),
+ iv_freq_values(i_freq_values)
+ {
+ iv_supported_port_freqs = std::vector<std::vector<bool>>(i_num_ports,
+ std::vector<bool>(i_freq_values.size(), true));
+ }
+
+ ///
+ /// @brief default destructor
+ ///
+ ~freq_scoreboard() = default;
+
+ ///
+ /// @brief Remove frequencies above a limit from the scoreboard
+ /// @param[in] i_port_pos position index of port within parent MCBIST
+ /// @param[in] i_freq_limit upper limit for frequency
+ /// @return FAPI2_RC_SUCCESS if successful
+ ///
+ fapi2::ReturnCode remove_freqs_above_limit(const uint64_t i_port_pos,
+ const uint32_t i_freq_limit);
+
+ ///
+ /// @brief Remove frequencies above a limit from the scoreboard
+ /// @param[in] i_port_pos position index of port within parent MCBIST
+ /// @param[in] i_freq_limits reference to vector of upper limits for frequency per port
+ /// @return FAPI2_RC_SUCCESS if successful
+ ///
+ fapi2::ReturnCode remove_freqs_above_limit(const uint64_t i_port_pos,
+ const std::vector<uint32_t> i_freq_limits);
+
+ ///
+ /// @brief Remove frequencies not on a given list from the scoreboard
+ /// @tparam T the type of data in the vector
+ /// @param[in] i_port_pos position index of port within parent MCBIST
+ /// @param[in] i_freq_list vector of supported frequencies
+ /// @return FAPI2_RC_SUCCESS if successful
+ ///
+ template<typename T>
+ fapi2::ReturnCode remove_freqs_not_on_list(const uint64_t i_port_pos,
+ const std::vector<T>& i_freq_list)
+ {
+ FAPI_ASSERT(i_port_pos < iv_num_ports,
+ fapi2::MSS_INVALID_PORT_INDEX_PASSED()
+ .set_INDEX(i_port_pos)
+ .set_FUNCTION(generic_ffdc_codes::FREQ_SCOREBOARD_REMOVE_FREQS_NOT_ON_LIST),
+ "Invalid port index passed to remove_freqs_not_on_list (%d)",
+ i_port_pos);
+
+ for ( size_t l_index = 0; l_index < iv_freq_values.size(); ++l_index )
+ {
+ const auto l_it = std::find(i_freq_list.begin(), i_freq_list.end(), iv_freq_values[l_index]);
+
+ if (l_it == i_freq_list.end())
+ {
+ FAPI_INF("Removing freq %d on port %d since it's not supported", iv_freq_values[l_index], i_port_pos);
+ iv_supported_port_freqs[i_port_pos][l_index] = false;
+ }
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+
+ ///
+ /// @brief Return the maximum supported frequency for a given port
+ /// @param[in] i_port_pos position index of port within parent MCBIST
+ /// @param[out] o_freq max supported frequency
+ /// @return FAPI2_RC_SUCCESS if successful
+ ///
+ fapi2::ReturnCode max_supported_freq(const uint64_t i_port_pos,
+ uint32_t& o_freq) const;
+
+ ///
+ /// @brief Return a list of supported frequencies for a given port
+ /// @param[in] i_port_pos position index of port within parent MCBIST
+ /// @param[out] o_freq vector of supported frequencies
+ /// @return FAPI2_RC_SUCCESS if successful
+ ///
+ fapi2::ReturnCode supported_freqs(const uint64_t i_port_pos,
+ std::vector<uint32_t>& o_freqs) const;
+
+ ///
+ /// @brief Resolve frequency scoreboard by deconfiguring any non-conforming ports
+ /// and return a list of the supported frequencies
+ /// @tparam P mss::proc_type on which to operate
+ /// @tparam TT Traits associated with the processor type
+ /// @param[in] i_target MCBIST target
+ /// @param[in] i_vpd_supported_freqs vector of hardware supported freqs -- from VPD
+ /// @param[out] o_deconfigured vector of port positions that were deconfigured by this function
+ /// @param[out] o_freqs vector of frequencies supported by all ports
+ /// @return FAPI2_RC_SUCCESS if successful
+ ///
+ template<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+ fapi2::ReturnCode resolve(const fapi2::Target<TT::FREQ_TARGET_TYPE>& i_target,
+ const std::vector<std::vector<uint32_t>>& i_vpd_supported_freqs,
+ std::vector<uint8_t>& o_deconfigured,
+ std::vector<uint32_t>& o_freqs)
+ {
+ const auto l_ports = mss::find_targets<TT::PORT_TARGET_TYPE>(i_target);
+ const auto l_port_count = l_ports.size();
+
+ // empty_port_count is the number of port that are deconfigured
+ // We use it later to make sure our common freq is supported by at least one configured port
+ const auto l_empty_port_count = iv_num_ports - l_port_count;
+
+ // Get a count of how many ports support each frequency
+ const auto l_support_counts = count_supported_frequencies<P>(i_target, l_ports, o_freqs);
+
+ // If we have at least one common frequency, we're done
+ if (!o_freqs.empty())
+ {
+ return fapi2::FAPI2_RC_SUCCESS;
+ }
+
+ // If we made it here, that means we don't have a common supported freq for all ports
+ // So let's deconfigure the least number of ports to get a common freq
+
+ // Find the last instance of the most ports that support a given frequency
+ // That way we get the highest frequency supported by the most ports
+ // Note: this may be inefficient, but this is a small vector and HB doesn't support reverse iterators
+ uint64_t l_common_ports = 0;
+ size_t l_best_freq_index = 0;
+
+ for ( size_t l_index = 0; l_index < l_support_counts.size(); ++l_index )
+ {
+ if (l_support_counts[l_index] >= l_common_ports)
+ {
+ l_common_ports = l_support_counts[l_index];
+ l_best_freq_index = l_index;
+ }
+ }
+
+ FAPI_INF("%s Max ports supporting a common frequency is %d", mss::c_str(i_target), l_common_ports);
+ FAPI_INF("%s Fastest common frequency is %d", mss::c_str(i_target), TT::SUPPORTED_FREQS[l_best_freq_index]);
+
+ // Assert if we don't have any frequencies supported by at least one configured port
+ FAPI_TRY(callout_no_common_freq<P>(i_target, l_common_ports > l_empty_port_count, l_port_count));
+
+ // Now find and deconfigure all ports that don't support our selected frequency
+ FAPI_TRY(deconfigure_ports<P>(i_target, l_ports, l_best_freq_index, o_deconfigured));
+
+ // Now find all the frequencies supported by the ports that are left over
+ FAPI_TRY(this->template resolve<P>(i_target, i_vpd_supported_freqs, o_deconfigured, o_freqs));
+
+#ifndef __HOSTBOOT_MODULE
+
+ // Cronus doesn't deconfigure, so let's bail out if we didn't find a common frequency
+ if (!o_deconfigured.empty())
+ {
+ FAPI_TRY(callout_max_freq_empty_set<P>(i_target, i_vpd_supported_freqs));
+ }
+
+#endif
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+
+ private:
+ uint64_t iv_num_ports;
+ std::vector<uint64_t> iv_freq_values;
+ std::vector<std::vector<bool>> iv_supported_port_freqs;
+
+ // Private helper functions
+
+ ///
+ /// @brief Checks our port position
+ /// @param[in] i_port_pos port position
+ /// @param[in] i_ffdc generic_ffdc_codes for the calling function
+ /// @return FAPI2_RC_SUCCESS iff ok
+ ///
+ inline fapi2::ReturnCode check_port_position(const uint64_t i_port_pos, const generic_ffdc_codes i_ffdc) const
+ {
+ FAPI_ASSERT(i_port_pos < iv_num_ports,
+ fapi2::MSS_INVALID_PORT_INDEX_PASSED()
+ .set_INDEX(i_port_pos)
+ .set_FUNCTION(i_ffdc),
+ "Invalid port index passed into the function (%d)",
+ i_port_pos);
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+
+ ///
+ /// @brief Counts the common port frequencies
+ /// @tparam P mss::proc_type on which to operate
+ /// @tparam TT Traits associated with the processor type
+ /// @param[in] i_target frequency domain target
+ /// @param[in] i_ports vector of ports
+ /// @param[out] o_freqs vector of frequencies
+ /// @returh l_supported_vector return the fector of supported frequencies
+ ///
+ template<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+ std::vector<uint64_t> count_supported_frequencies(const fapi2::Target<TT::FREQ_TARGET_TYPE>& i_target,
+ const std::vector<fapi2::Target<TT::PORT_TARGET_TYPE>>& i_ports,
+ std::vector<uint32_t>& o_freqs)
+ {
+ // This vector will hold the number of ports that support each frequency in TT::SUPPORTED_FREQS
+ std::vector<uint64_t> l_support_counts(TT::SUPPORTED_FREQS.size(), 0);
+ o_freqs.clear();
+
+ // Get a count of how many ports support each frequency
+ for ( size_t l_index = 0; l_index < TT::SUPPORTED_FREQS.size(); ++l_index )
+ {
+ size_t l_pos = 0;
+
+ for ( const auto& l_supported : iv_supported_port_freqs )
+ {
+ if (l_supported[l_index])
+ {
+ FAPI_INF("%s Frequency %d is supported by port%d", mss::c_str(i_target), TT::SUPPORTED_FREQS[l_index], l_pos);
+ ++l_support_counts[l_index];
+ }
+
+ // Add any frequencies supported by all configured ports to our output list
+ // Note that deconfigured ports will support all frequencies due to the way the scoreboard is built
+ if (l_support_counts[l_index] == iv_num_ports)
+ {
+ FAPI_INF("%s Frequency %d is supported by all ports", mss::c_str(i_target), TT::SUPPORTED_FREQS[l_index]);
+ o_freqs.push_back(TT::SUPPORTED_FREQS[l_index]);
+ }
+
+ ++l_pos;
+ }
+ }
+
+ return l_support_counts;
+ }
+
+ ///
+ /// @brief Counts the common port frequencies
+ /// @tparam P mss::proc_type on which to operate
+ /// @tparam TT Traits associated with the processor type
+ /// @param[in] i_target frequency domain target
+ /// @param[in] i_ports vector of ports
+ /// @param[in] i_best_freq_index index corresponding to the best case frequency
+ /// @param[out] o_deconfigured vector of deconfigured port positions
+ /// @return FAPI2_RC_SUCCESS iff ok
+ ///
+ template<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+ fapi2::ReturnCode deconfigure_ports(const fapi2::Target<TT::FREQ_TARGET_TYPE>& i_target,
+ const std::vector<fapi2::Target<TT::PORT_TARGET_TYPE>>& i_ports,
+ const uint64_t i_best_freq_index,
+ std::vector<uint8_t>& o_deconfigured)
+ {
+ o_deconfigured.clear();
+
+ for ( size_t l_pos = 0; l_pos < iv_num_ports; ++l_pos )
+ {
+ // Find the port with this position
+ const auto l_it_port = std::find_if(i_ports.begin(),
+ i_ports.end(),
+ [l_pos]( const fapi2::Target<TT::PORT_TARGET_TYPE>& i_rhs) -> bool
+ {
+ return (mss::relative_pos<TT::FREQ_TARGET_TYPE>(i_rhs) != l_pos);
+ });
+
+ // If we didn't find an port for a given position, there wasn't one configured there
+ if (l_it_port == i_ports.end())
+ {
+ continue;
+ }
+
+ // and call it out if it doesn't support the selected freq
+ const auto& p = *l_it_port;
+ FAPI_INF("Checking if port %d (%s) supports common frequency", l_pos, mss::c_str(p));
+
+ if (!iv_supported_port_freqs[l_pos][i_best_freq_index])
+ {
+ FAPI_INF("Port %d (%s) does not support the common frequency so will be deconfigured", l_pos, mss::c_str(p));
+ auto& l_port_supported_freqs = iv_supported_port_freqs[l_pos];
+
+ o_deconfigured.push_back(l_pos);
+ FAPI_ASSERT_NOEXIT( false,
+ fapi2::MSS_PORT_DOES_NOT_SUPPORT_MAJORITY_FREQ()
+ .set_FREQ_TARGET(i_target)
+ .set_PORT_TARGET(p)
+ .set_FREQUENCY(TT::SUPPORTED_FREQS[i_best_freq_index]),
+ "%s does not support the majority frequency (%d) so will be deconfigured",
+ mss::c_str(p), TT::SUPPORTED_FREQS[i_best_freq_index] );
+
+ // Now mark all frequencies as supported by that port since it was deconfigured
+ for ( size_t l_index = 0; l_index < l_port_supported_freqs.size(); ++l_index )
+ {
+ l_port_supported_freqs[l_index] = true;
+ }
+ }
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+ }
+};
+
+///
+/// @brief Update supported frequency scoreboard according to processor limits
+/// @tparam P mss::proc_type on which to operate
+/// @tparam TT Traits associated with the processor type
+/// @param[in] i_target processor frequency domain
+/// @param[in,out] io_scoreboard scoreboard of port targets supporting each frequency
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+fapi2::ReturnCode limit_freq_by_processor(const fapi2::Target<TT::FREQ_TARGET_TYPE>& i_target,
+ freq_scoreboard& io_scoreboard);
+
+///
+/// @brief Update supported frequency scoreboard according to MRW/config limits
+/// @tparam P mss::proc_type on which to operate
+/// @tparam TT Traits associated with the processor type
+/// @param[in] i_target target for which to get the DIMM configs
+/// @param[in] i_max_mrw_freqs vector of max allowed freqs
+/// @param[in,out] io_scoreboard scoreboard of targets supporting each frequency
+/// @return FAPI2_RC_SUCCESS iff ok
+/// @note This helper allows us to use the attributes for the main path but
+/// have a path for testing
+///
+template<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+inline fapi2::ReturnCode limit_freq_by_mrw(const fapi2::Target<TT::FREQ_TARGET_TYPE>& i_target,
+ const std::vector<uint32_t>& i_max_mrw_freqs,
+ freq_scoreboard& io_scoreboard)
+{
+ // Static asserting to ensure that we have the correct sized array bellow
+ // We'll need to do some code updates if this changes anyways
+ static_assert(2 == TT::MAX_DIMM_PER_PORT, "Number of DIMM's per port is not 2!");
+ static_assert(4 == TT::MAX_PRIMARY_RANK_PER_DIMM, "Maximum number of primary ranks per DIMM is not 4!");
+
+ // Indexes into the ATTR_MAX_ALLOWED_DIMM_FREQ arrary. e.g., [0][0] is 1R 1 drop
+ constexpr size_t l_indexes[2][4] =
+ {
+ {0, 1, 0xFF, 2},
+ {3, 4, 0xFF, 0xFF}
+ };
+
+ // This is the number of elements in the max_allowed_dimm_freq attribute, not the frequencies of
+ // the system.
+ FAPI_ASSERT( i_max_mrw_freqs.size() == NUM_MAX_FREQS,
+ fapi2::MSS_MAX_FREQ_ATTR_SIZE_CHANGED()
+ .set_ACTUAL_SIZE(i_max_mrw_freqs.size())
+ .set_SUPPOSED_SIZE(NUM_MAX_FREQS)
+ .set_MCA_TARGET(i_target),
+ "%s Incorrect number of max frequencies in attribute for (%d)",
+ mss::c_str(i_target),
+ i_max_mrw_freqs.size());
+
+ FAPI_INF("attribute supported max allowed dimm freqs %d %d %d %d %d for %s",
+ i_max_mrw_freqs[0], i_max_mrw_freqs[1], i_max_mrw_freqs[2], i_max_mrw_freqs[3], i_max_mrw_freqs[4],
+ mss::c_str(i_target));
+
+ for( const auto& p : mss::find_targets<TT::PORT_TARGET_TYPE>(i_target) )
+ {
+ const auto l_port_pos = mss::relative_pos<TT::FREQ_TARGET_TYPE>(p);
+ const auto l_dimms = mss::find_targets<fapi2::TARGET_TYPE_DIMM>(p);
+ const uint64_t l_dimms_on_port = l_dimms.size();
+
+ // Holds the max freq allowed for this port. This is the minimum of maximum
+ // frequencies allowed by the DIMM. So, we start way off the charts so std::min can do the lifting for us.
+ uint32_t l_port_max_freq = ~(0);
+
+ FAPI_ASSERT( (l_dimms_on_port <= TT::MAX_DIMM_PER_PORT),
+ fapi2::MSS_TOO_MANY_DIMMS_ON_PORT()
+ .set_DIMM_COUNT(l_dimms_on_port)
+ .set_MCA_TARGET(p),
+ "Seeing %d DIMM on port %s",
+ l_dimms_on_port,
+ mss::c_str(p));
+
+ // Find the max supported frequency for this port
+ for (const auto& d : l_dimms)
+ {
+ uint8_t l_num_master_ranks = 0;
+ size_t l_index = 0xFF;
+ FAPI_TRY( num_master_ranks_per_dimm<P>(d, l_num_master_ranks) );
+
+ // Just a quick check but we're in deep yogurt if this triggers
+ FAPI_ASSERT( (l_num_master_ranks <= TT::MAX_PRIMARY_RANK_PER_DIMM),
+ fapi2::MSS_TOO_MANY_PRIMARY_RANKS_ON_DIMM()
+ .set_RANK_COUNT(l_num_master_ranks)
+ .set_DIMM_TARGET(d),
+ "seeing %d primary ranks on DIMM %s",
+ l_dimms_on_port,
+ mss::c_str(d));
+
+ l_index = l_indexes[l_dimms_on_port - 1][l_num_master_ranks - 1];
+
+ FAPI_ASSERT( (l_index < NUM_MAX_FREQS),
+ fapi2::MSS_FREQ_INDEX_TOO_LARGE()
+ .set_INDEX(l_index)
+ .set_NUM_MAX_FREQS(NUM_MAX_FREQS),
+ "seeing %d index for %d DIMM and %d ranks on DIMM %s",
+ l_index,
+ l_dimms_on_port,
+ l_num_master_ranks,
+ mss::c_str(d));
+
+ FAPI_INF("%s rank config %d drop %d yields max freq attribute index of %d (%d)",
+ mss::c_str(d), l_num_master_ranks, l_dimms_on_port,
+ l_indexes[l_dimms_on_port - 1][l_num_master_ranks - 1],
+ i_max_mrw_freqs[l_index] );
+
+ l_port_max_freq = std::min(l_port_max_freq, i_max_mrw_freqs[l_index]);
+ }// dimm
+
+ // Remove any frequencies bigger than this port's max from the scoreboard
+ io_scoreboard.remove_freqs_above_limit(l_port_pos, l_port_max_freq);
+
+ FAPI_INF("%s after processing MRW, max freq is %d", mss::c_str(p), l_port_max_freq);
+ }// port
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Update supported frequency scoreboard according to VPD limits
+/// @tparam P mss::proc_type on which to operate
+/// @tparam TT Traits associated with the processor type
+/// @param[in] i_target MCBIST target for which to get the DIMM configs
+/// @param[in] i_hw_freqs vector of hardware supported freqs -- from VPD
+/// @param[in,out] io_scoreboard scoreboard of port targets supporting each frequency
+/// @return FAPI2_RC_SUCCESS iff ok
+/// @note This helper allows us to use the attributes for the main path but
+/// have a path for testing
+///
+template<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+fapi2::ReturnCode limit_freq_by_vpd(const fapi2::Target<TT::FREQ_TARGET_TYPE>& i_target,
+ const std::vector<std::vector<uint32_t>>& i_hw_freqs,
+ freq_scoreboard& io_scoreboard)
+{
+ const auto PORTS_PER_FREQ_DOMAIN = TT::PORTS_PER_FREQ_DOMAIN;
+ FAPI_ASSERT(i_hw_freqs.size() == TT::PORTS_PER_FREQ_DOMAIN,
+ fapi2::MSS_INVALID_VPD_FREQ_LIST_PASSED()
+ .set_SIZE(i_hw_freqs.size())
+ .set_EXPECTED(PORTS_PER_FREQ_DOMAIN),
+ "Wrong size VPD frequency vector passed to limit_freq_by_vpd (got %d, expected %d)",
+ i_hw_freqs.size(), TT::PORTS_PER_FREQ_DOMAIN);
+
+ for( const auto& p : mss::find_targets<TT::PORT_TARGET_TYPE>(i_target) )
+ {
+ const auto l_port_pos = mss::relative_pos<TT::FREQ_TARGET_TYPE>(p);
+ const auto& l_port_freqs = i_hw_freqs[l_port_pos];
+
+ // This is the list of supported frequencies for VPD
+ FAPI_ASSERT( !l_port_freqs.empty(),
+ fapi2::MSS_EMPTY_VECTOR().
+ set_FUNCTION(LIMIT_FREQ_BY_VPD).
+ set_TARGET(p),
+ "Supported system freqs from VPD are empty for %s",
+ mss::c_str(p));
+
+ for( const auto& freq : l_port_freqs )
+ {
+ FAPI_DBG("VPD supported freqs %d for %s", freq, mss::c_str(p) );
+ }
+
+ // Remove any frequencies that aren't in this port's list from the scoreboard
+ io_scoreboard.remove_freqs_not_on_list(l_port_pos, l_port_freqs);
+
+ uint32_t l_max_freq = 0;
+ FAPI_TRY( io_scoreboard.max_supported_freq(l_port_pos, l_max_freq) );
+ FAPI_INF("%s after processing VPD, max freq is %d", mss::c_str(p), l_max_freq);
+ }// port
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Update supported frequency scoreboard according to SPD limits
+/// @tparam P mss::proc_type on which to operate
+/// @tparam TT Traits associated with the processor type
+/// @param[in] i_target target for which to get the DIMM configs
+/// @param[in] i_hw_freqs vector of hardware supported freqs -- from SPD
+/// @param[in,out] io_scoreboard scoreboard of port targets supporting each frequency
+/// @return FAPI2_RC_SUCCESS iff ok
+/// @note This helper allows us to use the attributes for the main path but
+/// have a path for testing
+///
+template<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+fapi2::ReturnCode limit_freq_by_spd(const fapi2::Target<TT::FREQ_TARGET_TYPE>& i_target,
+ const std::vector<uint32_t>& i_hw_freqs,
+ freq_scoreboard& io_scoreboard)
+{
+ for( const auto& p : mss::find_targets<TT::PORT_TARGET_TYPE>(i_target) )
+ {
+ const auto l_port_pos = mss::relative_pos<TT::FREQ_TARGET_TYPE>(p);
+
+ // Remove any frequencies that aren't in this port's list from the scoreboard
+ io_scoreboard.remove_freqs_above_limit(l_port_pos, i_hw_freqs);
+
+ uint32_t l_max_freq = 0;
+ FAPI_TRY( io_scoreboard.max_supported_freq(l_port_pos, l_max_freq) );
+ FAPI_INF("%s after processing SPD, max freq is %d", mss::c_str(p), l_max_freq);
+ }// port
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+} // ns mss
+
+#endif
diff --git a/src/import/generic/memory/lib/utils/shared/mss_generic_consts.H b/src/import/generic/memory/lib/utils/shared/mss_generic_consts.H
index adc56d990..3a02f8165 100644
--- a/src/import/generic/memory/lib/utils/shared/mss_generic_consts.H
+++ b/src/import/generic/memory/lib/utils/shared/mss_generic_consts.H
@@ -78,6 +78,11 @@ enum conversions
BITS_PER_BYTE = 8,
};
+enum generic_sizes
+{
+ NUM_MAX_FREQS = 5, ///< Used for ATTR_MAX_ALLOWED_DIMM_FREQ
+};
+
///
/// @brief FFDC generic codes
///
@@ -118,16 +123,25 @@ enum generic_ffdc_codes
BAD_SPD_DATA = 0x101D,
SET_FIELD = 0x101E,
+ // mss_freq functions
SELECT_SUPPORTED_FREQ = 0x101F,
+ FREQ_SCOREBOARD_REMOVE_FREQS_ABOVE_LIMIT = 0x1020,
+ FREQ_SCOREBOARD_REMOVE_FREQS_ABOVE_LIMIT_VECTOR = 0x1021,
+ FREQ_SCOREBOARD_REMOVE_FREQS_NOT_ON_LIST = 0x1022,
+ FREQ_SCOREBOARD_MAX_SUPPORTED_FREQ = 0x1023,
+ FREQ_SCOREBOARD_SUPPORTED_FREQS = 0x1024,
+ LIMIT_FREQ_BY_VPD = 0x1025,
};
///
/// @brief Supported proc types
+/// @note Processor types by system generation and sub numbering
///
-enum proc_type
+enum class proc_type
{
- NIMBUS,
- AXONE,
+ NIMBUS = 0x0900,
+ CUMULUS = 0x0901,
+ AXONE = 0x0902,
};
///
diff --git a/src/import/generic/procedures/xml/error_info/generic_error.xml b/src/import/generic/procedures/xml/error_info/generic_error.xml
index 57b6685c9..611aa111d 100644
--- a/src/import/generic/procedures/xml/error_info/generic_error.xml
+++ b/src/import/generic/procedures/xml/error_info/generic_error.xml
@@ -38,6 +38,25 @@
<hwpErrors>
<hwpError>
+ <rc>RC_MSS_BAD_FREQ_CALCULATED</rc>
+ <description>
+ No frequency found for MC Either bad mrw attribute or no DIMMS installed?
+ Should be a code bug if we get here
+ </description>
+ <ffdc>MSS_FREQ</ffdc>
+ <ffdc>SUPPORTED_FREQ_0</ffdc>
+ <ffdc>SUPPORTED_FREQ_1</ffdc>
+ <ffdc>SUPPORTED_FREQ_2</ffdc>
+ <ffdc>SUPPORTED_FREQ_3</ffdc>
+ <ffdc>TARGET</ffdc>
+ <ffdc>PROC_TYPE</ffdc>
+ <callout>
+ <procedure>CODE</procedure>
+ <priority>HIGH</priority>
+ </callout>
+ </hwpError>
+
+ <hwpError>
<rc>RC_MSS_EMPTY_VECTOR</rc>
<description>
Empty vector conditional failed.
@@ -216,6 +235,17 @@
</hwpError>
<hwpError>
+ <rc>RC_MSS_INVALID_PORT_INDEX_PASSED</rc>
+ <description>An invalid port index was passed into an MSS function</description>
+ <ffdc>INDEX</ffdc>
+ <ffdc>FUNCTION</ffdc>
+ <callout>
+ <procedure>CODE</procedure>
+ <priority>HIGH</priority>
+ </callout>
+ </hwpError>
+
+ <hwpError>
<rc>RC_MSS_INVALID_TIMING_VALUE</rc>
<description>Invalid value calculated for timing value based on MTB and FTB from SPD.</description>
<ffdc>VALUE</ffdc>
@@ -232,4 +262,40 @@
</gard>
</hwpError>
+<hwpError>
+ <rc>RC_MSS_LOOKUP_FAILED</rc>
+ <description>
+ Conditional that tests whether a certain key value is located in a map.
+ </description>
+ <ffdc>KEY</ffdc>
+ <ffdc>DATA</ffdc>
+ <ffdc>FUNCTION</ffdc>
+ <callout>
+ <target>TARGET</target>
+ <priority>MEDIUM</priority>
+ </callout>
+ <deconfigure>
+ <target>TARGET</target>
+ </deconfigure>
+</hwpError>
+
+ <hwpError>
+ <rc>RC_MSS_PORT_DOES_NOT_SUPPORT_MAJORITY_FREQ</rc>
+ <description>
+ When considering the frequencies in the MRW and the max supported
+ frequencies based on DIMM config, the indicated port's DIMM do not support
+ the frequency of the majority of other ports' DIMM, so it will be deconfigured
+ </description>
+ <ffdc>FREQ_TARGET</ffdc>
+ <ffdc>PORT_TARGET</ffdc>
+ <ffdc>FREQUENCY</ffdc>
+ <callout>
+ <childTargets>
+ <parent>PORT_TARGET</parent>
+ <childType>TARGET_TYPE_DIMM</childType>
+ </childTargets>
+ <priority>MEDIUM</priority>
+ </callout>
+ </hwpError>
+
</hwpErrors>
OpenPOWER on IntegriCloud