summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9a
diff options
context:
space:
mode:
authorLouis Stermole <stermole@us.ibm.com>2019-01-24 13:36:56 -0500
committerChristian R. Geddes <crgeddes@us.ibm.com>2019-04-15 12:11:18 -0500
commit2b26420e72477835ffeacb2dab9970266ef07566 (patch)
tree005fff430a99823e7d1fcd11bc66fb043f160c68 /src/import/chips/p9a
parent0d3c3c752b95d3ddc42d82bb2a66ea9ff4f0c6b1 (diff)
downloadtalos-hostboot-2b26420e72477835ffeacb2dab9970266ef07566.tar.gz
talos-hostboot-2b26420e72477835ffeacb2dab9970266ef07566.zip
Add p9a_mss_freq procedure
Change-Id: I764e1ade2f63cabb7f6e5cf2b39e89811ea432c4 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/70989 Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Tested-by: HWSV CI <hwsv-ci+hostboot@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Reviewed-by: STEPHEN GLANCY <sglancy@us.ibm.com> Reviewed-by: ANDRE A. MARIN <aamarin@us.ibm.com> Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com> Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com> Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/75567 Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com> Tested-by: Christian R. Geddes <crgeddes@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9a')
-rw-r--r--src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_freq_traits.H70
-rw-r--r--src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_mss_freq.C427
-rw-r--r--src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_sync.C250
-rw-r--r--src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_sync.H180
-rw-r--r--src/import/chips/p9a/procedures/hwp/memory/p9a_mss_eff_config.C24
-rw-r--r--src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.C28
-rw-r--r--src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.H3
-rw-r--r--src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.mk4
-rw-r--r--src/import/chips/p9a/procedures/xml/error_info/p9a_freq_errors.xml112
9 files changed, 1077 insertions, 21 deletions
diff --git a/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_freq_traits.H b/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_freq_traits.H
index ae17d925d..1b4f96d0c 100644
--- a/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_freq_traits.H
+++ b/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_freq_traits.H
@@ -22,3 +22,73 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
+
+///
+/// @file axone_freq_traits.H
+/// @brief Contains frequency traits information for Axone
+///
+// *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 _AXONE_FREQ_TRAITS_H_
+#define _AXONE_FREQ_TRAITS_H_
+
+#include <fapi2.H>
+#include <generic/memory/lib/utils/shared/mss_generic_consts.H>
+#include <generic/memory/lib/utils/freq/gen_mss_freq_traits.H>
+#include <vpd_access.H>
+
+namespace mss
+{
+
+///
+/// @class Traits and policy class for frequency and synchronous code - specialization for the AXONE processor type
+///
+template<>
+class frequency_traits<mss::proc_type::AXONE>
+{
+ public:
+ //////////////////////////////////////////////////////////////
+ // Target types
+ //////////////////////////////////////////////////////////////
+ static constexpr fapi2::TargetType PORT_TARGET_TYPE = fapi2::TARGET_TYPE_MEM_PORT;
+ static constexpr fapi2::TargetType FREQ_TARGET_TYPE = fapi2::TARGET_TYPE_MEM_PORT;
+ static constexpr fapi2::TargetType VPD_TARGET_TYPE = fapi2::TARGET_TYPE_OCMB_CHIP;
+
+ //////////////////////////////////////////////////////////////
+ // Traits values
+ //////////////////////////////////////////////////////////////
+ static const std::vector<uint64_t> SUPPORTED_FREQS;
+ // MEM_PORT is our frequency domain. So 1 port per domain
+ static constexpr uint64_t PORTS_PER_FREQ_DOMAIN = 1;
+ // 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 Axone is constant - EXPLORER
+ static constexpr mss::mc_type MC = mss::mc_type::EXPLORER;
+ static constexpr const char* PROC_STR = "AXONE";
+
+ // VPD traits values
+ // TK Resolve these when we know what they are for Axone
+ static constexpr uint64_t VPD_KEYWORD_MAX = 255;
+ static constexpr const char* VPD_BLOB_NAME = "EFD";
+ static constexpr auto VPD_BLOB = fapi2::MemVpdData::EFD;
+ static constexpr auto LRDIMM_TYPE = fapi2::ENUM_ATTR_EFF_DIMM_TYPE_LRDIMM;
+
+ // 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_2666;
+ static constexpr uint64_t SUPPORTED_FREQ1 = DIMM_SPEED_2933;
+ static constexpr uint64_t SUPPORTED_FREQ2 = DIMM_SPEED_3200;
+};
+
+
+} // ns mss
+#endif
diff --git a/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_mss_freq.C b/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_mss_freq.C
index d9dcbda4a..23d6481ad 100644
--- a/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_mss_freq.C
+++ b/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_mss_freq.C
@@ -22,3 +22,430 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
+
+///
+/// @file axone_mss_freq.C
+/// @brief Axone specializations for frequency library
+///
+// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com>
+// *HWP HWP Backup: Louis Stermole <stermole@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 3
+// *HWP Consumed by: HB:FSP
+
+#include <fapi2.H>
+#include <vpd_access.H>
+#include <vector>
+
+// Memory libraries
+#include <lib/freq/axone_freq_traits.H>
+#include <lib/shared/axone_consts.H>
+#include <lib/freq/axone_sync.H>
+
+// Generic libraries
+#include <mss_generic_attribute_getters.H>
+#include <mss_generic_attribute_setters.H>
+#include <mss_generic_system_attribute_getters.H>
+#include <generic/memory/lib/utils/assert_noexit.H>
+#include <generic/memory/lib/utils/count_dimm.H>
+#include <generic/memory/lib/utils/freq/gen_mss_freq.H>
+#include <generic/memory/lib/utils/freq/mss_freq_scoreboard.H>
+
+namespace mss
+{
+
+const std::vector< uint64_t > frequency_traits<mss::proc_type::AXONE>::SUPPORTED_FREQS =
+{
+ mss::DIMM_SPEED_2666,
+ mss::DIMM_SPEED_2933,
+ mss::DIMM_SPEED_3200,
+};
+
+///
+/// @brief Sets DRAM CAS latency attributes - specialization for Axone and MEM_PORT
+/// @param[in] i_target the controller target for the cas_latency value
+/// @param[in] i_cas_latency cas latency to update
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode set_CL_attr<mss::proc_type::AXONE>(
+ const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
+ const uint64_t i_cas_latency)
+{
+ const auto l_temp = static_cast<uint8_t>(i_cas_latency);
+
+ //Check for rounding issues. Going from a uint64_t to a uint8_t
+ FAPI_ASSERT( l_temp == i_cas_latency,
+ fapi2::MSS_BAD_CL_CAST()
+ .set_CL(i_cas_latency)
+ .set_PORT_TARGET(i_target),
+ "%s bad cast for cas latency from %d to %d",
+ mss::c_str(i_target),
+ i_cas_latency,
+ l_temp);
+
+ FAPI_INF( "Final Chosen CL: %d for %s", l_temp, mss::c_str(i_target));
+
+ FAPI_TRY( mss::attr::set_dram_cl(i_target, l_temp) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Sets the frequency value - specialization for Axone and MEM_PORT
+/// @param[in] i_target the target on which to set the frequency values
+/// @param[in] i_freq frequency value to set
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode set_freq<mss::proc_type::AXONE>(
+ const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
+ const uint64_t i_freq)
+{
+ FAPI_TRY( mss::attr::set_freq(i_target, i_freq) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Gets the number of master ranks per DIMM - specialization for Axone and MEM_PORT
+/// @param[in] i_target the target on which to get the number of master ranks per DIMM
+/// @param[out] o_master_ranks number of master ranks per DIMM
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode get_master_rank_per_dimm<mss::proc_type::AXONE>(
+ const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
+ uint8_t* o_master_ranks)
+{
+ using TT = mss::frequency_traits<mss::proc_type::AXONE>;
+
+ uint8_t l_master_ranks[TT::MAX_DIMM_PER_PORT] = {0};
+ FAPI_TRY(mss::attr::get_num_master_ranks_per_dimm(i_target, l_master_ranks));
+ std::copy(&l_master_ranks[0], &l_master_ranks[0] + TT::MAX_DIMM_PER_PORT, &o_master_ranks[0]);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Gets the attribute for the maximum - specialization for Axone
+/// @param[out] o_allowed_dimm_freq allowed dimm frequency
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode max_allowed_dimm_freq<mss::proc_type::AXONE>(uint32_t* o_allowed_dimm_freq)
+{
+ uint32_t l_allowed_dimm_freq[NUM_MAX_FREQS] = {0};
+ FAPI_TRY(mss::attr::get_max_allowed_dimm_freq(l_allowed_dimm_freq));
+ std::copy(&l_allowed_dimm_freq[0], &l_allowed_dimm_freq[0] + NUM_MAX_FREQS, &o_allowed_dimm_freq[0]);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Gets the DIMM type - specialization for Axone and MEM_PORT
+/// @param[in] i_target the target on which to get the DIMM types
+/// @param[out] o_dimm_type DIMM types
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode get_dimm_type<mss::proc_type::AXONE>(
+ const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
+ uint8_t* o_dimm_type)
+{
+ using TT = mss::frequency_traits<mss::proc_type::AXONE>;
+
+ uint8_t l_dimm_type[TT::MAX_DIMM_PER_PORT] = {0};
+ FAPI_TRY(mss::attr::get_dimm_type(i_target, l_dimm_type));
+ std::copy(&l_dimm_type[0], &l_dimm_type[0] + TT::MAX_DIMM_PER_PORT, &o_dimm_type[0]);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Calls out the code if we calculated a bad frequency for the domain - specialization for Axone and MEM_PORT
+/// @param[in] i_target target on which to operate
+/// @param[in] i_final_freq frequency calculated for domain
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode callout_bad_freq_calculated<mss::proc_type::AXONE>(
+ const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
+ const uint64_t i_final_freq)
+{
+ using TT = mss::frequency_traits<mss::proc_type::AXONE>;
+
+ // 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;
+
+ // 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(), i_final_freq) ||
+ i_final_freq == 0,
+ fapi2::P9A_MSS_BAD_FREQ_CALCULATED()
+ .set_MSS_FREQ(i_final_freq)
+ .set_TARGET(i_target)
+ .set_PROC_TYPE(mss::proc_type::AXONE)
+ .set_SUPPORTED_FREQ_0(FREQ0)
+ .set_SUPPORTED_FREQ_1(FREQ1)
+ .set_SUPPORTED_FREQ_2(FREQ2),
+ "%s: Calculated FREQ (%d) isn't supported",
+ mss::c_str(i_target),
+ i_final_freq);
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Return a list of configured ranks on a MEM_PORT
+/// @param[in] i_target the port target
+/// @param[out] o_ranks list of valid ranks on the port
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+// TK this function should get replaced by our rank API when available
+fapi2::ReturnCode get_ranks_for_vpd(
+ const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
+ std::vector<uint64_t>& o_ranks)
+{
+ using TT = mss::frequency_traits<mss::proc_type::AXONE>;
+
+ uint8_t l_rank_count_dimm[TT::MAX_DIMM_PER_PORT] = {};
+ uint8_t l_dimm_type[TT::MAX_DIMM_PER_PORT] = {};
+
+ o_ranks.clear();
+
+ FAPI_TRY( get_master_rank_per_dimm<mss::proc_type::AXONE>(i_target, &(l_rank_count_dimm[0])) );
+ FAPI_TRY( get_dimm_type<mss::proc_type::AXONE>(i_target, &(l_dimm_type[0])) );
+
+ // So for LRDIMM, our SI works a bit differently than for non-LRDIMM
+ // LRDIMM's have buffers that operate on a per-DIMM basis across multiple ranks
+ // As such, they act as a single load, similar to a 1R DIMM would
+ // per the IBM signal integrity team, the 1R DIMM settings should be used for LRDIMM's
+ // So, if we are LRDIMM's and have ranks, we want to only note it as a 1R DIMM for purposes of querying the VPD
+ FAPI_DBG("%s for DIMM 0 rank count %u dimm type %u %s",
+ mss::c_str(i_target), l_rank_count_dimm[0], l_dimm_type[0], l_dimm_type[0] == TT::LRDIMM_TYPE ? "LRDIMM" : "RDIMM");
+ FAPI_DBG("%s for DIMM 1 rank count %u dimm type %u %s",
+ mss::c_str(i_target), l_rank_count_dimm[1], l_dimm_type[1], l_dimm_type[1] == TT::LRDIMM_TYPE ? "LRDIMM" : "RDIMM");
+
+ l_rank_count_dimm[0] = ((l_dimm_type[0] == TT::LRDIMM_TYPE) && (l_rank_count_dimm[0] > 0)) ? 1 : l_rank_count_dimm[0];
+ l_rank_count_dimm[1] = ((l_dimm_type[1] == TT::LRDIMM_TYPE) && (l_rank_count_dimm[1] > 0)) ? 1 : l_rank_count_dimm[1];
+
+ FAPI_DBG("after LR modification %s for DIMM 0 rank count %u dimm type %u %s",
+ mss::c_str(i_target), l_rank_count_dimm[0], l_dimm_type[0], l_dimm_type[0] == TT::LRDIMM_TYPE ? "LRDIMM" : "RDIMM");
+ FAPI_DBG("after LR modification %s for DIMM 1 rank count %u dimm type %u %s",
+ mss::c_str(i_target), l_rank_count_dimm[1], l_dimm_type[1], l_dimm_type[1] == TT::LRDIMM_TYPE ? "LRDIMM" : "RDIMM");
+
+ // Add DIMM0's ranks
+ for (uint64_t l_rank = 0; l_rank < l_rank_count_dimm[0]; ++l_rank)
+ {
+ o_ranks.push_back(l_rank);
+ }
+
+ // Add DIMM1's ranks
+ for (uint64_t l_rank = 0; l_rank < l_rank_count_dimm[1]; ++l_rank)
+ {
+ o_ranks.push_back(l_rank + TT::MAX_PRIMARY_RANK_PER_DIMM);
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Check VPD config for support of a given freq - Axone specialization
+/// @param[in] i_target the target on which to operate
+/// @param[in] i_proposed_freq frequency to check for support
+/// @param[out] o_supported true if VPD supports the proposed frequency
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode check_freq_support_vpd<mss::proc_type::AXONE>( const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>&
+ i_target,
+ const uint64_t i_proposed_freq,
+ bool& o_supported)
+{
+ using TT = mss::frequency_traits<mss::proc_type::AXONE>;
+ o_supported = false;
+
+ std::vector<uint64_t> l_ranks;
+ fapi2::VPDInfo<TT::VPD_TARGET_TYPE> l_vpd_info(TT::VPD_BLOB);
+
+ const auto& l_vpd_target = mss::find_target<TT::VPD_TARGET_TYPE>(i_target);
+
+ l_vpd_info.iv_is_config_ffdc_enabled = false;
+
+ FAPI_TRY(convert_ddr_freq_to_omi_freq(i_target, i_proposed_freq, l_vpd_info.iv_omi_freq_mhz));
+ FAPI_INF("Setting VPD info OMI frequency: %d Gbps, for DDR frequency %d MT/s",
+ l_vpd_info.iv_omi_freq_mhz, i_proposed_freq);
+
+ // DDIMM SPD can contain different SI settings for each master rank.
+ // To determine which frequencies are supported, we have to check for each valid
+ // master rank on the port's DIMMs
+ FAPI_TRY(get_ranks_for_vpd(i_target, l_ranks));
+
+ for (const auto l_rank : l_ranks)
+ {
+ l_vpd_info.iv_rank = l_rank;
+ FAPI_INF("%s. VPD info - checking rank: %d",
+ mss::c_str(i_target), l_rank);
+
+ // Check if this VPD configuration is supported
+ FAPI_TRY(is_vpd_config_supported<mss::proc_type::AXONE>(l_vpd_target, i_proposed_freq, l_vpd_info, o_supported),
+ "%s failed to determine if %u freq is supported", mss::c_str(i_target), i_proposed_freq);
+
+
+ // If we fail any of the ranks, then this VPD configuration is not supported
+ if(o_supported == false)
+ {
+ FAPI_INF("%s is not supported on rank%u exiting...", mss::c_str(i_target), l_rank);
+ break;
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Update supported frequency scoreboard according to processor limits - specialization for Axone and MEM_PORT
+/// @param[in] i_target processor frequency domain
+/// @param[in,out] io_scoreboard scoreboard of port targets supporting each frequency
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode limit_freq_by_processor<mss::proc_type::AXONE>(
+ const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
+ freq_scoreboard& io_scoreboard)
+{
+ std::vector<uint64_t> l_converted_omi_freqs;
+
+ // OCMB always needs to be in sync between OMI and DDR, by the given ratio
+ // so we convert the supported OMI freqs and remove every other DDR freq
+ // from the scoreboard
+ for (const auto l_omi_freq : AXONE_OMI_FREQS)
+ {
+ uint64_t l_ddr_freq = 0;
+ FAPI_TRY(convert_omi_freq_to_ddr_freq(i_target, l_omi_freq, l_ddr_freq));
+ l_converted_omi_freqs.push_back(l_ddr_freq);
+ }
+
+ FAPI_TRY(io_scoreboard.remove_freqs_not_on_list(0, l_converted_omi_freqs));
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Gets the number of master ranks on each DIMM - specialization for the Axone processor type
+/// @param[in] i_target DIMM target
+/// @param[out] o_master_ranks number of master ranks
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode num_master_ranks_per_dimm<mss::proc_type::AXONE>(
+ const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ uint8_t& o_master_ranks)
+{
+ return mss::attr::get_num_master_ranks_per_dimm(i_target, o_master_ranks);
+}
+
+///
+/// @brief Calls out the target if no DIMM frequencies are supported - specialization for Axone and MEM_PORT
+/// @param[in] i_target target on which to operate
+/// @param[in] i_supported_freq true if any FREQ's are supported
+/// @param[in,out] i_num_ports number of configured ports (always 1 for Axone)
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode callout_no_common_freq<mss::proc_type::AXONE>(
+ const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
+ const bool i_supported_freq,
+ const uint64_t i_num_ports)
+{
+ uint32_t l_max_mrw_freqs[NUM_MAX_FREQS] = {0};
+ FAPI_TRY( mss::attr::get_max_allowed_dimm_freq(l_max_mrw_freqs) );
+
+ FAPI_ASSERT(i_supported_freq,
+ fapi2::P9A_MSS_NO_SUPPORTED_FREQ()
+ .set_MEM_PORT_TARGET(i_target)
+ .set_MRW_MAX_FREQ_0(l_max_mrw_freqs[0])
+ .set_MRW_MAX_FREQ_1(l_max_mrw_freqs[1])
+ .set_MRW_MAX_FREQ_2(l_max_mrw_freqs[2])
+ .set_MRW_MAX_FREQ_3(l_max_mrw_freqs[3])
+ .set_MRW_MAX_FREQ_4(l_max_mrw_freqs[4]),
+ "%s didn't find a frequency that was supported on any ports", mss::c_str(i_target));
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Calls out the target if no DIMM frequencies are supported - specialization for Axone and MEM_PORT
+/// @param[in] i_target target on which to operate
+/// @param[in] i_vpd_supported_freqs VPD supported frequencies for the callout
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+template<>
+fapi2::ReturnCode callout_max_freq_empty_set<mss::proc_type::AXONE>(
+ const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
+ const std::vector<std::vector<uint32_t>>& i_vpd_supported_freqs)
+{
+
+ std::vector<uint32_t> l_port_vpd_max_freq;
+
+ // Get the max freq supported on each port
+ for ( const auto& l_port_supported_freqs : i_vpd_supported_freqs )
+ {
+ l_port_vpd_max_freq.push_back(l_port_supported_freqs.back());
+ }
+
+ uint32_t l_max_mrw_freqs[NUM_MAX_FREQS] = {0};
+ FAPI_TRY( mss::attr::get_max_allowed_dimm_freq(l_max_mrw_freqs) );
+
+ FAPI_ASSERT(false,
+ fapi2::P9A_MSS_MRW_FREQ_MAX_FREQ_EMPTY_SET()
+ .set_MSS_VPD_FREQ_0(l_port_vpd_max_freq[0])
+ .set_MSS_VPD_FREQ_1(l_port_vpd_max_freq[1])
+ .set_MSS_VPD_FREQ_2(l_port_vpd_max_freq[2])
+ .set_MSS_MAX_FREQ_0(l_max_mrw_freqs[0])
+ .set_MSS_MAX_FREQ_1(l_max_mrw_freqs[1])
+ .set_MSS_MAX_FREQ_2(l_max_mrw_freqs[2])
+ .set_MSS_MAX_FREQ_3(l_max_mrw_freqs[3])
+ .set_MSS_MAX_FREQ_4(l_max_mrw_freqs[4])
+ .set_OMI_FREQ_0(fapi2::ENUM_ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_SERDES_21_33GBPS)
+ .set_OMI_FREQ_1(fapi2::ENUM_ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_SERDES_23_46GBPS)
+ .set_OMI_FREQ_2(fapi2::ENUM_ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_SERDES_25_60GBPS)
+ .set_PORT_TARGET(i_target),
+ "%s didn't find a supported frequency for the port", mss::c_str(i_target));
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+namespace check
+{
+
+///
+/// @brief Checks the final frequency for the system type - Axone and MEM_PORT specialization
+/// @param[in] i_target the target on which to operate
+/// @return FAPI2_RC_SUCCESS iff okay
+/// @note This function was needed in Nimbus to enforce a frequency limit due to a hardware limitation
+/// and is not needed here.
+///
+template<>
+fapi2::ReturnCode final_freq<mss::proc_type::AXONE>(const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target)
+{
+ return fapi2::FAPI2_RC_SUCCESS;
+}
+
+} // ns check
+
+} // ns mss
diff --git a/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_sync.C b/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_sync.C
index a2ea450e7..311e12cf7 100644
--- a/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_sync.C
+++ b/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_sync.C
@@ -22,3 +22,253 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
+
+///
+/// @file axone_sync.C
+/// @brief Synchronous function implementations for Axone
+///
+// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
+// *HWP HWP Backup: Louis Stermole <stermole@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 3
+// *HWP Consumed by: HB:FSP
+
+#include <fapi2.H>
+#include <vpd_access.H>
+#include <algorithm>
+#include <vector>
+#include <map>
+
+// Memory libraries
+#include <lib/freq/axone_freq_traits.H>
+#include <lib/freq/axone_sync.H>
+#include <mss_explorer_attribute_getters.H>
+
+// Generic libraries
+#include <mss_generic_attribute_getters.H>
+#include <generic/memory/lib/utils/assert_noexit.H>
+#include <generic/memory/lib/utils/find.H>
+#include <generic/memory/lib/utils/count_dimm.H>
+#include <generic/memory/lib/spd/spd_facade.H>
+#include <generic/memory/lib/spd/spd_utils.H>
+#include <generic/memory/lib/utils/conversions.H>
+#include <generic/memory/lib/utils/freq/gen_mss_freq.H>
+#include <generic/memory/lib/utils/freq/mss_freq_scoreboard.H>
+
+namespace mss
+{
+
+///
+/// @brief Retrieves a mapping of MSS frequency values per port target
+/// @param[in] i_targets vector of port targets
+/// @param[out] o_freq_map dimm speed map <key, value> = (port target, frequency)
+/// @param[out] o_is_speed_equal holds whether map dimm speed is equal
+/// @return FAPI2_RC_SUCCESS iff successful
+///
+fapi2::ReturnCode dimm_speed_map(const std::vector< fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT> >& i_targets,
+ std::map< fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>, uint64_t >& o_freq_map,
+ speed_equality& o_is_speed_equal)
+{
+ o_freq_map.clear();
+
+ // The find_if loop is meant to find the "first" good (non-zero) freq value
+ // so I can compare it against all other freq values from the MEM_PORT vector
+ // I am checking to make sure I don't get a value of 0
+ // Since Cronus can hand me back a MEM_PORT w/no DIMMs
+ // Which would give ATTR_MSS_FREQ value of 0 in p9_mss_freq
+ uint64_t l_comparator = 0;
+ fapi2::ReturnCode l_rc(fapi2::FAPI2_RC_FALSE);
+
+ const auto l_found_comp = std::find_if(i_targets.begin(), i_targets.end(),
+ [&l_rc, &l_comparator] (const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target)->bool
+ {
+ l_rc = mss::attr::get_freq(i_target, l_comparator);
+ return l_comparator != 0;
+ });
+
+ // Getting error cross initializing with the Assert
+ // find_if should work if passed in an empty vector. begin() and end() will match and it'll exit without trying freq()
+ FAPI_ASSERT( !i_targets.empty(),
+ fapi2::MSS_EMPTY_FREQ_TARGET_VECTOR_PASSED(),
+ "Empty MEM_PORT target vector found when constructing dimm speed mapping!" );
+
+ FAPI_TRY(l_rc, "Failed accessor mss::freq()");
+
+ // If all MEM_PORTs are 0 we go no further
+ // We shouldn't get here though. We check for DIMMS in freq_system. If no DIMMS, we exit
+ // We can assume if there is a dimm configured at this point (after mss_freq)
+ // It has a valid freq
+ // Thus, this shouldn't ever happen, but let's check anyways
+ FAPI_ASSERT( l_found_comp != i_targets.end(),
+ fapi2::MSS_ALL_TARGETS_HAVE_0_FREQ()
+ .set_VECTOR_SIZE(i_targets.size()),
+ "All MEM_PORTs have 0 MSS_FREQ, but there are dimms?");
+
+ // DIMM speed is equal until we deduce otherwise
+ o_is_speed_equal = speed_equality::EQUAL_DIMM_SPEEDS;
+
+ // Make sure to stick the first one we found in the freq map.
+ o_freq_map.emplace( std::make_pair(*l_found_comp, l_comparator) );
+
+ // Loop through all MEM_PORTs and store dimm speeds
+ // Starting from 1st known good freq (non-zero) value
+ // I found above to avoid double looping target vector
+ for (auto l_iter = l_found_comp + 1; l_iter != i_targets.end(); ++l_iter)
+ {
+ uint64_t l_dimm_speed = 0;
+ FAPI_TRY( mss::attr::get_freq(*l_iter, l_dimm_speed), "Failed accessor to mss_freq" );
+
+ // In FW, parents are deconfigured if they have no children
+ // So there is no way to get a MEM_PORT w/no DIMMs.
+ // This isn't true for Cronus so I am skipping map
+ // insertion and check for dimm speed equality
+ // to avoid incorrect settings
+ if( l_dimm_speed != 0)
+ {
+ // At least one mismatch freq value occurred
+ if(l_comparator != l_dimm_speed)
+ {
+ o_is_speed_equal = speed_equality::NOT_EQUAL_DIMM_SPEEDS;
+ }
+
+ FAPI_INF("%s: Dimm speed %d MT/s", c_str(*l_iter), l_dimm_speed);
+
+ o_freq_map.emplace( std::make_pair(*l_iter, l_dimm_speed) );
+ }
+ }
+
+ // Idiot check - most certainly a programming error
+ FAPI_ASSERT( o_freq_map.size() != 0,
+ fapi2::MSS_ERROR_FINDING_DIMM_SPEED_MAP(),
+ "freq system freq map is empty? found port: %s",
+ mss::c_str(*l_found_comp) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Deconfigures MEM_PORT targets
+/// @param[in] i_target the port target
+/// @param[in] i_dimm_speed dimm speed in MT/s
+/// @param[in] i_max_freq maximum dimm freq in MT/s of freq domain
+/// @return true if hardware was deconfigured
+///
+bool deconfigure(const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
+ const uint64_t i_dimm_speed,
+ const uint32_t i_max_freq)
+{
+ bool l_is_hw_deconfigured = (i_dimm_speed != i_max_freq);
+
+ MSS_ASSERT_NOEXIT(!l_is_hw_deconfigured,
+ fapi2::MSS_FREQ_NOT_EQUAL_MAX_DOMAIN_FREQ()
+ .set_MSS_FREQ(i_dimm_speed)
+ .set_DOMAIN_FREQ(i_max_freq)
+ .set_DOMAIN_TARGET(i_target),
+ "Deconfiguring %s due to unequal frequencies: this port: %d, Max in freq domain: %d",
+ mss::c_str(i_target),
+ i_dimm_speed,
+ i_max_freq );
+
+ return l_is_hw_deconfigured;
+}
+
+///
+/// @brief Selects synchronous mode and performs requirements enforced by selected port frequency
+/// @param[in] i_freq_map dimm speed mapping
+/// @param[in] i_equal_dimm_speed tracks whether map has equal dimm speeds
+/// @param[in] i_omi_freq OMI frequency
+/// @param[out] o_selected_sync_mode final synchronous mode
+/// @param[out] o_selected_omi_freq final freq selected, only valid if final sync mode is in-sync
+/// @return FAPI2_RC_SUCCESS iff successful
+///
+fapi2::ReturnCode select_sync_mode(const std::map< fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>, uint64_t >& i_freq_map,
+ const speed_equality i_equal_dimm_speed,
+ const uint32_t i_omi_freq,
+ uint8_t& o_selected_sync_mode,
+ uint64_t& o_selected_omi_freq)
+{
+ FAPI_INF("---- In select_sync_mode ----");
+
+ switch(i_equal_dimm_speed)
+ {
+ // If we have a port which has resolved to equal speeds ...
+ case speed_equality::EQUAL_DIMM_SPEEDS:
+ {
+ // Return back the resulting speed. It doesn't matter which we select from the map as they're all equal
+ // If we end up not in sync in the conditional below, thats ok - this parameter is ignored by the
+ // caller if we're not in sync mode
+ const auto l_ddr_freq = i_freq_map.begin()->second;
+ FAPI_TRY(convert_ddr_freq_to_omi_freq(i_freq_map.begin()->first, l_ddr_freq, o_selected_omi_freq));
+
+ // When we selected ATTR_MSS_FREQ, we made sure that we didn't
+ // select a DIMM freq the OMI couldn't support.
+ o_selected_sync_mode = fapi2::ENUM_ATTR_MC_SYNC_MODE_IN_SYNC;
+ // On Cronus if the o_selected_omi_freq != i_omi_freq we've got a mismatch. Note that p9a_mss_freq ensures
+ // we don't select an invalid freq, but doesn't ensure we select the current OMI freq.
+#ifndef __HOSTBOOT_MODULE
+ FAPI_ASSERT(o_selected_omi_freq == i_omi_freq,
+ fapi2::P9A_MSS_FAILED_SYNC_MODE()
+ .set_OMI_FREQ(i_omi_freq)
+ .set_MEM_FREQ(o_selected_omi_freq),
+ "The DIMM freq (%d) and the OMI freq (%d) don't align",
+ o_selected_omi_freq, i_omi_freq);
+#endif
+ return fapi2::FAPI2_RC_SUCCESS;
+ break;
+ }
+
+ case speed_equality::NOT_EQUAL_DIMM_SPEEDS:
+ {
+ // When we selected ATTR_MSS_FREQ, we made sure that we didn't
+ // select a DIMM freq the OMI couldn't support. That means that the fastest of the ports
+ // is the one that rules the roost (the OMI can support it too.) So find that, and set it to
+ // the selected frequency. Then deconfigure the slower port (unless we're in Cronus in which
+ // case we just bomb out.)
+#ifdef __HOSTBOOT_MODULE
+ uint64_t l_max_dimm_speed = 0;
+ fapi2::Target<TARGET_TYPE_MEM_PORT> l_fastest_port_target = i_freq_map.begin()->first;
+ std::for_each(i_freq_map.begin(), i_freq_map.end(),
+ [&l_max_dimm_speed](const std::pair<fapi2::Target<TARGET_TYPE_MEM_PORT>, uint64_t>& m)
+ {
+ l_max_dimm_speed = std::max(l_max_dimm_speed, m.second);
+ l_fastest_port_target = m.first;
+ });
+
+ std::for_each(i_freq_map.begin(), i_freq_map.end(),
+ [&l_max_dimm_speed](const std::pair<fapi2::Target<TARGET_TYPE_MEM_PORT>, uint64_t>& m)
+ {
+ deconfigure(m.first, m.second, l_max_dimm_speed);
+ });
+
+ o_selected_sync_mode = fapi2::ENUM_ATTR_MC_SYNC_MODE_IN_SYNC;
+ FAPI_TRY(convert_ddr_freq_to_omi_freq(l_fastest_port_target, l_max_dimm_speed, o_selected_omi_freq));
+ return fapi2::FAPI2_RC_SUCCESS;
+#else
+ // Cronus only
+ FAPI_ASSERT(false,
+ fapi2::P9A_MSS_FAILED_SYNC_MODE()
+ .set_OMI_FREQ(i_omi_freq),
+ "DIMM speeds differ from OMI speed %d", i_omi_freq);
+#endif
+ break;
+ }
+
+ default:
+ // Switches on an enum class
+ // The only valid speed_equality values are NOT_EQUAL and EQUAL.
+ // If it's something else ,I think it's a code error and really shouldn't be possible, thus fapi2::Assert below
+ FAPI_ERR("Invalid speed_equality parameter!");
+ fapi2::Assert(false);
+ break;
+ }// end switch
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+#ifndef __HOSTBOOT_MODULE
+fapi_try_exit:
+ return fapi2::current_err;
+#endif
+}
+
+}// mss
diff --git a/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_sync.H b/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_sync.H
index 7b8cb4fe9..06345713c 100644
--- a/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_sync.H
+++ b/src/import/chips/p9a/procedures/hwp/memory/lib/freq/axone_sync.H
@@ -22,3 +22,183 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
+
+///
+/// @file axone_sync.H
+/// @brief Synchronous function implementations for Axone
+///
+// *HWP HWP Owner: Andre Marin <aamarin@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_SYNC_H_
+#define _MSS_SYNC_H_
+
+#include <map>
+#include <vector>
+
+#include <fapi2.H>
+#include <mss_generic_attribute_getters.H>
+#include <generic/memory/lib/utils/shared/mss_generic_consts.H>
+#include <lib/shared/axone_consts.H>
+#include <generic/memory/lib/utils/freq/mss_freq_scoreboard.H>
+#include <generic/memory/lib/utils/c_str.H>
+#include <generic/memory/lib/utils/mss_math.H>
+
+namespace mss
+{
+
+// List of the OMI frequencies for Axone
+// Note: these need to be sorted so binary search works
+static const std::vector<uint64_t> AXONE_OMI_FREQS =
+{
+ 21330, // fapi2::ENUM_ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_SERDES_21_33GBPS,
+ 23460, // fapi2::ENUM_ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_SERDES_23_46GBPS,
+ 25600, // fapi2::ENUM_ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_SERDES_25_60GBPS,
+};
+
+///
+/// @brief Converts an OMI frequency attribute enum to the corresponding OMI frequency
+/// @param[in] i_omi_enum a frequency enum value that is to be converted
+/// @return the corresponding OMI frequency
+///
+inline uint64_t convert_omi_freq_attr_to_freq(const fapi2::ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_Type
+ i_omi_enum)
+{
+ switch (i_omi_enum)
+ {
+ case fapi2::ENUM_ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_SERDES_21_33GBPS:
+ return 21330;
+
+ case fapi2::ENUM_ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_SERDES_23_46GBPS:
+ return 23460;
+
+ case fapi2::ENUM_ATTR_MSS_OCMB_EXP_BOOT_CONFIG_SERDES_FREQUENCY_SERDES_25_60GBPS:
+ return 25600;
+
+ default:
+ FAPI_ASSERT( false,
+ fapi2::P9A_MSS_UNSUPPORTED_OMI_FREQ()
+ .set_OMI_FREQ_ENUM(i_omi_enum),
+ "freq system saw an unsupported OMI frequency with enum value: %d",
+ i_omi_enum );
+ }
+
+fapi_try_exit:
+ return 0;
+}
+
+///
+/// @brief Converts a DDR frequency to the corresponding OMI frequency
+/// @param[in] i_target the port target
+/// @param[in] i_ddr_freq a frequency value that is to be converted
+/// @param[out] o_omi_freq the corresponding OMI frequency
+/// @return FAPI2_RC_SUCCESS iff successful
+///
+inline fapi2::ReturnCode convert_ddr_freq_to_omi_freq(const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
+ const uint64_t i_ddr_freq,
+ uint64_t& o_omi_freq)
+{
+ using TT = mss::frequency_traits<mss::proc_type::AXONE>;
+ constexpr uint64_t ROUND_UNITS = 10;
+
+ // Get the OMI to DDR freq ratio
+ uint8_t l_ratio[TT::MAX_DIMM_PER_PORT] = {0};
+ FAPI_TRY(mss::attr::get_host_to_ddr_speed_ratio(i_target, l_ratio));
+
+ // Multiply by the ratio and round to the nearest 10GBPS
+ FAPI_TRY(mss::divide_and_round((i_ddr_freq * l_ratio[0]), ROUND_UNITS, o_omi_freq));
+ o_omi_freq *= ROUND_UNITS;
+ FAPI_DBG("For ratio %d and DDR freq %d, corresponding OMI freq is %d", l_ratio[0], i_ddr_freq, o_omi_freq);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Converts an OMI frequency to the corresponding DDR frequency
+/// @param[in] i_target the port target
+/// @param[in] i_omi_freq a frequency value that is to be converted
+/// @param[out] o_ddr_freq the corresponding DDR frequency
+/// @return FAPI2_RC_SUCCESS iff successful
+///
+inline fapi2::ReturnCode convert_omi_freq_to_ddr_freq(const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
+ const uint64_t i_omi_freq,
+ uint64_t& o_ddr_freq)
+{
+ using TT = mss::frequency_traits<mss::proc_type::AXONE>;
+
+ // Get the OMI to DDR freq ratio
+ uint8_t l_ratio[TT::MAX_DIMM_PER_PORT] = {0};
+ FAPI_TRY(mss::attr::get_host_to_ddr_speed_ratio(i_target, l_ratio));
+
+ FAPI_TRY(mss::divide_and_round(i_omi_freq, static_cast<uint64_t>(l_ratio[0]), o_ddr_freq),
+ "%s freq system saw a zero Host (OMI) to DDR frequency ratio", mss::c_str(i_target));
+ FAPI_DBG( "For ratio %d and OMI freq %d, corresponding DDR freq is %d", l_ratio[0], i_omi_freq, o_ddr_freq);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Checks to see if a passed in value could be a valid OMI frequency
+/// @param[in] i_target the port target
+/// @param[in] i_proposed_freq a frequency value that is to be checked
+/// @param[out] o_valid boolean whether the value is a valid OMI frequency
+/// @return FAPI2_RC_SUCCESS iff successful
+///
+inline fapi2::ReturnCode is_omi_freq_valid (const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
+ const uint64_t i_proposed_freq,
+ uint64_t& o_valid)
+{
+ uint64_t l_proposed_omi_freq = 0;
+ FAPI_TRY(convert_ddr_freq_to_omi_freq(i_target, i_proposed_freq, l_proposed_omi_freq));
+
+ o_valid = std::binary_search(AXONE_OMI_FREQS.begin(), AXONE_OMI_FREQS.end(), l_proposed_omi_freq);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Retrieves a mapping of MSS frequency values per port target
+/// @param[in] i_targets vector of port targets
+/// @param[out] o_freq_map dimm speed map <key, value> = (port target, frequency)
+/// @param[out] o_is_speed_equal holds whether map dimm speed is equal
+/// @return FAPI2_RC_SUCCESS iff successful
+///
+fapi2::ReturnCode dimm_speed_map(const std::vector< fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT> >& i_targets,
+ std::map< fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>, uint64_t >& o_freq_map,
+ speed_equality& o_is_speed_equal);
+
+///
+/// @brief Helper function to deconfigure MEM_PORT target
+/// @param[in] i_target the port target
+/// @param[in] i_dimm_speed dimm speed in MT/s
+/// @param[in] i_omi_freq OMI freq in MHz
+/// @return true if hardware was deconfigured
+///
+bool deconfigure(const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target,
+ const uint64_t i_dimm_speed,
+ const uint32_t i_omi_freq);
+
+///
+/// @brief Selects synchronous mode and performs requirements enforced by selected port frequency
+/// @param[in] i_freq_map dimm speed mapping
+/// @param[in] i_equal_dimm_speed tracks whether map has equal dimm speeds
+/// @param[in] i_omi_freq OMI frequency
+/// @param[out] o_selected_sync_mode final synchronous mode
+/// @param[out] o_selected_omi_freq final freq selected, only valid if final sync mode is in-sync
+/// @return FAPI2_RC_SUCCESS iff successful
+///
+fapi2::ReturnCode select_sync_mode(const std::map< fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>, uint64_t >& i_freq_map,
+ const speed_equality i_equal_dimm_speed,
+ const uint32_t i_omi_freq,
+ uint8_t& o_selected_sync_mode,
+ uint64_t& o_selected_omi_freq);
+
+}// mss
+
+#endif
diff --git a/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_eff_config.C b/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_eff_config.C
index 4fc51a28e..75d23c6af 100644
--- a/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_eff_config.C
+++ b/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_eff_config.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2018 */
+/* Contributors Listed Below - COPYRIGHT 2018,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -42,6 +42,8 @@
#include <vpd_access.H>
#include <mss_generic_attribute_getters.H>
#include <lib/eff_config/explorer_attr_engine_traits.H>
+#include <lib/freq/axone_freq_traits.H>
+#include <lib/freq/axone_sync.H>
///
/// @brief Configure the attributes for each controller
@@ -53,21 +55,15 @@ fapi2::ReturnCode p9a_mss_eff_config( const fapi2::Target<fapi2::TARGET_TYPE_MEM
// Workaround until DIMM level attrs work
uint8_t l_ranks[mss::exp::MAX_DIMM_PER_PORT] = {};
- // Get EFD size - should only need to do it once
- const auto l_ocmb = mss::find_target<fapi2::TARGET_TYPE_OCMB_CHIP>(i_target);
- fapi2::MemVpdData_t l_vpd_type(fapi2::EFD);
- fapi2::VPDInfo<fapi2::TARGET_TYPE_OCMB_CHIP> l_vpd_info(l_vpd_type);
- FAPI_TRY( fapi2::getVPD(l_ocmb, l_vpd_info, nullptr) );
-
FAPI_TRY( mss::attr::get_num_master_ranks_per_dimm(i_target, l_ranks) );
for(const auto& dimm : mss::find_targets<fapi2::TARGET_TYPE_DIMM>(i_target))
{
uint8_t l_dimm_index = 0;
uint64_t l_freq = 0;
+ uint64_t l_omi_freq = 0;
FAPI_TRY( mss::attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(dimm), l_freq) );
-
- FAPI_TRY( mss::attr_derived_engine<mss::generic_metadata_fields>::set(dimm) );
+ FAPI_TRY( mss::convert_ddr_freq_to_omi_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(dimm), l_freq, l_omi_freq));
// Quick hack to get the index until DIMM level attrs work
FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_REL_POS, dimm, l_dimm_index) );
@@ -76,9 +72,15 @@ fapi2::ReturnCode p9a_mss_eff_config( const fapi2::Target<fapi2::TARGET_TYPE_MEM
{
std::shared_ptr<mss::efd::base_decoder> l_efd_data;
- // Get EFD data
+ // Get EFD size
+ const auto l_ocmb = mss::find_target<fapi2::TARGET_TYPE_OCMB_CHIP>(i_target);
+ fapi2::MemVpdData_t l_vpd_type(fapi2::MemVpdData::EFD);
+ fapi2::VPDInfo<fapi2::TARGET_TYPE_OCMB_CHIP> l_vpd_info(l_vpd_type);
l_vpd_info.iv_rank = rank;
- l_vpd_info.iv_omi_freq_mhz = l_freq;
+ l_vpd_info.iv_omi_freq_mhz = l_omi_freq;
+ FAPI_TRY( fapi2::getVPD(l_ocmb, l_vpd_info, nullptr), "failed getting VPD size from getVPD" );
+
+ // Get EFD data
std::vector<uint8_t> l_vpd_raw (l_vpd_info.iv_size, 0);
FAPI_TRY( fapi2::getVPD(l_ocmb, l_vpd_info, l_vpd_raw.data()) );
diff --git a/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.C b/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.C
index 7591689e2..342523d5a 100644
--- a/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.C
+++ b/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2018 */
+/* Contributors Listed Below - COPYRIGHT 2018,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -30,14 +30,23 @@
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP HWP Backup: Louis Stermole <stermole@us.ibm.com>
// *HWP Team: Memory
-// *HWP Level: 1
+// *HWP Level: 2
// *HWP Consumed by: FSP:HB
+// fapi2
+#include <fapi2.H>
+
+// mss lib
#include <p9a_mss_freq.H>
+
+#include <lib/freq/axone_freq_traits.H>
#include <generic/memory/lib/data_engine/p9a/p9a_data_init_traits.H>
+#include <lib/eff_config/explorer_attr_engine_traits.H>
#include <generic/memory/lib/data_engine/data_engine.H>
#include <generic/memory/lib/utils/find.H>
#include <generic/memory/lib/spd/spd_facade.H>
+#include <generic/memory/lib/utils/count_dimm.H>
+#include <generic/memory/lib/utils/freq/gen_mss_freq.H>
///
/// @brief Calculate and save off DIMM frequencies
@@ -46,6 +55,13 @@
///
fapi2::ReturnCode p9a_mss_freq( const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>& i_target )
{
+ // If there are no DIMM, we can just get out.
+ if (mss::count_dimm(i_target) == 0)
+ {
+ FAPI_INF("Seeing no DIMM on %s, no freq to set", mss::c_str(i_target));
+ return fapi2::FAPI2_RC_SUCCESS;
+ }
+
// We will first set pre-eff_config attribes
for(const auto& d : mss::find_targets<fapi2::TARGET_TYPE_DIMM>(i_target))
{
@@ -60,12 +76,12 @@ fapi2::ReturnCode p9a_mss_freq( const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>
FAPI_TRY( l_rc, "Failed to initialize SPD facade for %s", mss::spd::c_str(d) );
FAPI_TRY( mss::attr_eff_engine<mss::pre_data_init_fields>::set(l_spd_decoder) );
+ FAPI_TRY( mss::attr_derived_engine<mss::generic_metadata_fields>::set(d) );
}
- // TK - Remove hard-code FREQ -- Should we have enums? Louis problem now
- uint64_t HARDCODE_FREQ_LOUIS_REMOVE = 25600;
- FAPI_TRY( mss::attr::set_freq(i_target, HARDCODE_FREQ_LOUIS_REMOVE) );
- }// dimm
+ }
+
+ FAPI_TRY(mss::generate_freq<mss::proc_type::AXONE>(i_target));
fapi_try_exit:
return fapi2::current_err;
diff --git a/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.H b/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.H
index 179292a80..e4e20b050 100644
--- a/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.H
+++ b/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2018 */
+/* Contributors Listed Below - COPYRIGHT 2018,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -37,7 +37,6 @@
#define P9A_MSS_FREQ_H_
#include <fapi2.H>
-#include <vector>
typedef fapi2::ReturnCode (*p9a_mss_freq_FP_t) (const fapi2::Target<fapi2::TARGET_TYPE_MEM_PORT>&);
diff --git a/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.mk b/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.mk
index bd2a3e083..47d2c11ea 100644
--- a/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.mk
+++ b/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.mk
@@ -5,7 +5,7 @@
#
# OpenPOWER HostBoot Project
#
-# Contributors Listed Below - COPYRIGHT 2018
+# Contributors Listed Below - COPYRIGHT 2018,2019
# [+] International Business Machines Corp.
#
#
@@ -27,5 +27,5 @@
-include 00p9a_common.mk
PROCEDURE=p9a_mss_freq
-$(eval $(call ADD_MEMORY_INCDIRS,$(PROCEDURE)))
+$(eval $(call ADD_P9A_MEMORY_INCDIRS,$(PROCEDURE)))
$(call BUILD_PROCEDURE)
diff --git a/src/import/chips/p9a/procedures/xml/error_info/p9a_freq_errors.xml b/src/import/chips/p9a/procedures/xml/error_info/p9a_freq_errors.xml
index c83af56bf..37909deb2 100644
--- a/src/import/chips/p9a/procedures/xml/error_info/p9a_freq_errors.xml
+++ b/src/import/chips/p9a/procedures/xml/error_info/p9a_freq_errors.xml
@@ -24,5 +24,117 @@
<!-- IBM_PROLOG_END_TAG -->
<hwpErrors>
+ <hwpError>
+ <rc>RC_P9A_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>TARGET</ffdc>
+ <ffdc>PROC_TYPE</ffdc>
+ <callout>
+ <procedure>CODE</procedure>
+ <priority>HIGH</priority>
+ </callout>
+ </hwpError>
+
+ <!-- Cronus only error when we can't match DIMM speeds to sync mode -->
+ <hwpError>
+ <rc>RC_P9A_MSS_FAILED_SYNC_MODE</rc>
+ <description>
+ DIMM speeds are different and sync mode is required
+ </description>
+ <ffdc>OMI_FREQ</ffdc>
+ <ffdc>MEM_FREQ</ffdc>
+ <callout>
+ <procedure>CODE</procedure>
+ <priority>HIGH</priority>
+ </callout>
+ </hwpError>
+
+ <hwpError>
+ <rc>RC_P9A_MSS_MRW_FREQ_MAX_FREQ_EMPTY_SET</rc>
+ <description>
+ When considering the frequencies in the MRW, the OMI frequency, and the max supported
+ frequencies based on DIMM config (MAX_ALLOWED_DIMM_FREQ), there are no applicable frequencies
+ remaining
+ </description>
+ <ffdc>MSS_VPD_FREQ_0</ffdc>
+ <ffdc>MSS_VPD_FREQ_1</ffdc>
+ <ffdc>MSS_VPD_FREQ_2</ffdc>
+ <ffdc>MSS_MAX_FREQ_0</ffdc>
+ <ffdc>MSS_MAX_FREQ_1</ffdc>
+ <ffdc>MSS_MAX_FREQ_2</ffdc>
+ <ffdc>MSS_MAX_FREQ_3</ffdc>
+ <ffdc>MSS_MAX_FREQ_4</ffdc>
+ <ffdc>OMI_FREQ_0</ffdc>
+ <ffdc>OMI_FREQ_1</ffdc>
+ <ffdc>OMI_FREQ_2</ffdc>
+ <callout>
+ <procedure>CODE</procedure>
+ <priority>HIGH</priority>
+ </callout>
+ <callout>
+ <childTargets>
+ <parent>PORT_TARGET</parent>
+ <childType>TARGET_TYPE_DIMM</childType>
+ </childTargets>
+ <priority>MEDIUM</priority>
+ </callout>
+ </hwpError>
+
+ <hwpError>
+ <rc>RC_P9A_MSS_NO_SUPPORTED_FREQ</rc>
+ <description>
+ When considering the frequencies in the MRW and the max supported
+ frequencies based on DIMM config, there are no applicable frequencies
+ remaining
+ </description>
+ <ffdc>MEM_PORT_TARGET</ffdc>
+ <ffdc>MRW_MAX_FREQ_0</ffdc>
+ <ffdc>MRW_MAX_FREQ_1</ffdc>
+ <ffdc>MRW_MAX_FREQ_2</ffdc>
+ <ffdc>MRW_MAX_FREQ_3</ffdc>
+ <ffdc>MRW_MAX_FREQ_4</ffdc>
+ <callout>
+ <procedure>CODE</procedure>
+ <priority>HIGH</priority>
+ </callout>
+ <callout>
+ <childTargets>
+ <parent>MEM_PORT_TARGET</parent>
+ <childType>TARGET_TYPE_DIMM</childType>
+ </childTargets>
+ <priority>MEDIUM</priority>
+ </callout>
+ </hwpError>
+
+ <hwpError>
+ <rc>RC_P9A_MSS_UNSUPPORTED_OMI_FREQ</rc>
+ <description>
+ Unsupported OMI frequency encountered in mss_freq_system
+ </description>
+ <ffdc>OMI_FREQ_ENUM</ffdc>
+ <callout>
+ <procedure>CODE</procedure>
+ <priority>HIGH</priority>
+ </callout>
+ </hwpError>
+
+ <hwpError>
+ <rc>RC_P9A_MSS_ZERO_HOST_TO_DDR_FREQ_RATIO</rc>
+ <description>
+ Zero OMI to DDR frequency ratio encountered in mss_freq_system
+ </description>
+ <ffdc>PORT_TARGET</ffdc>
+ <callout>
+ <procedure>CODE</procedure>
+ <priority>HIGH</priority>
+ </callout>
+ </hwpError>
</hwpErrors>
OpenPOWER on IntegriCloud