summaryrefslogtreecommitdiffstats
path: root/src/import/generic/memory/lib/utils/freq/gen_mss_freq.H
diff options
context:
space:
mode:
Diffstat (limited to 'src/import/generic/memory/lib/utils/freq/gen_mss_freq.H')
-rw-r--r--src/import/generic/memory/lib/utils/freq/gen_mss_freq.H225
1 files changed, 106 insertions, 119 deletions
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 a70dcebb5..4df0eeb06 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
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2018 */
+/* Contributors Listed Below - COPYRIGHT 2018,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -43,7 +43,6 @@
#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 <generic/memory/lib/utils/count_dimm.H>
#include <vpd_access.H>
@@ -81,7 +80,7 @@ fapi2::ReturnCode set_freq(const fapi2::Target<T>& i_target,
/// @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>
+template<mss::proc_type P, typename TT = mss::frequency_traits<P>, fapi2::TargetType T>
fapi2::ReturnCode get_master_rank_per_dimm(const fapi2::Target<T>& i_target,
uint8_t* o_master_ranks);
@@ -93,56 +92,114 @@ fapi2::ReturnCode get_master_rank_per_dimm(const fapi2::Target<T>& i_target,
/// @param[out] o_dimm_type DIMM types
/// @return FAPI2_RC_SUCCESS iff ok
///
-template<mss::proc_type P, fapi2::TargetType T>
+template<mss::proc_type P, typename TT = mss::frequency_traits<P>, fapi2::TargetType T>
fapi2::ReturnCode get_dimm_type(const fapi2::Target<T>& i_target,
uint8_t* o_dimm_type);
///
-/// @brief Configures the number of ranks in the VPD accessor dependent upon DIMM type
+/// @brief Calls out the code if we calculated a bad frequency for the 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 set the frequency values
-/// @param[in,out] io_vpd_info VPD information that needs to be configured
-/// @return FAPI2_RC_SUCCESS iff ok
+/// @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<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+fapi2::ReturnCode callout_bad_freq_calculated(const fapi2::Target<TT::FREQ_TARGET_TYPE>& i_target,
+ const uint64_t i_final_freq);
+
+///
+/// @brief Configures the number of ranks in the VPD accessor dependent upon DIMM 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 set the frequency values
+/// @param[in,out] io_vpd_info VPD information that needs to be configured
+/// @return FAPI2_RC_SUCCESS iff ok
///
template<mss::proc_type P, typename TT = mss::frequency_traits<P>>
fapi2::ReturnCode configure_vpd_ranks(const fapi2::Target<TT::PORT_TARGET_TYPE>& i_target,
- fapi2::VPDInfo<TT::VPD_TARGET_TYPE>& io_vpd_info)
+ fapi2::VPDInfo<TT::VPD_TARGET_TYPE>& io_vpd_info);
+
+///
+/// @brief Checks to see if a specific VPD configuration is valid
+/// @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_proposed_freq frequency to check for support
+/// @param[in,out] io_vpd_info VPDInfo instance to use
+/// @param[out] o_supported true if VPD supports the proposed frequency
+///
+template<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+fapi2::ReturnCode is_vpd_config_supported( const fapi2::Target<TT::VPD_TARGET_TYPE>& i_target,
+ const uint64_t i_proposed_freq,
+ fapi2::VPDInfo<TT::VPD_TARGET_TYPE>& io_vpd_info,
+ bool& o_supported)
{
- uint8_t l_rank_count_dimm[TT::MAX_DIMM_PER_PORT] = {};
- uint8_t l_dimm_type[TT::MAX_DIMM_PER_PORT] = {};
-
- // 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>(i_target, &(l_rank_count_dimm[0])) );
- FAPI_TRY( get_dimm_type<P>(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");
-
- io_vpd_info.iv_rank_count_dimm_0 = l_rank_count_dimm[0];
- io_vpd_info.iv_rank_count_dimm_1 = l_rank_count_dimm[1];
+ uint8_t l_vpd_blob[TT::VPD_KEYWORD_MAX] = {};
+
+ // We are unsupported by default
+ o_supported = false;
+
+ // 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(i_target, io_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(i_target), i_proposed_freq );
+
+ return fapi2::FAPI2_RC_SUCCESS;
+ }
+
+ // Need temporary variables to avoid issues with FAPI_ASSERT and templated variables
+ {
+ fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
+ const auto VPD_KW_MAX = TT::VPD_KEYWORD_MAX;
+ const auto VPD_BLOB = TT::VPD_BLOB;
+ FAPI_ASSERT( io_vpd_info.iv_size <= TT::VPD_KEYWORD_MAX,
+ fapi2::MSS_INVALID_VPD_KEYWORD_MAX().
+ set_MAX(VPD_KW_MAX).
+ set_ACTUAL(io_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",
+ io_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(i_target, io_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(i_target), i_proposed_freq );
+
+ return fapi2::FAPI2_RC_SUCCESS;
+ }
+
+ // If we made it here, it means the frequency was supported for this config
+ o_supported = true;
fapi_try_exit:
return fapi2::current_err;
}
///
+/// @brief Check VPD config for support of a given freq
+/// @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_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<mss::proc_type P, typename TT = mss::frequency_traits<P>>
+fapi2::ReturnCode check_freq_support_vpd( const fapi2::Target<TT::PORT_TARGET_TYPE>& i_target,
+ const uint64_t i_proposed_freq,
+ bool& o_supported);
+
+///
/// @brief Sets frequency attributes
/// @tparam P mss::proc_type on which to operate
/// @tparam TT Traits associated with the processor type
@@ -169,28 +226,7 @@ inline fapi2::ReturnCode set_freq_attrs(const fapi2::Target<TT::FREQ_TARGET_TYPE
// 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_TRY(callout_bad_freq_calculated<P>(i_target, l_final_freq));
FAPI_INF( "Final Chosen Frequency: %d (%s)", l_final_freq, mss::c_str(i_target) );
@@ -258,7 +294,6 @@ fapi_try_exit:
/// @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
///
@@ -267,8 +302,6 @@ 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_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;
@@ -281,12 +314,9 @@ fapi2::ReturnCode vpd_supported_freqs( const fapi2::Target<TT::FREQ_TARGET_TYPE>
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) );
@@ -302,61 +332,21 @@ fapi2::ReturnCode vpd_supported_freqs( const fapi2::Target<TT::FREQ_TARGET_TYPE>
continue;
}
- // Configures the number of ranks for the VPD configuration
- FAPI_TRY( configure_vpd_ranks<P>(p, l_vpd_info), "%s failed to configure VPD ranks", mss::c_str(p));
- 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;
+ bool l_supported = false;
- 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);
+ FAPI_TRY(check_freq_support_vpd<P>(p, freq, l_supported));
- // 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 )
+ // Add supported freqs to our output
+ if (l_supported)
{
- 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;
+ FAPI_INF("VPD supported freq added: %d for %s", freq, mss::c_str(p) );
+ o_vpd_supported_freqs[l_port_pos].push_back(freq);
}
-
- // 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 )
@@ -468,13 +458,13 @@ inline fapi2::ReturnCode supported_freqs(const fapi2::Target<TT::FREQ_TARGET_TYP
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<uint32_t> l_max_mrw_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( max_allowed_dimm_freq<P>(l_max_mrw_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),
@@ -484,7 +474,7 @@ inline fapi2::ReturnCode supported_freqs(const fapi2::Target<TT::FREQ_TARGET_TYP
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) );
+ FAPI_TRY( limit_freq_by_mrw<P>(i_target, l_max_mrw_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) );
@@ -537,9 +527,6 @@ fapi2::ReturnCode generate_freq(const fapi2::Target<TT::FREQ_TARGET_TYPE>& i_tar
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) );
OpenPOWER on IntegriCloud