diff options
Diffstat (limited to 'src/import')
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> |