diff options
author | Stephen Glancy <sglancy@us.ibm.com> | 2018-09-04 10:57:35 -0500 |
---|---|---|
committer | Christian R. Geddes <crgeddes@us.ibm.com> | 2018-09-19 17:21:05 -0500 |
commit | 4f8cfb6e9c07076261fac4b58105bd6863f6c13f (patch) | |
tree | bd3133e372feeedfd117aa16c23030cf190d0ca1 /src/import/generic | |
parent | 8247477571339e0cba2d06d0701378e029628806 (diff) | |
download | talos-hostboot-4f8cfb6e9c07076261fac4b58105bd6863f6c13f.tar.gz talos-hostboot-4f8cfb6e9c07076261fac4b58105bd6863f6c13f.zip |
Moves sync code to generic folder
Change-Id: I440cdb0ea105a6dbdcd0ac26696308e55d56f88b
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/65786
Dev-Ready: STEPHEN GLANCY <sglancy@us.ibm.com>
Tested-by: HWSV CI <hwsv-ci+hostboot@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com>
Reviewed-by: Louis Stermole <stermole@us.ibm.com>
Reviewed-by: ANDRE A. MARIN <aamarin@us.ibm.com>
Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com>
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/66323
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
Diffstat (limited to 'src/import/generic')
7 files changed, 1463 insertions, 294 deletions
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> |