summaryrefslogtreecommitdiffstats
path: root/src/import/generic
diff options
context:
space:
mode:
authorStephen Glancy <sglancy@us.ibm.com>2018-09-04 10:57:35 -0500
committerChristian R. Geddes <crgeddes@us.ibm.com>2018-09-19 17:21:05 -0500
commit4f8cfb6e9c07076261fac4b58105bd6863f6c13f (patch)
treebd3133e372feeedfd117aa16c23030cf190d0ca1 /src/import/generic
parent8247477571339e0cba2d06d0701378e029628806 (diff)
downloadtalos-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')
-rw-r--r--src/import/generic/memory/lib/data_engine/pre_data_init.H360
-rw-r--r--src/import/generic/memory/lib/utils/freq/gen_mss_freq.H485
-rw-r--r--src/import/generic/memory/lib/utils/freq/gen_mss_freq_traits.H76
-rw-r--r--src/import/generic/memory/lib/utils/freq/mss_freq_scoreboard.C150
-rw-r--r--src/import/generic/memory/lib/utils/freq/mss_freq_scoreboard.H600
-rw-r--r--src/import/generic/memory/lib/utils/shared/mss_generic_consts.H20
-rw-r--r--src/import/generic/procedures/xml/error_info/generic_error.xml66
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>
OpenPOWER on IntegriCloud