From e734170c132ccb53b65d24c5f89955b1250cf150 Mon Sep 17 00:00:00 2001 From: Jacob Harvey Date: Tue, 2 May 2017 11:17:07 -0500 Subject: [PATCH] Change cas latency to be per MCA Change-Id: I61684fe0b69c72dea4c79ad248f8928a007ffb0f Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/40052 Reviewed-by: STEPHEN GLANCY Reviewed-by: Louis Stermole Tested-by: Jenkins Server Tested-by: Hostboot CI Reviewed-by: Thi N. Tran Dev-Ready: JACOB L. HARVEY Reviewed-by: Jennifer A. Stofer Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/40501 Reviewed-by: Hostboot Team Tested-by: Jenkins OP Build CI Reviewed-by: Daniel M. Crowell --- .../hwp/memory/lib/freq/cas_latency.C | 9 +- .../hwp/memory/lib/freq/cas_latency.H | 6 +- .../p9/procedures/hwp/memory/lib/freq/sync.C | 98 ++++++++------- .../p9/procedures/hwp/memory/lib/freq/sync.H | 8 +- .../hwp/memory/lib/spd/spd_factory.C | 53 +-------- .../hwp/memory/lib/spd/spd_factory.H | 55 ++++++++- .../p9/procedures/hwp/memory/p9_mss_freq.C | 112 ++++++++++-------- .../p9/procedures/hwp/memory/p9_mss_freq.H | 45 +++++-- .../xml/error_info/p9_memory_mss_freq.xml | 15 +++ src/import/generic/memory/lib/utils/find.H | 28 ++++- 10 files changed, 247 insertions(+), 182 deletions(-) diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.C b/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.C index 490b0677b76..1a9490a8ed8 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.C @@ -77,7 +77,7 @@ enum invalid_timing_function_encoding /// @param[in] i_caches decoder caches /// @param[out] o_rc returns FAPI2_RC_SUCCESS if constructor initialzed successfully /// -cas_latency::cas_latency(const fapi2::Target& i_target, +cas_latency::cas_latency(const fapi2::Target& i_target, const std::vector< std::shared_ptr >& i_caches, fapi2::ReturnCode& o_rc ): iv_dimm_list_empty(false), @@ -86,7 +86,6 @@ cas_latency::cas_latency(const fapi2::Target& i_target, iv_proposed_tck(0), iv_common_cl(UINT64_MAX) // Masks out supported CLs { - if( i_caches.empty() ) { FAPI_INF("cas latency ctor seeing no SPD caches for %s", mss::c_str(i_target) ); @@ -96,7 +95,7 @@ cas_latency::cas_latency(const fapi2::Target& i_target, for ( const auto& l_cache : i_caches ) { - // Retrive timing values from the SPD + // Retrieve timing values from the SPD uint64_t l_taa_min_in_ps = 0; uint64_t l_tckmax_in_ps = 0; uint64_t l_tck_min_in_ps = 0; @@ -191,7 +190,7 @@ fapi_try_exit: /// @param[in] i_common_cl_mask common CAS latency mask we want to force (bitmap) /// @param[in] i_is_3ds boolean for whether this is a 3DS SDRAM, 3DS is true, false otherwise (default) /// -cas_latency::cas_latency(const fapi2::Target& i_target, +cas_latency::cas_latency(const fapi2::Target& i_target, const uint64_t i_taa_min, const uint64_t i_tck_min, const uint64_t i_common_cl_mask, @@ -244,7 +243,7 @@ fapi2::ReturnCode cas_latency::find_cl(uint64_t& o_cas_latency, } // Update output values after all criteria is met - // If the MCS has no dimm configured than both + // If the MCA has no dimm configured than both // l_desired_latency & iv_proposed_tck is 0 by initialization o_cas_latency = l_desired_cas_latency; o_tck = iv_proposed_tck; diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.H b/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.H index baf44ffaec7..7a323270bd7 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.H @@ -84,7 +84,7 @@ class cas_latency /// @param[in] i_caches decoder caches /// @param[out] o_rc returns FAPI2_RC_SUCCESS if constructor initialzed successfully /// - cas_latency(const fapi2::Target& i_target_mcs, + cas_latency(const fapi2::Target& i_target_mcs, const std::vector< std::shared_ptr >& i_caches, fapi2::ReturnCode& o_rc); @@ -96,7 +96,7 @@ class cas_latency /// @param[in] i_is_3ds loading::IS_3DS if this is for 3DS, /// loading::NOT_3DS otherwise (default) /// - cas_latency(const fapi2::Target& i_target, + cas_latency(const fapi2::Target& i_target, const uint64_t i_taa_min, const uint64_t i_tck_min, const uint64_t i_common_cl_mask, @@ -144,7 +144,7 @@ class cas_latency ///////////////////////// // Private variables ///////////////////////// - fapi2::Target iv_target; + fapi2::Target iv_target; uint64_t iv_largest_taamin;// cas latency time uint64_t iv_proposed_tck;// cycle time uint64_t iv_common_cl; // common cas latency diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.C b/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.C index 73f99cd7ace..5513224d8c4 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.C @@ -300,14 +300,14 @@ fapi_try_exit: /// /// @brief Create and sort a vector of supported MT/s (freq) -/// @param[in] MCS target for which to get the DIMM configs +/// @param[in] MCA target for which to get the DIMM configs /// @param[in,out] reference to a std::vector space to put the sorted vector /// @return FAPI2_RC_SUCCESS iff ok /// @note Taken from ATTR_MSS_MRW_SUPPORTED_FREQ. The result is sorted so such that the min /// supported freq is std::vector<>.begin and the max is std::vector<>.end - 1. You can /// search the resulting vector for valid frequencies as it is sorted. /// -fapi2::ReturnCode supported_freqs(const fapi2::Target& i_target, std::vector& io_freqs) +fapi2::ReturnCode supported_freqs(const fapi2::Target& i_target, std::vector& io_freqs) { std::vector l_freqs(NUM_VPD_FREQS, 0); std::vector l_max_freqs(NUM_MAX_FREQS, 0); @@ -337,7 +337,7 @@ fapi_try_exit: /// /// @brief Create and sort a vector of supported MT/s (freq) - helper for testing purposes -/// @param[in] MCS target for which to get the DIMM configs +/// @param[in] MCA target for which to get the DIMM configs /// @param[in] vector of MVPD freqs /// @param[in] vector of max allowed freqs /// @param[in] bool whether or not we're forced into sync mode @@ -347,7 +347,7 @@ fapi_try_exit: /// testing. So this helper allows us to use the attributes for the main path but /// have a path for testing (DFT I think the cool kids call it.) /// -fapi2::ReturnCode supported_freqs_helper(const fapi2::Target& i_target, +fapi2::ReturnCode supported_freqs_helper(const fapi2::Target& i_target, const std::vector& i_freqs, const std::vector& i_max_freqs, const bool i_req_sync_mode, @@ -388,55 +388,53 @@ fapi2::ReturnCode supported_freqs_helper(const fapi2::Target& i FAPI_INF("max supported freqs %d %d %d %d %d", i_max_freqs[0], i_max_freqs[1], i_max_freqs[2], i_max_freqs[3], i_max_freqs[4]); - // Given the max supported freqs, find the config based on our DIMMs. There's no great way to do this ... - for (const auto& p : mss::find_targets(i_target)) + const auto l_dimms = mss::find_targets(i_target); + uint64_t l_dimms_on_port = l_dimms.size(); + + FAPI_ASSERT( (l_dimms_on_port <= MAX_DIMM_PER_PORT), + fapi2::MSS_TOO_MANY_DIMMS_ON_PORT() + .set_DIMM_COUNT(l_dimms_on_port) + .set_MCA_TARGET(i_target), + "Seeing %d DIMM on port %s", + l_dimms_on_port, + mss::c_str(i_target)); + + for (const auto& d : l_dimms) { - const auto l_dimms = mss::find_targets(p); - uint64_t l_dimms_on_port = l_dimms.size(); - - FAPI_ASSERT( (l_dimms_on_port <= MAX_DIMM_PER_PORT), - fapi2::MSS_TOO_MANY_DIMMS_ON_PORT() - .set_DIMM_COUNT(l_dimms_on_port) - .set_MCA_TARGET(p), - "Seeing %d DIMM on port %s", + uint8_t l_num_master_ranks = 0; + size_t l_index = 0xFF; + + FAPI_TRY( mss::eff_num_master_ranks_per_dimm(d, l_num_master_ranks) ); + + // Just a quick check but we're in deep yogurt if this triggers + FAPI_ASSERT( (l_num_master_ranks <= MAX_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(p)); + mss::c_str(d)); + + l_index = l_indexes[l_dimms_on_port - 1][l_num_master_ranks - 1]; + + 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_index, + i_max_freqs[l_index] ); + + 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)); - for (const auto& d : l_dimms) - { - uint8_t l_num_master_ranks = 0; - size_t l_index = 0xFF; - - FAPI_TRY( mss::eff_num_master_ranks_per_dimm(d, l_num_master_ranks) ); - - // Just a quick check but we're in deep yogurt if this triggers - FAPI_ASSERT( (l_num_master_ranks <= MAX_RANK_PER_DIMM), - fapi2::MSS_TOO_MANY_PRIMARY_RANKS_ON_DIMM() - .set_RANK_COUNT(l_num_master_ranks) - .set_DIMM_TARGET(p), - "seeing %d primary ranks on DIMM %s", - l_dimms_on_port, - 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_freqs[l_indexes[l_dimms_on_port - 1][l_num_master_ranks - 1]] ); - - 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)); - - l_our_max_freq = std::min(l_our_max_freq, i_max_freqs[l_index]); - } + l_our_max_freq = std::min(l_our_max_freq, i_max_freqs[l_index]); } FAPI_INF("after processing DIMM, max freq is %d", l_our_max_freq); diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.H b/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.H index 15f926c1b2d..a5d8dfaffc1 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.H @@ -90,7 +90,7 @@ fapi2::ReturnCode select_sync_mode(const std::map< fapi2::Target.begin and the max is std::vector<>.end - 1. You can /// search the resulting vector for valid frequencies as it is sorted. /// -fapi2::ReturnCode supported_freqs_helper(const fapi2::Target& i_target, +fapi2::ReturnCode supported_freqs_helper(const fapi2::Target& i_target, const std::vector& i_freqs, const std::vector& i_max_freqs, const bool i_req_sync_mode, @@ -108,14 +108,14 @@ fapi2::ReturnCode supported_freqs_helper(const fapi2::Target space to put the sorted vector /// @return FAPI2_RC_SUCCESS iff ok /// @note Taken from ATTR_MSS_MRW_SUPPORTED_FREQ. The result is sorted so such that the min /// supported freq is std::vector<>.begin and the max is std::vector<>.end - 1. You can /// search the resulting vector for valid frequencies as it is sorted. /// -fapi2::ReturnCode supported_freqs(const fapi2::Target& i_target, +fapi2::ReturnCode supported_freqs(const fapi2::Target& i_target, std::vector& io_freqs); /// diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.C b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.C index e46b4a8cb4c..f61ba52b04e 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.C @@ -378,7 +378,7 @@ fapi_try_exit: /// @note This is done after the SPD cache is configured so that it can reflect the results of the /// factory and we don't need to worry about SPD versions. This is expressly different than the dram and dimm setters /// -static fapi2::ReturnCode master_ranks_per_dimm_setter(const fapi2::Target& i_target, +fapi2::ReturnCode master_ranks_per_dimm_setter(const fapi2::Target& i_target, const std::shared_ptr& i_pDecoder) { const auto l_mcs = find_target(i_target); @@ -757,57 +757,6 @@ fapi_try_exit: return fapi2::current_err; } -/// -/// @brief Creates factory object & SPD data caches -/// @param[in] i_target controller target -/// @param[out] o_factory_caches vector of factory objects -/// @param[in] i_pDecoder custom decoder to populate cache (ignored for this specialization) -/// @return FAPI2_RC_SUCCESS if okay -/// @note This specialization is suited for creating a cache with platform -/// SPD data. -/// -template<> -fapi2::ReturnCode populate_decoder_caches( const fapi2::Target& i_target, - std::vector< std::shared_ptr >& o_factory_caches, - const std::shared_ptr& i_pDecoder) -{ - // Input decoder for this version of populating cache would get overriden - // so I don't bother with it in this specialization - std::shared_ptr l_pDecoder; - - for( const auto& l_dimm : find_targets(i_target) ) - { - size_t l_size = 0; - FAPI_TRY( fapi2::getSPD(l_dimm, nullptr, l_size), - "%s. Failed to retrieve SPD blob size", mss::c_str(i_target) ); - - { - // "Container" for SPD data - std::vector l_spd(l_size); - - // Retrive SPD data - FAPI_TRY( fapi2::getSPD(l_dimm, l_spd.data(), l_size), - "%s. Failed to retrieve SPD data", mss::c_str(i_target) ); - - // Retrieve factory object instance & populate spd data for that instance - FAPI_TRY( factory(l_dimm, l_spd, l_pDecoder), - "%s. Failed SPD factory, could not instantiate decoder object", mss::c_str(i_target) ); - - // Populate spd caches - o_factory_caches.push_back( l_pDecoder ); - } - - // Populate some of the DIMM attributes early. This allows the following code to make - // decisions based on DIMM information. Expressly done after the factory has decided on the SPD version - FAPI_TRY( master_ranks_per_dimm_setter(l_dimm, l_pDecoder), - "%s. Failed master_ranks_per_dimm_setter()", mss::c_str(i_target) ); - - }// end dimm - -fapi_try_exit: - return fapi2::current_err; -} - /// /// @brief Creates factory object & SPD data caches /// @param[in] i_target the dimm target diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.H b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.H index 29f6804ba51..4087bf464fa 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.H @@ -42,9 +42,11 @@ // fapi2 #include +#include // mss lib #include +#include namespace mss { @@ -147,9 +149,22 @@ fapi2::ReturnCode factory(const fapi2::Target& i_target const std::vector& i_spd_data, std::shared_ptr& o_fact_obj); + +/// +/// @brief Determines & sets effective config for number of master ranks per dimm +/// @param[in] i_target DIMM fapi2::Target +/// @param[in] i_pDecoder shared_ptr to SPD decoder +/// @return fapi2::FAPI2_RC_SUCCESS if okay +/// @note This is done after the SPD cache is configured so that it can reflect the results of the +/// factory and we don't need to worry about SPD versions. This is expressly different than the dram and dimm setters +/// +fapi2::ReturnCode master_ranks_per_dimm_setter(const fapi2::Target& i_target, + const std::shared_ptr& i_pDecoder); + /// /// @brief Creates factory object & SPD data caches -/// @param[in] i_target the fapi2 target +/// @tparam T fapi2::TargetType, MCA, MCS, MCBIST, PROC_CHIP are possible TargetTypes +/// @param[in] i_target the fapi2 target to find DIMMs on /// @param[out] o_factory_caches vector of factory objects /// @param[in] i_pDecoder optional input decoder to insert custom decoder (nullptr default) /// @return FAPI2_RC_SUCCESS if okay @@ -157,8 +172,44 @@ fapi2::ReturnCode factory(const fapi2::Target& i_target template fapi2::ReturnCode populate_decoder_caches(const fapi2::Target& i_target, std::vector< std::shared_ptr >& o_factory_caches, - const std::shared_ptr& i_pDecoder = nullptr); + const std::shared_ptr& i_pDecoder = nullptr) +{ + // Input decoder for this version of populating cache would get overriden + // so I don't bother with it in this specialization + std::shared_ptr l_pDecoder; + + for( const auto& l_dimm : find_targets(i_target) ) + { + size_t l_size = 0; + FAPI_TRY( fapi2::getSPD(l_dimm, nullptr, l_size), + "%s. Failed to retrieve SPD blob size", mss::c_str(i_target) ); + + { + // "Container" for SPD data + std::vector l_spd(l_size); + + // Retrieve SPD data + FAPI_TRY( fapi2::getSPD(l_dimm, l_spd.data(), l_size), + "%s. Failed to retrieve SPD data", mss::c_str(i_target) ); + + // Retrieve factory object instance & populate spd data for that instance + FAPI_TRY( factory(l_dimm, l_spd, l_pDecoder), + "%s. Failed SPD factory, could not instantiate decoder object", mss::c_str(i_target) ); + + // Populate spd caches + o_factory_caches.push_back( l_pDecoder ); + } + + // Populate some of the DIMM attributes early. This allows the following code to make + // decisions based on DIMM information. Expressly done after the factory has decided on the SPD version + FAPI_TRY( master_ranks_per_dimm_setter(l_dimm, l_pDecoder), + "%s. Failed master_ranks_per_dimm_setter()", mss::c_str(i_target) ); + + }// end dimm +fapi_try_exit: + return fapi2::current_err; +} }// spd }// mss diff --git a/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C b/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C index 5c3cf9607ba..5af64ff64a6 100644 --- a/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C +++ b/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C @@ -28,7 +28,7 @@ /// @brief Calculate and save off DIMM frequencies /// // *HWP HWP Owner: Andre Marin -// *HWP FW Owner: Brian Silver +// *HWP HWP Backup: Jacob Harvey // *HWP Team: Memory // *HWP Level: 1 // *HWP Consumed by: FSP:HB @@ -63,7 +63,6 @@ using fapi2::FAPI2_RC_SUCCESS; extern "C" { - /// /// @brief Calculate and save off DIMM frequencies /// @param[in] i_target, the controller (e.g., MCS) @@ -80,8 +79,8 @@ extern "C" // twice for every MC. However, attribute access is cheap so this will suffice for // the time being. - std::vector l_min_dimm_freq(mss::MCS_PER_MC, 0); - std::vector l_desired_cas_latency(mss::MCS_PER_MC, 0); + std::vector< std::vector > l_min_dimm_freq(mss::MCS_PER_MC, std::vector (mss::PORTS_PER_MCS, 0) ); + const auto& l_mcbist = mss::find_target(i_target); @@ -94,59 +93,69 @@ extern "C" for (const auto& l_mcs : mss::find_targets(l_mcbist)) { - const auto l_index = mss::index(l_mcs); + const auto l_mcs_index = mss::index(l_mcs); - // Get cached decoder - std::vector< std::shared_ptr > l_factory_caches; - FAPI_TRY( mss::spd::populate_decoder_caches(l_mcs, l_factory_caches), - "%s. Failed to populate decoder cache", mss::c_str(i_target) ); + std::vector< uint64_t > l_desired_cas_latency(mss::PORTS_PER_MCS, 0 ); + for (const auto& l_mca : mss::find_targets(l_mcbist)) { - // instantiation of class that calculates CL algorithm - fapi2::ReturnCode l_rc; - mss::cas_latency l_cas_latency( l_mcs, l_factory_caches, l_rc ); - FAPI_TRY( l_rc, "%s. Failed to initialize cas_latency ctor", mss::c_str(i_target) ); - - 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(i_target) ); - } - 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. - l_min_dimm_freq[l_index] = fapi2::ENUM_ATTR_MSS_FREQ_MT2666; - - uint64_t l_tCKmin = 0; - - // Find CAS latency using JEDEC algorithm - FAPI_TRY( l_cas_latency.find_cl(l_desired_cas_latency[l_index], - l_tCKmin) ); + const auto l_index = mss::index(l_mca); - FAPI_INF("%s. Result from CL algorithm, CL (nck): %d, tCK (ps): %d", - mss::c_str(i_target), l_desired_cas_latency[l_index], l_tCKmin); + // Get cached decoder + std::vector< std::shared_ptr > l_factory_caches; - // Find dimm transfer speed from selected tCK - FAPI_TRY( mss::ps_to_freq(l_tCKmin, l_min_dimm_freq[l_index]), - "%s. Failed ps_to_freq()", mss::c_str(i_target) ); + FAPI_TRY( mss::spd::populate_decoder_caches(l_mca, l_factory_caches), + "%s. Failed to populate decoder cache", mss::c_str(i_target) ); - FAPI_INF("DIMM speed from selected tCK (ps): %d for %s", l_min_dimm_freq[l_index], mss::c_str(l_mcs)); - - FAPI_TRY(mss::select_supported_freq(l_mcs, l_min_dimm_freq[l_index]), - "Failed select_supported_freq() for %s", mss::c_str(l_mcs)); - - FAPI_INF("%s. Selected DIMM speed from supported speeds: %d", - mss::c_str(i_target), l_min_dimm_freq[l_index]); - - }// end else - - } // close scope - - FAPI_TRY(mss::set_CL_attr(l_mcs, l_desired_cas_latency[l_index] ), + { + // instantiation of class that calculates CL algorithm + fapi2::ReturnCode l_rc; + mss::cas_latency l_cas_latency( l_mca, l_factory_caches, l_rc ); + FAPI_TRY( l_rc, "%s. Failed to initialize cas_latency ctor", mss::c_str(i_target) ); + + 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(i_target) ); + } + 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. + l_min_dimm_freq[l_mcs_index][l_index] = fapi2::ENUM_ATTR_MSS_FREQ_MT2666; + + uint64_t l_tCKmin = 0; + + // Find CAS latency using JEDEC algorithm + FAPI_TRY( l_cas_latency.find_cl(l_desired_cas_latency[l_index], + l_tCKmin) ); + + FAPI_INF("%s. Result from CL algorithm, CL (nck): %d, tCK (ps): %d", + mss::c_str(i_target), l_desired_cas_latency[l_index], l_tCKmin); + + // Find dimm transfer speed from selected tCK + FAPI_TRY( mss::ps_to_freq(l_tCKmin, l_min_dimm_freq[l_mcs_index][l_index]), + "%s. Failed ps_to_freq()", mss::c_str(i_target) ); + + FAPI_INF("DIMM speed from selected tCK (ps): %d for %s", + l_min_dimm_freq[l_mcs_index][l_index], + mss::c_str(l_mca)); + + FAPI_TRY(mss::select_supported_freq(l_mca, l_min_dimm_freq[l_mcs_index][l_index]), + "Failed select_supported_freq() for %s", mss::c_str(l_mca)); + + FAPI_INF("%s. Selected DIMM speed from supported speeds: %d", + mss::c_str(i_target), l_min_dimm_freq[l_mcs_index][l_index]); + + }// end else + + } // close scope + } // End + + FAPI_TRY(mss::set_CL_attr(l_mcs, l_desired_cas_latency), "%s. Failed set_CL_attr()", mss::c_str(i_target) ); } // close for each mcs @@ -158,5 +167,4 @@ extern "C" return fapi2::current_err; }// p9_mss_freq - }// extern C diff --git a/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H b/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H index 3f24856bfb9..7f1a5177171 100644 --- a/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H +++ b/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -48,26 +48,44 @@ namespace mss /// /// @brief Sets DRAM CAS latency attributes /// @param[in] i_target the controller target -/// @param[in] i_cas_latency final selected CAS ltency +/// @param[in] i_cas_latency vector of the two final selected CAS latencies /// @return FAPI2_RC_SUCCESS iff ok /// inline fapi2::ReturnCode set_CL_attr(const fapi2::Target& i_target, - uint64_t i_cas_latency) + std::vector< uint64_t >& i_cas_latency) { - std::vector l_cls(PORTS_PER_MCS, 0); + // I wish I could do the reinterpret cast or set the pointer to the vector :( + // But no can do, manual copy pasta + uint8_t l_temp [mss::PORTS_PER_MCS] = {}; - // Set configured ports for( const auto& p : find_targets(i_target) ) { - l_cls[mss::index(p)] = i_cas_latency; - FAPI_INF( "Final Chosen CL: %d for %s", i_cas_latency, mss::c_str(p)); + // Local variable instead of calling it three times. Hopefully compiler can optimize this better + const auto l_index = mss::index(p); + + if ( l_index >= PORTS_PER_MCS) + { + FAPI_ERR("%s mss::index returned a value greater than PORTS_PER_MCS", mss::c_str(i_target) ); + fapi2::Assert(false); + } + + l_temp[l_index] = i_cas_latency[l_index]; + FAPI_ASSERT( l_temp[l_index] == i_cas_latency[l_index], + fapi2::MSS_BAD_CL_CAST() + .set_CL(i_cas_latency[l_index]) + .set_MCA_TARGET(p), + "%s bad cast for cas latency from %d to %d", + mss::c_str(i_target), + i_cas_latency[l_index], + l_temp[l_index]); + FAPI_INF( "Final Chosen CL: %d for %s", l_temp[l_index], mss::c_str(p)); } // set CAS latency attribute // casts vector into the type FAPI_ATTR_SET is expecting by deduction FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_EFF_DRAM_CL, i_target, - UINT8_VECTOR_TO_1D_ARRAY(l_cls, PORTS_PER_MCS)) , + l_temp) , "Failed to set CAS latency attribute"); fapi_try_exit: @@ -81,17 +99,20 @@ fapi_try_exit: /// @return FAPI2_RC_SUCCESS iff ok /// inline fapi2::ReturnCode set_freq_attrs(const fapi2::Target& i_target, - const std::vector& i_dimm_freq) + const std::vector< std::vector >& 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) + for (const auto l_vec : i_dimm_freq) { - if (l_freq != 0) + for (const auto l_freq : l_vec) { - l_final_freq = std::min(l_final_freq, l_freq); + if (l_freq != 0) + { + l_final_freq = std::min(l_final_freq, l_freq); + } } } diff --git a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_freq.xml b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_freq.xml index 7b4ac84cf13..64993ae64e9 100644 --- a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_freq.xml +++ b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_freq.xml @@ -38,6 +38,21 @@ + + RC_MSS_BAD_CL_CAST + + Calculated Cas Latency exceeds the 8-bit limit. Error calculating + + CL + + CODE + HIGH + + + MCA_TARGET + MEDIUM + + RC_MSS_INVALID_TIMING_VALUE diff --git a/src/import/generic/memory/lib/utils/find.H b/src/import/generic/memory/lib/utils/find.H index 3641d331f31..41d77114b46 100644 --- a/src/import/generic/memory/lib/utils/find.H +++ b/src/import/generic/memory/lib/utils/find.H @@ -38,7 +38,6 @@ #include #include - #include #include @@ -50,9 +49,17 @@ namespace mss /// @tparam T the fapi2 target type of the argument /// @param[in] i_target the fapi2 target T /// @return a vector of M targets. +/// @note Only works for valid parent-child relationships +/// So calling find_targets(l_mca) will work here +/// but calling find_targets(l_mcs) will not work +/// Compiler will freak out and we'll never get a bad relationship/ error at runtime +/// If we do, it's on fapi2 /// template< fapi2::TargetType M, fapi2::TargetType T > -inline std::vector< fapi2::Target > find_targets( const fapi2::Target& i_target); +inline std::vector< fapi2::Target > find_targets( const fapi2::Target& i_target) +{ + return i_target.template getChildren(); +} /// /// @brief find an element based on a fapi2 target @@ -60,6 +67,10 @@ inline std::vector< fapi2::Target > find_targets( const fapi2::Target& i_t /// @tparam T the fapi2 target type of the argument /// @param[in] i_target the fapi2 target T /// @return an M target. +/// @note Only works for valid parent-child relationships +/// Will work for MCA and DIMM +/// Will not work for MCS and DIMM +/// The compiler will let you know if it doesn't work /// template< fapi2::TargetType M, fapi2::TargetType T > inline fapi2::Target find_target( const fapi2::Target& i_target ) @@ -222,6 +233,19 @@ inline std::vector< fapi2::Target > find_targets return i_target.getChildren(); } +/// +/// @brief find all the MCA connected to an MCBIST +/// @param[in] i_target a fapi2::Target MCBIST +/// @return a vector of fapi2::TARGET_TYPE_MCA +/// +template<> +inline std::vector< fapi2::Target > find_targets +( const fapi2::Target& i_target ) +{ + std::vector< fapi2::Target > l_temp = {i_target}; + return l_temp; +} + /// /// @brief find the magic MCA connected to an MCBIST /// @param[in] i_target the fapi2::Target MCBIST