From 8c104ea1e91975df04c82f18cd672d9d4a7e4862 Mon Sep 17 00:00:00 2001 From: Andre Marin Date: Wed, 10 Jan 2018 12:17:50 -0600 Subject: Add VPD lookup to build a supported frequency list, and bin-down support Bypassing FFDC collection in p9_get_mem_vpd_keyword.C for unsupported configs that appear while polling the VPD for supported frequencies in the memory procedure p9_mss_freq.C. This removes the fail trace during istep to avoid user confusion. Change-Id: Ic679fb2fd8357567059f87d689acc0e0c534cd9f CQ:SW415931 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/51836 Tested-by: FSP CI Jenkins Dev-Ready: Brent Wieman Reviewed-by: STEPHEN GLANCY Tested-by: Jenkins Server Tested-by: HWSV CI Tested-by: PPE CI Tested-by: Hostboot CI Reviewed-by: Louis Stermole Reviewed-by: Jennifer A. Stofer Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/51842 Tested-by: Jenkins OP Build CI Reviewed-by: Daniel M. Crowell Tested-by: Daniel M. Crowell --- .../hwp/accessors/p9_get_mem_vpd_keyword.C | 58 +-- .../procedures/hwp/memory/lib/freq/cas_latency.C | 469 ++++++++------------- .../procedures/hwp/memory/lib/freq/cas_latency.H | 291 ++++++++++--- .../chips/p9/procedures/hwp/memory/lib/freq/sync.C | 382 ++++++++++++----- .../chips/p9/procedures/hwp/memory/lib/freq/sync.H | 143 +++---- .../procedures/hwp/memory/lib/shared/mss_const.H | 7 + .../p9/procedures/hwp/memory/lib/spd/spd_factory.C | 132 +++++- .../p9/procedures/hwp/memory/lib/spd/spd_factory.H | 21 +- .../chips/p9/procedures/hwp/memory/p9_mss_freq.C | 89 ++-- .../chips/p9/procedures/hwp/memory/p9_mss_freq.H | 9 +- .../xml/error_info/p9_memory_mss_freq.xml | 25 +- .../error_info/p9_memory_mss_general_errors.xml | 18 +- 12 files changed, 1018 insertions(+), 626 deletions(-) (limited to 'src/import/chips/p9') diff --git a/src/import/chips/p9/procedures/hwp/accessors/p9_get_mem_vpd_keyword.C b/src/import/chips/p9/procedures/hwp/accessors/p9_get_mem_vpd_keyword.C index c03ab1304..e44363989 100644 --- a/src/import/chips/p9/procedures/hwp/accessors/p9_get_mem_vpd_keyword.C +++ b/src/import/chips/p9/procedures/hwp/accessors/p9_get_mem_vpd_keyword.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -422,29 +422,39 @@ extern "C" } } - //Was a matching row found? - //Was a valid keyword name found? - FAPI_ASSERT( (0 != l_second) && - (static_cast(MAPPING_LAYOUT_INVALID) != l_second), - fapi2::GET_MEM_VPD_UNSUPPORTED_CONFIG(). - set_MCS(fapi2::ATTR_MEMVPD_POS_Type(l_mcsPos)). - set_FREQ(uint32_t(i_vpd_info.iv_freq_mhz)). - set_DIMM0RANK(uint64_t(i_vpd_info.iv_rank_count_dimm_0)). - set_DIMM1RANK(uint64_t(i_vpd_info.iv_rank_count_dimm_1)). - set_HEADER(mappingHeader_t(*l_mappingHeader)). - set_MCS_TARGET(i_target). - set_VPDTYPE(i_vpd_info.iv_vpd_type). - set_MAPROW0(l_ffdc_MAPROW[0]). - set_MAPROW1(l_ffdc_MAPROW[1]). - set_MAPROW2(l_ffdc_MAPROW[2]). - set_MAPROW3(l_ffdc_MAPROW[3]). - set_MAPROW4(l_ffdc_MAPROW[4]). - set_MAPROW5(l_ffdc_MAPROW[5]). - set_MAPROW6(l_ffdc_MAPROW[6]). - set_MAPROW7(l_ffdc_MAPROW[7]). - set_MAPROW8(l_ffdc_MAPROW[8]). - set_MAPROW9(l_ffdc_MAPROW[9]), - "Unsupported configuration, no match in memory vpd mapping table"); + // Was a matching row found? + // Was a valid keyword name found? + if( (0 == l_second) || ((static_cast(MAPPING_LAYOUT_INVALID) == l_second)) ) + { + // If we are in this conditional then we have encountered a fail and must decide + // how to proceed further. If iv_is_config_ffdc_enabled is true we will collect + // FFDC and assert out here. + FAPI_ASSERT( !i_vpd_info.iv_is_config_ffdc_enabled, + fapi2::GET_MEM_VPD_UNSUPPORTED_CONFIG(). + set_MCS(fapi2::ATTR_MEMVPD_POS_Type(l_mcsPos)). + set_FREQ(uint32_t(i_vpd_info.iv_freq_mhz)). + set_DIMM0RANK(uint64_t(i_vpd_info.iv_rank_count_dimm_0)). + set_DIMM1RANK(uint64_t(i_vpd_info.iv_rank_count_dimm_1)). + set_HEADER(mappingHeader_t(*l_mappingHeader)). + set_MCS_TARGET(i_target). + set_VPDTYPE(i_vpd_info.iv_vpd_type). + set_MAPROW0(l_ffdc_MAPROW[0]). + set_MAPROW1(l_ffdc_MAPROW[1]). + set_MAPROW2(l_ffdc_MAPROW[2]). + set_MAPROW3(l_ffdc_MAPROW[3]). + set_MAPROW4(l_ffdc_MAPROW[4]). + set_MAPROW5(l_ffdc_MAPROW[5]). + set_MAPROW6(l_ffdc_MAPROW[6]). + set_MAPROW7(l_ffdc_MAPROW[7]). + set_MAPROW8(l_ffdc_MAPROW[8]). + set_MAPROW9(l_ffdc_MAPROW[9]), + "Unsupported configuration, no match in memory vpd mapping table"); + + // If iv_is_config_ffdc_enabled is false we will arrive here and exit with a bad ReturnCode + // but won't collect FFDC so we don't pollute users with false fails. + FAPI_INF("Unsupported configuration, no match in memory vpd mapping table"); + return fapi2::FAPI2_RC_FALSE; + } // build the keyword name o_keywordInfo.kwName[0] = l_first; 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 4c88f60d8..b81796771 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 @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -41,10 +41,8 @@ #include // mss lib -#include #include -#include -#include +#include #include #include #include @@ -56,34 +54,27 @@ using fapi2::TARGET_TYPE_MCA; namespace mss { -/// -/// @brief encoding for MSS_INVALID_TIMING so we can look up functions based on encoding -/// -enum invalid_timing_function_encoding -{ - TAAMIN = 10, - TCKMIN = 11, - TCKMAX = 12, -}; - ///////////////////////// // Member method implementation ///////////////////////// /// -/// @brief Class constructor that retrieves required SPD data held by internal state -/// @param[in] i_target the controller target -/// @param[in] i_caches decoder caches +/// @brief Class constructor that retrieves required SPD data held by internal state +/// @param[in] i_target the controller target +/// @param[in] i_caches decoder caches +/// @param[in] i_supported_freqs vector of supported freqs /// @param[out] o_rc returns FAPI2_RC_SUCCESS if constructor initialzed successfully /// cas_latency::cas_latency(const fapi2::Target& i_target, const std::vector< std::shared_ptr >& i_caches, - fapi2::ReturnCode& o_rc ): + const std::vector& i_supported_freqs, + fapi2::ReturnCode& o_rc): iv_dimm_list_empty(false), iv_target(i_target), iv_largest_taamin(0), iv_proposed_tck(0), - iv_common_cl(UINT64_MAX) // Masks out supported CLs + iv_common_cl_bitmap(UINT64_MAX), + iv_supported_freqs(i_supported_freqs) { o_rc = fapi2::FAPI2_RC_SUCCESS; @@ -97,16 +88,17 @@ cas_latency::cas_latency(const fapi2::Target& i_target, for ( const auto& l_cache : i_caches ) { // Retrieve timing values from the SPD + const auto l_target = l_cache->iv_target; uint64_t l_taa_min_in_ps = 0; uint64_t l_tckmax_in_ps = 0; uint64_t l_tck_min_in_ps = 0; FAPI_TRY( get_taamin(l_cache, l_taa_min_in_ps), - "%s. Failed to get tAAmin", mss::c_str(iv_target) ); + "%s. Failed to get tAAmin", mss::c_str(l_target) ); FAPI_TRY( get_tckmax(l_cache, l_tckmax_in_ps), - "%s. Failed to get tCKmax", mss::c_str(iv_target) ); + "%s. Failed to get tCKmax", mss::c_str(l_target) ); FAPI_TRY( get_tckmin(l_cache, l_tck_min_in_ps), - "%s. Failed to get tCKmin", mss::c_str(iv_target) ); + "%s. Failed to get tCKmin", mss::c_str(l_target) ); // Determine largest tAAmin value iv_largest_taamin = std::max(iv_largest_taamin, l_taa_min_in_ps); @@ -133,56 +125,28 @@ cas_latency::cas_latency(const fapi2::Target& i_target, // Retrieve dimm supported cas latencies from SPD uint64_t l_dimm_supported_cl = 0; FAPI_TRY( l_cache->supported_cas_latencies(l_dimm_supported_cl), - "%s. Failed to get supported CAS latency", mss::c_str(iv_target) ); + "%s. Failed to get supported CAS latency", mss::c_str(l_target) ); // Bitwise ANDING the bitmap from all modules creates a bitmap w/a common CL - iv_common_cl &= l_dimm_supported_cl; + iv_common_cl_bitmap &= l_dimm_supported_cl; } }// caches - // Limit tCK from the max supported dimm speed in the system - // So that this is taken into account when calculating CL - { - // Defaulting to non-zero speed - uint64_t l_freq_override = fapi2::ENUM_ATTR_MSS_FREQ_MT2666; - uint64_t l_tck_override_in_ps = 0; - - FAPI_TRY( select_supported_freq(iv_target, l_freq_override), - "%s. Failed select_supported_freq()", mss::c_str(iv_target) ); - FAPI_TRY( freq_to_ps(l_freq_override, l_tck_override_in_ps), - "%s. Failed freq_to_ps()", mss::c_str(iv_target) ); - - FAPI_INF("%s. Selected supported dimm speed %d MT/s (Clock period %d in ps)", - mss::c_str(iv_target), l_freq_override, l_tck_override_in_ps); - - iv_proposed_tck = std::max( l_tck_override_in_ps, iv_proposed_tck ); - FAPI_INF("%s. Initial proposed tCK in ps: %d", mss::c_str(iv_target), iv_proposed_tck); - - - // Sanity check - FAPI_ASSERT(iv_proposed_tck > 0, - fapi2::MSS_INVALID_CALCULATED_TCK(). - set_TAAMIN(iv_largest_taamin). - set_PROPOSED_TCK(iv_proposed_tck). - set_IS_3DS(iv_is_3ds). - set_FREQUENCY(l_freq_override). - set_MCA_TARGET(iv_target), - "%s. Invalid calculated clock period(<= 0) : %d", - mss::c_str(iv_target), - iv_proposed_tck); - } - // Why didn't I encapsulate common CL operations and checking in a function // like the timing params? Well, I want to check the "final" common CL and // the creation of common CLs (bitwise ANDING) is at the dimm level operation - FAPI_ASSERT(iv_common_cl != 0, + FAPI_ASSERT(iv_common_cl_bitmap != 0, fapi2::MSS_NO_COMMON_SUPPORTED_CL(). - set_CL_SUPPORTED(iv_common_cl). + set_CL_SUPPORTED(iv_common_cl_bitmap). set_MCA_TARGET(iv_target), "%s. No common CAS latencies (CL bitmap = 0)", mss::c_str(iv_target) ); - FAPI_INF("%s. Supported CL bitmap 0x%llX", mss::c_str(iv_target), iv_common_cl); + FAPI_INF("Largest tAAmin (ps): %d, tCKmin (ps): %d, and supported CL bitmap 0x%llX for all modules across %s", + iv_largest_taamin, iv_proposed_tck, iv_common_cl_bitmap, mss::c_str(iv_target)); + + iv_common_cl = integral_bitmap_to_vector(iv_common_cl_bitmap); + FAPI_TRY( mss::required_synch_mode(iv_req_sync_mode) ); fapi_try_exit: o_rc = fapi2::current_err; @@ -191,24 +155,30 @@ fapi_try_exit: /// -/// @brief Constructor that allows the user to set desired data in lieu of SPD -/// @param[in] i_target the controller target -/// @param[in] i_taa_min largest tAAmin we want to set in picoseconds -/// @param[in] i_tck_min proposed tCKmin in picoseconds -/// @param[in] i_common_cl_mask common CAS latency mask we want to force (bitmap) -/// @param[in] i_is_3ds loading::IS_3DS if this is for 3DS, loading::NOT_3DS otherwise +/// @brief Constructor that allows the user to set desired data in lieu of SPD - helpful for testing +/// @param[in] i_target the controller target +/// @param[in] i_taa_min largest tAAmin we want to set in picoseconds +/// @param[in] i_tck_min proposed tCKmin in picoseconds +/// @param[in] i_common_cl_mask common CAS latency mask we want to force (bitmap) +/// @param[in] i_is_3ds loading::IS_3DS if this is for 3DS, loading::NOT_3DS otherwise +/// @param[in] i_req_sync_mode required synchronous mode -- defaulted to SYNCH_MODE_UNDETERMINED, +/// @param[in] i_supported_freqs vector of supported freqs -- defaulted to NIMBUS_SUPPORTED_FREQS /// 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, - const loading i_is_3ds): + const loading i_is_3ds, + const uint8_t i_req_sync_mode, + const std::vector& i_supported_freqs): iv_dimm_list_empty(false), iv_target(i_target), iv_largest_taamin(i_taa_min), iv_proposed_tck(i_tck_min), - iv_common_cl(i_common_cl_mask), - iv_is_3ds(i_is_3ds) + iv_is_3ds(i_is_3ds), + iv_common_cl_bitmap(i_common_cl_mask), + iv_req_sync_mode(i_req_sync_mode), + iv_supported_freqs(i_supported_freqs) { const auto l_dimm_list = find_targets(iv_target); @@ -217,52 +187,122 @@ cas_latency::cas_latency(const fapi2::Target& i_target, FAPI_INF("cas latency ctor seeing no DIMM on %s", mss::c_str(iv_target)); iv_dimm_list_empty = true; } + + iv_common_cl = integral_bitmap_to_vector(iv_common_cl_bitmap); } /// -/// @brief Calculates CAS latency and checks if it is supported and within JEDEC spec. +/// @brief Calculates CAS latency and checks if it is supported and within JEDEC spec. /// @param[out] o_cas_latency selected CAS latency /// @param[out] o_tck cycle time corresponding to selected CAS latency -/// @return fapi2::FAPI2_RC_SUCCESS if ok +/// @return fapi2::FAPI2_RC_SUCCESS if ok /// fapi2::ReturnCode cas_latency::find_cl(uint64_t& o_cas_latency, uint64_t& o_tck) { - uint64_t l_desired_cas_latency = 0; - fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; - if(!iv_dimm_list_empty) + // note: iv_common_cl is sorted in increasing order + const uint64_t l_max_cl = iv_common_cl.back(); + const uint64_t l_min_cl = *iv_common_cl.begin(); + + bool l_is_cl_in_common = false; + bool l_is_cl_exceeding_taa = true; + uint64_t l_desired_cas_latency = 0; + bool l_is_1st_iteration = true; + + if(iv_dimm_list_empty) { - // Create a vector filled with common CLs from buffer - std::vector l_supported_cls = integral_bitmap_to_vector(iv_common_cl); + // If the MCA has no dimm configured then both + // CAS latency and tCK are safe as 0's + o_cas_latency = 0; + o_tck = 0; + return fapi2::FAPI2_RC_SUCCESS; + } - // Make sure we have at least one entry. We should since iv_common_cl is checked in ctor - FAPI_ASSERT( !l_supported_cls.empty(), - fapi2::MSS_NO_COMMON_SUPPORTED_CL(). - set_CL_SUPPORTED(iv_common_cl). - set_MCA_TARGET(iv_target), - "%s. Error making support cas latency vector. No common CAS latencies", - mss::c_str(iv_target) ); + while(!l_is_cl_in_common && l_is_cl_exceeding_taa) + { + if( l_is_1st_iteration ) + { + // Our first run should try to run the highest common supported freq. + // If we don't meet JEDEC requirements then every iteration afterwards + // will bin down + l_is_1st_iteration = false; + FAPI_TRY( apply_freq_constraints(iv_proposed_tck) ); + } + else + { + // Limit tCK from system constraints such as supported VPD for the system + // as well as MRW frequency overrides, if enabled. This guy will bin freq down until + // we can't and then we fail out, prevents infinite loop when raising tCK + FAPI_TRY( apply_freq_constraints(iv_proposed_tck) ); + } // For a proposed tCK value between tCKmin(all) and tCKmax, determine the desired CAS Latency. FAPI_TRY( calc_cas_latency(iv_largest_taamin, iv_proposed_tck, l_desired_cas_latency), "%s. Failed to calculate CAS latency", mss::c_str(iv_target) ); - // Chose an actual CAS Latency (CLactual) that is greater than or equal to CLdesired + // Choose an actual CAS Latency (CLactual) that is greater than or equal to CLdesired // and is supported by all modules on the memory channel - FAPI_TRY( is_cl_supported_in_common(l_supported_cls, l_desired_cas_latency), - "%s. Failed to find a common CAS latency supported among all modules", mss::c_str(iv_target) ); + l_is_cl_in_common = is_cl_supported_in_common(iv_common_cl, l_desired_cas_latency); + + while( !l_is_cl_in_common && (l_desired_cas_latency < l_max_cl) ) + { + ++l_desired_cas_latency; + l_is_cl_in_common = is_cl_supported_in_common(iv_common_cl, l_desired_cas_latency); + + } + + // If no such value exists, choose a higher tCKproposed value and repeat until a solution is found. + if(!l_is_cl_in_common) + { + FAPI_INF("Desired CL isn't supported by all DIMMs, choosing a higher tCK"); + continue; + } // Once the calculation of CLactual is completed // verify that this CAS Latency value does not exceed tAAmax. - FAPI_TRY( is_cl_exceeding_taa_max (l_desired_cas_latency, iv_proposed_tck), - "%s. Failed to find a CL value that doesn't exceed tAAmax", mss::c_str(iv_target) ); - } + l_is_cl_exceeding_taa = is_cl_exceeding_taa_max (l_desired_cas_latency, iv_proposed_tck); + + // If not, choose a lower CL value and repeat until a solution is found. + while( l_is_cl_exceeding_taa && (l_desired_cas_latency > l_min_cl) ) + { + --l_desired_cas_latency; + l_is_cl_exceeding_taa = is_cl_exceeding_taa_max (l_desired_cas_latency, iv_proposed_tck); + } + + l_is_cl_in_common = is_cl_supported_in_common(iv_common_cl, l_desired_cas_latency); + + }// end while + + FAPI_ASSERT( !l_is_cl_exceeding_taa, + fapi2::MSS_CL_EXCEEDS_TAA_MAX() + .set_CAS_LATENCY(l_desired_cas_latency) + .set_TCK(iv_proposed_tck) + .set_COMPARE(l_desired_cas_latency * iv_proposed_tck) + .set_TAA_MAX(iv_largest_taamin) + .set_IS_3DS(iv_is_3ds), + "%s: Calculated Cas Latency (CL %d * tCK %d) exceeds JEDEC value of tAAmax %d", + mss::c_str(iv_target), + l_desired_cas_latency, iv_proposed_tck, iv_largest_taamin); + + // If the cas_latency wasn't found, we return an error + // Passing in timing values which were used to calculated i_cas_latency for extra info + // iv_common_cl contains all of the valid cas latencies that populate the input vector + FAPI_ASSERT( l_is_cl_in_common, + fapi2::MSS_FAILED_TO_FIND_SUPPORTED_CL() + .set_DESIRED_CAS_LATENCY(l_desired_cas_latency) + .set_TAA(iv_largest_taamin) + .set_TCK(iv_proposed_tck) + .set_COMMON_CLS(iv_common_cl_bitmap) + .set_MCA_TARGET(iv_target), + "%s. Failed to find a common CAS latency supported among all modules" + "Desired %d, common CL's %016lx", + mss::c_str(iv_target), + l_desired_cas_latency, + iv_common_cl_bitmap); // Update output values after all criteria is met - // 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; @@ -271,10 +311,10 @@ fapi_try_exit: } /// -/// @brief Retrieves SDRAM Minimum CAS Latency Time (tAAmin) from SPD -/// @param[in] i_pDecoder the SPD decoder +/// @brief Retrieves SDRAM Minimum CAS Latency Time (tAAmin) from SPD +/// @param[in] i_pDecoder the SPD decoder /// @param[out] o_value tCKmin value in ps -/// @return FAPI2_RC_SUCCESS iff ok +/// @return FAPI2_RC_SUCCESS iff ok /// fapi2::ReturnCode cas_latency::get_taamin( const std::shared_ptr& i_pDecoder, uint64_t& o_value ) @@ -284,15 +324,18 @@ fapi2::ReturnCode cas_latency::get_taamin( const std::shared_ptriv_target; + FAPI_TRY( i_pDecoder->medium_timebase(l_medium_timebase), - "%s. Failed medium_timebase()", mss::c_str(iv_target) ); + "%s. Failed medium_timebase()", mss::c_str(l_target) ); FAPI_TRY( i_pDecoder->fine_timebase(l_fine_timebase), - "%s. Failed fine_timebase()", mss::c_str(iv_target) ); + "%s. Failed fine_timebase()", mss::c_str(l_target) ); FAPI_TRY( i_pDecoder->min_taa(l_timing_mtb), - "%s. Failed min_taa()", mss::c_str(iv_target) ); + "%s. Failed min_taa()", mss::c_str(l_target) ); FAPI_TRY( i_pDecoder->fine_offset_min_taa(l_timing_ftb), - "%s. Failed fine_offset_min_taa()", mss::c_str(iv_target) ); + "%s. Failed fine_offset_min_taa()", mss::c_str(l_target) ); // Calculate timing value l_temp = spd::calc_timing_from_timebase(l_timing_mtb, @@ -304,127 +347,28 @@ fapi2::ReturnCode cas_latency::get_taamin( const std::shared_ptr 0, fapi2::MSS_INVALID_TIMING_VALUE(). set_VALUE(o_value). - set_FUNCTION(TAAMIN). - set_DIMM_TARGET(iv_target), + set_FUNCTION(GET_TAAMIN). + set_DIMM_TARGET(l_target), "%s. tAAmin invalid (<= 0) : %d", - mss::c_str(iv_target), + mss::c_str(l_target), l_temp); o_value = l_temp; FAPI_INF( "%s. tAAmin (ps): %d", - mss::c_str(iv_target), + mss::c_str(l_target), o_value); -fapi_try_exit: - return fapi2::current_err; -} - -/// -/// @brief Retrieves SDRAM Minimum Cycle Time (tCKmin) from SPD -/// @param[in] i_pDecoder the SPD decoder -/// @param[out] o_value tCKmin value in ps -/// @return FAPI2_RC_SUCCESS iff ok -/// -fapi2::ReturnCode cas_latency::get_tckmin( const std::shared_ptr& i_pDecoder, - uint64_t& o_value ) -{ - int64_t l_timing_ftb = 0; - int64_t l_timing_mtb = 0; - int64_t l_medium_timebase = 0; - int64_t l_fine_timebase = 0; - int64_t l_temp = 0; - - // Retrieve timing parameters - FAPI_TRY( i_pDecoder->medium_timebase(l_medium_timebase), - "%s. Failed medium_timebase()", mss::c_str(iv_target) ); - FAPI_TRY( i_pDecoder->fine_timebase(l_fine_timebase), - "%s. Failed fine_timebase()", mss::c_str(iv_target) ); - FAPI_TRY( i_pDecoder->min_tck(l_timing_mtb), - "%s. Failed min_tck()", mss::c_str(iv_target) ); - FAPI_TRY( i_pDecoder->fine_offset_min_tck(l_timing_ftb), - "%s. Failed fine_offset_min_tck()", mss::c_str(iv_target) ); - - // Calculate timing value - l_temp = spd::calc_timing_from_timebase(l_timing_mtb, - l_medium_timebase, - l_timing_ftb, - l_fine_timebase); - - // Sanity check - FAPI_ASSERT(l_temp > 0, - fapi2::MSS_INVALID_TIMING_VALUE(). - set_VALUE(l_temp). - set_FUNCTION(TCKMIN). - set_DIMM_TARGET(iv_target), - "%s. tCKmin invalid (<= 0) : %d", - mss::c_str(iv_target), - l_temp); - - o_value = l_temp; - - FAPI_INF("%s. tCKmin (ps): %d", - mss::c_str(iv_target), - o_value ); - -fapi_try_exit: - return fapi2::current_err; -} - -/// -/// @brief Retrieves SDRAM Maximum Cycle Time (tCKmax) from SPD -/// @param[in] i_pDecoder SPD decoder -/// @param[out] o_value tCKmax value in ps -/// @return FAPI2_RC_SUCCESS iff ok -/// -fapi2::ReturnCode cas_latency::get_tckmax( const std::shared_ptr& i_pDecoder, - uint64_t& o_value ) -{ - int64_t l_timing_ftb = 0; - int64_t l_timing_mtb = 0; - int64_t l_medium_timebase = 0; - int64_t l_fine_timebase = 0; - int64_t l_temp = 0; - // Retrieve timing parameters - FAPI_TRY( i_pDecoder->medium_timebase(l_medium_timebase), - "%s. Failed medium_timebase()", mss::c_str(iv_target) ); - FAPI_TRY( i_pDecoder->fine_timebase(l_fine_timebase), - "%s. Failed fine_timebase()", mss::c_str(iv_target) ); - FAPI_TRY( i_pDecoder->max_tck(l_timing_mtb), - "%s. Failed max_tck()", mss::c_str(iv_target) ); - FAPI_TRY( i_pDecoder->fine_offset_max_tck(l_timing_ftb), - "%s. Failed fine_offset_max_tck()", mss::c_str(iv_target) ); - - // Calculate timing value - l_temp = spd::calc_timing_from_timebase(l_timing_mtb, - l_medium_timebase, - l_timing_ftb, - l_fine_timebase); - - // Sanity check - FAPI_ASSERT(l_temp > 0, - fapi2::MSS_INVALID_TIMING_VALUE(). - set_VALUE(l_temp). - set_FUNCTION(TCKMAX). - set_DIMM_TARGET(iv_target), - "%s. tCKmax invalid (<= 0) : %d", - mss::c_str(iv_target), - l_temp); - - o_value = l_temp; - - FAPI_INF( "%s. tCKmax (ps): %d", - mss::c_str(iv_target), - o_value); + return fapi2::FAPI2_RC_SUCCESS; fapi_try_exit: return fapi2::current_err; } /// -/// @brief Gets max CAS latency (CL) for the appropriate High/Low Range -/// @param[in] i_supported_cl -/// @return the maximum supported CL -/// @note Depends on bit 7 of byte 23 from the DDR4 SPD +/// @brief Gets max CAS latency (CL) for the appropriate High/Low Range +/// @param[in] i_supported_cl +/// @return the maximum supported CL +/// @note Depends on bit 7 of byte 23 from the DDR4 SPD /// inline uint64_t cas_latency::get_max_cl(const fapi2::buffer i_supported_cl) const { @@ -438,10 +382,10 @@ inline uint64_t cas_latency::get_max_cl(const fapi2::buffer i_supporte } /// -/// @brief Gets min CAS latency (CL) for the appropriate High/Low Range -/// @param[in] i_supported_cl -/// @return the minimum supported CL -/// @note Depends on bit 7 of byte 23 from the DDR4 SPD +/// @brief Gets min CAS latency (CL) for the appropriate High/Low Range +/// @param[in] i_supported_cl +/// @return the minimum supported CL +/// @note Depends on bit 7 of byte 23 from the DDR4 SPD /// inline uint64_t cas_latency::get_min_cl(const fapi2::buffer& i_supported_cl) const { @@ -456,10 +400,10 @@ inline uint64_t cas_latency::get_min_cl(const fapi2::buffer& i_support /// /// @brief Calculates CAS latency time from tCK and tAA -/// @param[in] i_taa cas latency time -/// @param[in] i_tck min cycle time +/// @param[in] i_taa cas latency time +/// @param[in] i_tck min cycle time /// @param[out] o_cas_latency calculated CAS latency -/// @return FAPI2_RC_SUCCESS iff okay +/// @return FAPI2_RC_SUCCESS iff okay /// inline fapi2::ReturnCode cas_latency::calc_cas_latency(const uint64_t i_taa, const uint64_t i_tck, @@ -478,26 +422,26 @@ fapi_try_exit: } /// -/// @brief Helper function to create a vector of supported CAS latencies from a bitmap -/// @param[in] i_common_cl common CAS latency bitmap -/// @return vector of supported CAS latencies +/// @brief Helper function to create a vector of supported CAS latencies from a bitmap +/// @param[in] i_common_cl common CAS latency bitmap +/// @return vector of supported CAS latencies /// std::vector cas_latency::integral_bitmap_to_vector(const uint64_t i_common_cl) const { std::vector l_vector; fapi2::buffer l_cl_mask(i_common_cl); - uint64_t min_cl = get_min_cl(l_cl_mask); - uint64_t max_cl = get_max_cl(l_cl_mask); + const uint64_t l_min_cl = get_min_cl(l_cl_mask); + const uint64_t l_max_cl = get_max_cl(l_cl_mask); - FAPI_INF("%s. min CL %lu", mss::c_str(iv_target), min_cl); - FAPI_INF("%s. max CL %lu", mss::c_str(iv_target), max_cl); + FAPI_INF("%s. min CL %lu", mss::c_str(iv_target), l_min_cl); + FAPI_INF("%s. max CL %lu", mss::c_str(iv_target), l_max_cl); - for(uint64_t l_cas_latency = min_cl; l_cas_latency <= max_cl; ++l_cas_latency) + for(uint64_t l_cas_latency = l_min_cl; l_cas_latency <= l_max_cl; ++l_cas_latency) { // 64 bit is buffer length - indexed at 0 - 63 constexpr uint64_t l_buffer_length = 64 - 1; - uint64_t l_bit_pos = l_buffer_length - (l_cas_latency - min_cl); + uint64_t l_bit_pos = l_buffer_length - (l_cas_latency - l_min_cl); // Traversing through buffer one bit at a time // 0 means unsupported CAS latency @@ -506,8 +450,8 @@ std::vector cas_latency::integral_bitmap_to_vector(const uint64_t i_co if( l_cl_mask.getBit(l_bit_pos) ) { // I want don't this to print all the time, DBG is fine - FAPI_DBG( "%s. Supported CL (%d) from common CL mask", - mss::c_str(iv_target), l_cas_latency ); + FAPI_DBG( "%s. Supported CL (%d) from common CL mask (0x%llX)", + mss::c_str(iv_target), l_cas_latency, i_common_cl ); l_vector.push_back(l_cas_latency); } @@ -517,85 +461,44 @@ std::vector cas_latency::integral_bitmap_to_vector(const uint64_t i_co } /// -/// @brief Determines if a requested CAS latency (CL) is supported in the bin of common CLs -/// @param[in] i_common_cls vector of common CAS latencies -/// @param[in] i_cas_latency CAS latency we are comparing against -/// @return FAPI2_RC_SUCCESS iff ok +/// @brief Determines if a requested CAS latency (CL) is supported in the bin of common CLs +/// @param[in] i_common_cls vector of common CAS latencies (must be sorted) +/// @param[in] i_cas_latency CL we are comparing against +/// @return true iff desired CL was found in the bitmap of common CLs, false otherwise /// -inline fapi2::ReturnCode cas_latency::is_cl_supported_in_common(const std::vector& i_common_cls, +inline bool cas_latency::is_cl_supported_in_common(const std::vector& i_common_cls, const uint64_t i_cas_latency) const { - fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + const bool l_found = std::binary_search(i_common_cls.begin(), i_common_cls.end(), i_cas_latency); - // Grabbing freq info for ffdc - std::vector l_mrw_freqs(NUM_MRW_FREQS, 0); - std::vector l_max_freqs(NUM_MAX_FREQS, 0); + FAPI_INF("Found CL: %d in common CL mask: 0x%llX ? %s for %s", + i_cas_latency, iv_common_cl_bitmap, l_found ? "yes" : "no", mss::c_str(iv_target)); - FAPI_TRY( mss::mrw_supported_freq(l_mrw_freqs.data()) ); - FAPI_TRY( mss::max_allowed_dimm_freq(l_max_freqs.data()) ); - - // If the cas_latency wasn't found, we return an error - // Passing in timing values which were used to calculated i_cas_latency for extra info - // iv_common_cl contains all of the valid cas latencies that populate the input vector - FAPI_ASSERT( std::binary_search(i_common_cls.begin(), i_common_cls.end(), i_cas_latency), - fapi2::MSS_FAILED_TO_FIND_SUPPORTED_CL() - .set_DESIRED_CAS_LATENCY(i_cas_latency) - .set_TAA(iv_largest_taamin) - .set_TCK(iv_proposed_tck) - .set_COMMON_CLS(iv_common_cl) - .set_MSS_MRW_FREQ_0(l_mrw_freqs[0]) - .set_MSS_MRW_FREQ_1(l_mrw_freqs[1]) - .set_MSS_MRW_FREQ_2(l_mrw_freqs[2]) - .set_MSS_MRW_FREQ_3(l_mrw_freqs[3]) - .set_MSS_MAX_FREQ_0(l_max_freqs[0]) - .set_MSS_MAX_FREQ_1(l_max_freqs[1]) - .set_MSS_MAX_FREQ_2(l_max_freqs[2]) - .set_MSS_MAX_FREQ_3(l_max_freqs[3]) - .set_MSS_MAX_FREQ_4(l_max_freqs[4]) - .set_MCA_TARGET(iv_target), - "%s. Failed to find a common CAS latency supported among all modules" - "Desired %d, common CL's %016lx", - mss::c_str(iv_target), - i_cas_latency, - iv_common_cl); -fapi_try_exit: - return fapi2::current_err; + return l_found; } /// -/// @brief Checks that CAS latency doesn't exceed largest CAS latency time -/// @param[in] i_cas_latency cas latency -/// @param[in] i_tck cycle time -/// @return FAPI2_RC_SUCCESS iff ok +/// @brief Checks that CAS latency doesn't exceed largest CAS latency time +/// @param[in] i_cas_latency cas latency +/// @param[in] i_tck cycle time +/// @return true iff CL exceeds tAAmax, false otherwise /// -inline fapi2::ReturnCode cas_latency::is_cl_exceeding_taa_max(const uint64_t i_cas_latency, +inline bool cas_latency::is_cl_exceeding_taa_max(const uint64_t i_cas_latency, const uint64_t i_tck) const { - fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; // JEDEC SPD spec requirement const size_t l_taa_max = (iv_is_3ds == loading::NOT_3DS) ? TAA_MAX_DDR4 : TAA_MAX_DDR4_3DS; + const bool l_is_cl_exceeding_taa = (i_cas_latency * i_tck) > l_taa_max; - FAPI_INF("%s. CL (%d) * tCK (%d) = %d > %d", + FAPI_INF("%s. CL (%d) * tCK (%d) = %d > %d ? %s", mss::c_str(iv_target), i_cas_latency, i_tck, i_cas_latency * i_tck, - l_taa_max); + l_taa_max, + l_is_cl_exceeding_taa ? "yes" : "no"); - FAPI_ASSERT( ((i_cas_latency * i_tck) <= l_taa_max), - fapi2::MSS_CL_EXCEEDS_TAA_MAX() - .set_CAS_LATENCY(i_cas_latency) - .set_TCK(i_tck) - .set_COMPARE(i_cas_latency * i_tck) - .set_TAA_MAX(l_taa_max) - .set_IS_3DS(iv_is_3ds), - "%s: Calculated Cas Latency (i_cas_latency %d * i_tck %d) exceeds JEDEC value of TAA MAX %d", - mss::c_str(iv_target), - i_cas_latency, - i_tck, - l_taa_max); -fapi_try_exit: - return fapi2::current_err; + return l_is_cl_exceeding_taa; } }// mss 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 c4b1e82c5..6c9ad087c 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 @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -46,6 +46,8 @@ // mss lib #include +#include +#include namespace mss { @@ -60,6 +62,50 @@ enum class loading : size_t IS_3DS, }; +enum freq_select : uint8_t +{ + BIN_DOWN, ///< option to bin down frequency + HIGHEST_COMMON ///< option to find highest common freq w/o bin down - useful for testing +}; + +/// +/// @brief Returns the iterator if a given freq is found +/// @tparam T the freq_select type +/// @param[in] i_supported_freqs a vector of sorted frequences +/// @param[im] i_dimm_freq current dimm speed +/// @return FAPI2_RC_SUCESS iff okay +/// +template< freq_select T > +static inline std::vector::const_iterator search_list( const std::vector& i_supported_freqs, + const uint32_t i_dimm_freq); + +/// +/// @brief Returns the iterator if a given freq is found - BIN_DOWN specialization +/// @param[in] i_supported_freqs a vector of sorted frequences +/// @param[in] i_dimm_freq current dimm speed +/// @return FAPI2_RC_SUCESS iff okay +/// +template< > +inline std::vector::const_iterator search_list( const std::vector& i_supported_freqs, + const uint32_t i_dimm_freq) +{ + return std::lower_bound(i_supported_freqs.begin(), i_supported_freqs.end(), i_dimm_freq); +} + +/// +/// @brief Returns the iterator if a given freq is found - HIGHEST_COMMON specialization +/// @param[in] i_supported_freqs a vector of sorted frequences +/// param[in] i_dimm_freq current dimm speed +/// @return FAPI2_RC_SUCESS iff okay +/// +template< > +inline std::vector::const_iterator search_list( const std::vector& + i_supported_freqs, + const uint32_t i_dimm_freq) +{ + return std::upper_bound(i_supported_freqs.begin(), i_supported_freqs.end(), i_dimm_freq); +} + /// /// @class cas_latency /// @brief CAS latency class that encapsulates JEDEC calculation algorithm @@ -79,28 +125,34 @@ class cas_latency cas_latency() = delete; /// - /// @brief Class constructor that retrieves required SPD data held by internal state - /// @param[in] i_target the controller target - /// @param[in] i_caches decoder caches + /// @brief Class constructor that retrieves required SPD data held by internal state + /// @param[in] i_target the controller target + /// @param[in] i_caches decoder caches + /// @param[in] i_supported_freqs vector of supported frequencies /// @param[out] o_rc returns FAPI2_RC_SUCCESS if constructor initialzed successfully /// cas_latency(const fapi2::Target& i_target_mcs, const std::vector< std::shared_ptr >& i_caches, + const std::vector& i_supported_freqs, fapi2::ReturnCode& o_rc); /// - /// @brief Constructor that allows the user to set desired data in lieu of SPD - /// @param[in] i_target the controller target - /// @param[in] i_taa_min largest tAAmin we want to set in picoseconds - /// @param[in] i_tck_min proposed tCKmin in picoseconds - /// @param[in] i_common_cl_mask common CAS latency mask we want to use (bitmap) - /// @param[in] i_is_3ds loading::IS_3DS if this is for 3DS, loading::NOT_3DS otherwise + /// @brief Constructor that allows the user to set desired data in lieu of SPD - helpful for testing + /// @param[in] i_target the controller target + /// @param[in] i_taa_min largest tAAmin we want to set in picoseconds + /// @param[in] i_tck_min proposed tCKmin in picoseconds + /// @param[in] i_common_cl_mask common CAS latency mask we want to use (bitmap) + /// @param[in] i_is_3ds loading::IS_3DS if this is for 3DS, loading::NOT_3DS otherwise + /// @param[in] i_req_sync_mode required synchronous mode -- defaulted to SYNCH_MODE_UNDETERMINED, + /// @param[in] i_supported_freqs vector of supported frequencies -- defaulted to NIMBUS_SUPPORTED_FREQS /// 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, - const loading i_is_3ds); + const loading i_is_3ds, + const uint8_t i_req_sync_mode = fapi2::ENUM_ATTR_REQUIRED_SYNCH_MODE_UNDETERMINED, + const std::vector& i_supported_freqs = NIMBUS_SUPPORTED_FREQS); /// /// @brief Default destructor @@ -108,14 +160,83 @@ class cas_latency ~cas_latency() = default; /// - /// @brief Calculates CAS latency and checks if it is supported and within JEDEC spec. + /// @brief Calculates CAS latency and checks if it is supported and within JEDEC spec. /// @param[out] o_cas_latency selected CAS latency /// @param[out] o_tck cycle time corresponding to seleted CAS latency - /// @return fapi2::FAPI2_RC_SUCCESS if ok + /// @return fapi2::FAPI2_RC_SUCCESS iff ok /// fapi2::ReturnCode find_cl(uint64_t& o_cas_latency, uint64_t& o_tck); + /// + /// @brief Selects DIMM frequency to run based on supported system frequencies -- helper function for testing + /// @tparam TT the freq_select type + /// @param[in] i_supported_freqs vector supported frequencies + /// @param[in,out] io_dimm_freq input is current dimm freq & output is next + /// lowest dimm freq between 1866 MT/s - 2666 MT/s + /// @return FAPI2_RC_SUCCESS iff ok + /// @note Frequency values obtained from: + /// @note From P9 User's Manual Version 0.8 - June 08, 2015 + /// @note Memory Controller Unit - page 199 of 456 + /// + template< freq_select TT > + inline fapi2::ReturnCode select_supported_freq_helper( const std::vector& i_supported_freqs, + uint64_t& io_dimm_freq) + { + FAPI_ASSERT( !i_supported_freqs.empty(), + fapi2::MSS_EMPTY_VECTOR(). + set_FUNCTION(SELECT_SUPPORTED_FREQ). + set_TARGET(iv_target), + "Empty supported frequency vector received for %s", + mss::c_str(iv_target)); + + for( const auto& freq : i_supported_freqs ) + { + FAPI_DBG("Supported freqs taking into account VPD, SPD, & MRW constraints %d for %s", freq, mss::c_str(iv_target) ); + } + + FAPI_DBG("Input frequency %d for %s", io_dimm_freq, mss::c_str(iv_target) ); + { + auto l_iterator = search_list(i_supported_freqs, io_dimm_freq); + + // Doing this because the HB compiler freaks out if we have it within the FAPI_ASSERT. + // Outputting the value and then incrementing the iterator, that's why it's a post increment + // We have at most 4 memory freqs (1866, 2133, 2400, & 2666), if we ever get a list with < 4 items + // a value of 0 is logged in FFDC once we hit i_supported_freqs.end()...which is better than no logging. + auto l_supported = i_supported_freqs.begin(); + + const auto l_freq0 = (l_supported != i_supported_freqs.end()) ? *(l_supported++) : 0; + const auto l_freq1 = (l_supported != i_supported_freqs.end()) ? *(l_supported++) : 0; + const auto l_freq2 = (l_supported != i_supported_freqs.end()) ? *(l_supported++) : 0; + const auto l_freq3 = (l_supported != i_supported_freqs.end()) ? *(l_supported++) : 0; + + // We can't choose a lower freq than the 1st element of this vector, + // hitting this case means that we exhausted all possible frequencies + FAPI_ASSERT( l_iterator != i_supported_freqs.begin(), + fapi2::MSS_SELECTED_FREQ_NOT_SUPPORTED() + .set_FREQ(io_dimm_freq) + .set_SUPPORTED_FREQ_0( l_freq0 ) + .set_SUPPORTED_FREQ_1( l_freq1 ) + .set_SUPPORTED_FREQ_2( l_freq2 ) + .set_SUPPORTED_FREQ_3( l_freq3 ) + .set_TARGET(iv_target), + "%s Error finding selected freq (%d) from list", + mss::c_str(iv_target), + io_dimm_freq ); + + // Lower bound checks for greater than or equal to input freq, + // we decrement to get the next lowest freq + io_dimm_freq = *(--l_iterator); + + FAPI_DBG("Output frequency %d for %s", io_dimm_freq, mss::c_str(iv_target) ); + } + + return fapi2::FAPI2_RC_SUCCESS; + + fapi_try_exit: + return fapi2::current_err; + } + private: enum @@ -147,89 +268,131 @@ class cas_latency 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 loading iv_is_3ds; + uint64_t iv_common_cl_bitmap; + bool iv_enable_freq_overrides; + std::vector iv_common_cl; // common cas latency + uint8_t iv_req_sync_mode; + std::vector iv_supported_freqs; /// - /// @brief Retrieves SDRAM Minimum CAS Latency Time (tAAmin) from SPD - /// @param[in] i_pDecoder the SPD decoder + /// @brief Retrieves SDRAM Minimum CAS Latency Time (tAAmin) from SPD + /// @param[in] i_pDecoder the SPD decoder /// @param[out] o_value tCKmin value in ps - /// @return FAPI2_RC_SUCCESS iff ok + /// @return FAPI2_RC_SUCCESS iff ok /// fapi2::ReturnCode get_taamin(const std::shared_ptr& i_pDecoder, uint64_t& o_value); + /// - /// @brief Retrieves SDRAM Minimum Cycle Time (tCKmin) from SPD - /// @param[in] i_pDecoder the SPD decoder - /// @param[out] o_value tCKmin value in ps - /// @return FAPI2_RC_SUCCESS iff ok + /// @brief Gets max CAS latency (CL) for the appropriate High/Low Range + /// @param[in] i_supported_cl + /// @return the maximum supported CL + /// @note Depends on bit 7 of byte 23 from the DDR4 SPD /// - fapi2::ReturnCode get_tckmin(const std::shared_ptr& i_pDecoder, - uint64_t& o_value); + uint64_t get_max_cl(const fapi2::buffer i_supported_cl) const; /// - /// @brief Retrieves SDRAM Maximum Cycle Time (tCKmax) from SPD - /// @param[in] i_pDecoder SPD decoder - /// @param[out] o_value tCKmax value in ps - /// @return FAPI2_RC_SUCCESS iff ok + /// @brief Gets min CAS latency (CL) for the appropriate High/Low Range + /// @param[in] i_supported_cl + /// @return the minimum supported CL + /// @note Depends on bit 7 of byte 23 from the DDR4 SPD /// - fapi2::ReturnCode get_tckmax(const std::shared_ptr& i_pDecoder, - uint64_t& o_value); + uint64_t get_min_cl(const fapi2::buffer& i_supported_cl) const; /// - /// @brief Gets max CAS latency (CL) for the appropriate High/Low Range - /// @param[in] i_supported_cl - /// @return the maximum supported CL - /// @note Depends on bit 7 of byte 23 from the DDR4 SPD + /// @brief Calculates CAS latency time from tCK and tAA + /// @param[in] i_taa cas latency time + /// @param[in] i_tck min cycle time + /// @param[out] o_cas_latency calculated CAS latency + /// @return FAPI2_RC_SUCCESS iff okay /// - inline uint64_t get_max_cl(const fapi2::buffer i_supported_cl) const; + fapi2::ReturnCode calc_cas_latency(const uint64_t i_taa, + const uint64_t i_tck, + uint64_t& o_cas_latency) const; /// - /// @brief Gets min CAS latency (CL) for the appropriate High/Low Range - /// @param[in] i_supported_cl - /// @return the minimum supported CL - /// @note Depends on bit 7 of byte 23 from the DDR4 SPD + /// @brief Helper function to create a vector of supported CAS latencies from a bitmap + /// @param[in] i_common_cl common CAS latency bitmap + /// @return vector of supported CAS latencies /// - inline uint64_t get_min_cl(const fapi2::buffer& i_supported_cl) const; + std::vector integral_bitmap_to_vector(const uint64_t i_bitmap) const; /// - /// @brief Calculates CAS latency time from tCK and tAA - /// @param[in] i_taa cas latency time - /// @param[in] i_tck min cycle time - /// @param[out] o_cas_latency calculated CAS latency - /// @return FAPI2_RC_SUCCESS iff okay + /// @brief Determines if a requested CAS latency (CL) is supported in the bin of common CLs + /// @param[in] i_common_cls vector of common CAS latencies + /// @param[in] i_cas_latency CAS latency we are comparing against + /// @return true iff desired CL was found in the bitmap of common CLs, false otherwise /// - inline fapi2::ReturnCode calc_cas_latency(const uint64_t i_taa, - const uint64_t i_tck, - uint64_t& o_cas_latency) const; + bool is_cl_supported_in_common(const std::vector& i_common_cls, + const uint64_t i_cas_latency) const; /// - /// @brief Helper function to create a vector of supported CAS latencies from a bitmap - /// @param[in] i_common_cl common CAS latency bitmap - /// @return vector of supported CAS latencies + /// @brief Checks that CAS latency doesn't exceed largest CAS latency time + /// @param[in] i_cas_latency cas latency + /// @param[in] i_tck cycle time + /// @return true iff CL exceeds tAAmax, false otherwise /// - std::vector integral_bitmap_to_vector(const uint64_t i_bitmap) const; + bool is_cl_exceeding_taa_max(const uint64_t i_cas_latency, + const uint64_t i_tck) const; /// - /// @brief Determines if a requested CAS latency (CL) is supported in the bin of common CLs - /// @param[in] i_common_cls vector of common CAS latencies - /// @param[in] i_cas_latency CAS latency we are comparing against - /// @return fapi2::FAPI2_RC_SUCCESS if ok + /// @brief Selects DIMM frequency to run based on supported system frequencies + /// @tparam TT the freq_select type + /// @param[in,out] io_dimm_freq input is current dimm freq & output is next + /// lowest dimm freq between 1866 MT/s - 2666 MT/s + /// @return FAPI2_RC_SUCCESS iff ok + /// @note Frequency values obtained from: + /// @note From P9 User's Manual Version 0.8 - June 08, 2015 + /// @note Memory Controller Unit - page 199 of 456 /// - inline fapi2::ReturnCode is_cl_supported_in_common(const std::vector& i_common_cls, - const uint64_t i_cas_latency) const; + template< freq_select TT > + inline fapi2::ReturnCode select_supported_freq(uint64_t& io_dimm_freq) + { + FAPI_TRY( (select_supported_freq_helper(iv_supported_freqs, io_dimm_freq)) ); + + fapi_try_exit: + return fapi2::current_err; + } /// - /// @brief Checks that CAS latency doesn't exceed largest CAS latency time - /// @param[in] i_cas_latency cas latency - /// @param[in] i_tck cycle time - /// @return fapi2::FAPI2_RC_SUCCESS if ok + /// @brief Limits tCK to system constraints (VPD and MRW) + /// @tparam T freq_select type + /// @param[in,out] io_tck input is current tCK, output is highest supported tCK (HIGHEST_COMMON specialization) + /// or the next highest supported tCK (BIN_DOWN specialization) + /// @return FAPI2_RC_SUCCESS iff okay /// - inline fapi2::ReturnCode is_cl_exceeding_taa_max(const uint64_t i_cas_latency, - const uint64_t i_tck) const; + template< freq_select T > + fapi2::ReturnCode apply_freq_constraints(uint64_t& io_tck) + { + uint64_t l_proposed_freq = 0; + FAPI_TRY( mss::ps_to_freq(io_tck, l_proposed_freq) ); -};// cas_latency + FAPI_TRY( (select_supported_freq(l_proposed_freq)), + "%s. Failed select_supported_freq()", mss::c_str(iv_target) ); + + FAPI_TRY( freq_to_ps(l_proposed_freq, io_tck), + "%s. Failed freq_to_ps()", mss::c_str(iv_target) ); + FAPI_INF("%s Supported dimm speed override %d MT/s (Clock period %d in ps)", + mss::c_str(iv_target), l_proposed_freq, io_tck); + + // Sanity check + FAPI_ASSERT(io_tck > 0, + fapi2::MSS_INVALID_CALCULATED_TCK(). + set_TAAMIN(iv_largest_taamin). + set_PROPOSED_TCK(io_tck). + set_IS_3DS(iv_is_3ds). + set_MCA_TARGET(iv_target), + "%s. Invalid calculated clock period(<= 0 nCK) : %d", + mss::c_str(iv_target), + io_tck); + + fapi_try_exit: + return fapi2::current_err; + } + +};// cas_latency }// mss 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 2c0338b64..4e2930711 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 @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -28,19 +28,21 @@ /// @brief Synchronous function implementations /// // *HWP HWP Owner: Andre Marin -// *HWP HWP Backup: Jacob Harvey +// *HWP HWP Backup: Louis Stermole // *HWP Team: Memory // *HWP Level: 3 // *HWP Consumed by: HB:FSP -#include -#include - #include +#include +#include +#include +#include #include #include #include #include +#include using fapi2::TARGET_TYPE_DIMM; using fapi2::TARGET_TYPE_MCS; @@ -309,60 +311,232 @@ fapi_try_exit: #endif } +/// +/// @brief Return whether a given freq is supported +/// @param[in] a freq to check for +/// @param[in] reference to a std::vector of supported freqs (sorted) +/// @return bool, true iff input freq is supported +/// +bool is_freq_supported(const uint32_t i_freq, const std::vector& i_freqs) +{ + return std::binary_search(i_freqs.begin(), i_freqs.end(), i_freq); +} + +/// +/// @brief Create a vector of support freq based on VPD config +/// @param[in] MCBIST target for which to get the DIMM configs +/// @param[out] reference to a std::vector of supported VPD frequencies +/// @return FAPI2_RC_SUCCESS iff ok +/// +fapi2::ReturnCode vpd_supported_freqs( const fapi2::Target& i_target, + std::vector& o_vpd_supported_freqs) +{ + uint8_t l_rank_count_dimm[MAX_DIMM_PER_PORT] = {}; + uint8_t l_mr_blob[mss::VPD_KEYWORD_MAX] = {}; + bool is_first_supported_freq = true; + + // Clearing output Just.In.Case + o_vpd_supported_freqs.clear(); + + fapi2::VPDInfo l_vpd_info(fapi2::MemVpdData::MR); + l_vpd_info.iv_is_config_ffdc_enabled = false; + + for( const auto& mcs : mss::find_targets(i_target) ) + { + for( const auto& p : mss::find_targets(mcs) ) + { + FAPI_TRY( mss::eff_num_master_ranks_per_dimm(p, &(l_rank_count_dimm[0])) ); + + l_vpd_info.iv_rank_count_dimm_0 = l_rank_count_dimm[0]; + l_vpd_info.iv_rank_count_dimm_1 = l_rank_count_dimm[1]; + + // Iterate through all Nimbus supported freqs + for( const auto& freq : NIMBUS_SUPPORTED_FREQS ) + { + l_vpd_info.iv_freq_mhz = freq; + + FAPI_INF("%s. VPD info - frequency: %d MT/s, rank count for dimm_0: %d, dimm_1: %d", + mss::c_str(p), l_vpd_info.iv_freq_mhz, l_vpd_info.iv_rank_count_dimm_0, l_vpd_info.iv_rank_count_dimm_1); + + // In order to retrieve the VPD contents we first need the keyword size. + // If we are unable to retrieve the keyword size then this speed isn't supported in the VPD + // and we skip to the next possible speed bin. + if( fapi2::getVPD(mcs, 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 ); + + // If we added a freq that was supported in one MCA, but isn't supported for + // another MCA under the same MCBIST (such as one port running single drop and another dual drop), + // we remove it from the VPD supported freq list. + auto l_it = std::find(o_vpd_supported_freqs.begin(), o_vpd_supported_freqs.end(), freq); + + if( l_it != o_vpd_supported_freqs.end() ) + { + o_vpd_supported_freqs.erase(l_it); + } + + continue; + } + + FAPI_ASSERT( l_vpd_info.iv_size <= mss::VPD_KEYWORD_MAX, + fapi2::MSS_INVALID_VPD_KEYWORD_MAX(). + set_MAX(mss::VPD_KEYWORD_MAX). + set_ACTUAL(l_vpd_info.iv_size). + set_KEYWORD(fapi2::MemVpdData::MR). + set_MCS_TARGET(i_target), + "VPD MR keyword size retrieved: %d, is larger than max: %d for %s", + l_vpd_info.iv_size, mss::VPD_KEYWORD_MAX, mss::c_str(i_target)); + + // If we are here then we should have a valid frequency selected from polling the VPD keyword size above. + // A hard-fail here means something is wrong and we want to return current_err instead of ignoring it. + FAPI_TRY( fapi2::getVPD(mcs, l_vpd_info, &(l_mr_blob[0])), + "Failed to retrieve VPD data for %s", mss::c_str(mcs) ); + + // Add non-repeating supported freqs + auto l_it = std::find(o_vpd_supported_freqs.begin(), o_vpd_supported_freqs.end(), freq); + + if( l_it == o_vpd_supported_freqs.end() || is_first_supported_freq ) + { + is_first_supported_freq = false; + FAPI_INF("VPD supported freq added: %d for %s", freq, mss::c_str(p) ); + o_vpd_supported_freqs.push_back(freq); + } + }// freqs + }// mca + }//mcs + + std::sort( o_vpd_supported_freqs.begin(), o_vpd_supported_freqs.end() ); + + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Removes frequencies unsupported by SPD from a sorted list of supported freqs -- helper function for testing +/// @param[in] i_target the MCBIST target +/// @param[in] i_highest_freq largest SPD supported freq +/// @param[in,out] io_freqs std::vector of VPD supported freqs (sorted) +/// +void rm_unsupported_spd_freqs(const fapi2::Target& i_target, + const uint32_t i_highest_freq, + std::vector& io_freqs) +{ + + // Don't use 'auto' since I want a const iterator and HB compiler + // bombs out using 'const auto'... + // The idea here is that if SPD across and MC can only support 2133 MT/s, + // we remove any supported frequencies in the vector higher than that (e.g. 2400, 2666) + auto it = std::upper_bound(io_freqs.begin(), io_freqs.end(), i_highest_freq); + + // Remove all frequencies higher than max supported SPD freq per MCBIST + // since we set freq at that level + if( it != io_freqs.end() ) + { + io_freqs.erase(it, io_freqs.end()); + } + + return; +} + +/// +/// @brief Retrieves largest supported frequency the MC supports due to DIMM SPD +/// @param[in] i_target the MCBIST target +/// @param[out] o_highest_freq the largest SPD supported freq +/// @return FAPI2_RC_SUCCESS iff okay +/// +fapi2::ReturnCode largest_spd_supported_freq(const fapi2::Target& i_target, + uint32_t& o_highest_freq) +{ + uint64_t l_largest_tck = 0; + + // Get cached decoder + std::vector< std::shared_ptr > l_factory_caches; + + FAPI_TRY( mss::spd::populate_decoder_caches(i_target, l_factory_caches), + "%s. Failed to populate decoder cache", mss::c_str(i_target) ); + + // Looking for the biggest application period on an MC. + // This will further reduce supported frequencies the system can run on. + for ( const auto& l_cache : l_factory_caches ) + { + const auto l_dimm = l_cache->iv_target; + uint64_t l_tckmax_in_ps = 0; + uint64_t l_tck_min_in_ps = 0; + + FAPI_TRY( get_tckmax(l_cache, l_tckmax_in_ps), + "%s. Failed to get tCKmax", mss::c_str(l_dimm) ); + FAPI_TRY( get_tckmin(l_cache, l_tck_min_in_ps), + "%s. Failed to get tCKmin", mss::c_str(l_dimm) ); + + // Determine a proposed tCK value that is greater than or equal tCKmin + // But less than tCKmax + l_largest_tck = std::max(l_largest_tck, l_tck_min_in_ps); + l_largest_tck = std::min(l_largest_tck, l_tckmax_in_ps); + } + + FAPI_TRY( mss::ps_to_freq(l_largest_tck, o_highest_freq) ); + FAPI_INF("Biggest freq supported from SPD %d MT/s for %s", + o_highest_freq, mss::c_str(i_target)); + +fapi_try_exit: + return fapi2::current_err; +} + /// /// @brief Create and sort a vector of supported MT/s (freq) -/// @param[in] MCA target for which to get the DIMM configs -/// @param[out] reference to a std::vector space to put the sorted vector +/// @param[in] i_target MCBIST target for which to get the DIMM configs +/// @param[out] o_freqs reference to a std::vector 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 +/// @note Taken from VPD supported freqs. 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& o_freqs) +fapi2::ReturnCode supported_freqs(const fapi2::Target& i_target, + std::vector& o_freqs) { o_freqs.clear(); - std::vector l_mrw_freqs(NUM_MRW_FREQS, 0); - std::vector l_max_freqs(NUM_MAX_FREQS, 0); + std::vector l_vpd_supported_freqs; + uint32_t l_largest_spd_freq = 0; uint8_t l_req_sync_mode = 0; - FAPI_TRY( mss::mrw_supported_freq(l_mrw_freqs.data()) ); + // Retrieve system MRW constraints + std::vector l_max_freqs(NUM_MAX_FREQS, 0); FAPI_TRY( mss::max_allowed_dimm_freq(l_max_freqs.data()) ); - FAPI_TRY( mss::required_synch_mode(l_req_sync_mode) ); - - FAPI_INF("attribute supported freqs %d %d %d %d", - l_mrw_freqs[0], l_mrw_freqs[1], l_mrw_freqs[2], l_mrw_freqs[3]); - FAPI_INF("attribute supported max freqs %d %d %d %d %d", - l_max_freqs[0], l_max_freqs[1], l_max_freqs[2], l_max_freqs[3], l_max_freqs[4]); + // Retrieve frequency constraints due to DIMM SPD and VPD per MCBIST + FAPI_TRY( largest_spd_supported_freq(i_target, l_largest_spd_freq) ); + FAPI_TRY( vpd_supported_freqs(i_target, l_vpd_supported_freqs) ); + rm_unsupported_spd_freqs(i_target, l_largest_spd_freq, l_vpd_supported_freqs); - FAPI_INF("attribute required sync mode %d", l_req_sync_mode); + FAPI_TRY( mss::required_synch_mode(l_req_sync_mode) ); FAPI_TRY( supported_freqs_helper( i_target, - l_mrw_freqs, + l_vpd_supported_freqs, l_max_freqs, l_req_sync_mode == fapi2::ENUM_ATTR_REQUIRED_SYNCH_MODE_ALWAYS, o_freqs) ); - fapi_try_exit: return fapi2::current_err; } /// /// @brief Create and sort a vector of supported MT/s (freq) - helper for testing purposes -/// @param[in] MCA target for which to get the DIMM configs -/// @param[in] vector of MRW freqs -/// @param[in] vector of max allowed freqs -/// @param[in] bool whether or not we're forced into sync mode -/// @param[out] reference to a std::vector space to put the sorted vector +/// @param[in] i_target MCBIST target for which to get the DIMM configs +/// @param[in] i_hw_freqs vector of hardware supported freqs -- from VPD and SPD +/// @param[in] i_max_mrw_freqs vector of max allowed freqs +/// @param[in] i_req_sync_mode bool whether or not we're forced into sync mode +/// @param[out] o_freqs reference to a std::vector to put the sorted vector /// @return FAPI2_RC_SUCCESS iff ok /// @note the attributes which drive this are read-only so they're hard to change when /// 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, - const std::vector& i_mrw_freqs, - const std::vector& i_max_freqs, +fapi2::ReturnCode supported_freqs_helper(const fapi2::Target& i_target, + const std::vector& i_hw_freqs, + const std::vector& i_max_mrw_freqs, const bool i_req_sync_mode, std::vector& o_freqs) { @@ -377,44 +551,46 @@ fapi2::ReturnCode supported_freqs_helper(const fapi2::Target& i // frequencies allowed by the DIMM. So, we start way off the charts so std::min can do the lifting for us. uint32_t l_our_max_freq = ~(0); - // This magic number isn't the number of frequencies supported by the hardware, it's the number - // of frequencies in the attribute or MRW. They may be different - FAPI_ASSERT( i_mrw_freqs.size() == NUM_MRW_FREQS, - fapi2::MSS_MRW_FREQ_SIZE_CHANGED() - .set_ACTUAL_SIZE(i_mrw_freqs.size()) - .set_SUPPOSED_SIZE(NUM_MRW_FREQS) - .set_MCA_TARGET(i_target), - "%s Incorrect number of frequencies (%d)", - mss::c_str(i_target), - i_mrw_freqs.size()); - - FAPI_INF("unsorted supported freqs %d %d %d %d", - i_mrw_freqs[0], i_mrw_freqs[1], i_mrw_freqs[2], i_mrw_freqs[3]); - // This is the number of elements in the max_allowed_dimm_freq attribute, not the frequencies of - // the system. Hence the magic number. - FAPI_ASSERT( i_max_freqs.size() == NUM_MAX_FREQS, + // the system. + FAPI_ASSERT( i_max_mrw_freqs.size() == NUM_MAX_FREQS, fapi2::MSS_MAX_FREQ_ATTR_SIZE_CHANGED() - .set_ACTUAL_SIZE(i_max_freqs.size()) + .set_ACTUAL_SIZE(i_max_mrw_freqs.size()) .set_SUPPOSED_SIZE(NUM_MAX_FREQS) .set_MCA_TARGET(i_target), "%s Incorrect number of max frequencies in attribute for (%d)", mss::c_str(i_target), - i_max_freqs.size()); + i_max_mrw_freqs.size()); + + FAPI_INF("attribute supported max allowed dimm freqs %d %d %d %d %d for %s", + i_max_mrw_freqs[0], i_max_mrw_freqs[1], i_max_mrw_freqs[2], i_max_mrw_freqs[3], i_max_mrw_freqs[4], + mss::c_str(i_target)); - 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]); + // This is the list of supported frequencies for VPD and SPD + FAPI_ASSERT( !i_hw_freqs.empty(), + fapi2::MSS_EMPTY_VECTOR(). + set_FUNCTION(SUPPORTED_FREQS). + set_TARGET(i_target), + "Supported system freqs from VPD and SPD are empty for %s", + mss::c_str(i_target)); + + for( const auto& freq : i_hw_freqs ) + { + FAPI_DBG("VPD supported freqs %d for %s", freq, mss::c_str(i_target) ); + } + + 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(); + const auto l_dimms = mss::find_targets(p); + const 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), + .set_MCA_TARGET(p), "Seeing %d DIMM on port %s", l_dimms_on_port, - mss::c_str(i_target)); + mss::c_str(p)); for (const auto& d : l_dimms) { @@ -447,87 +623,85 @@ fapi2::ReturnCode supported_freqs_helper(const fapi2::Target& i 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_index] ); + i_max_mrw_freqs[l_index] ); + + l_our_max_freq = std::min(l_our_max_freq, i_max_mrw_freqs[l_index]); + }// dimm + }// mca - 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); // We need to push things as the memcpy doesn't update the vector's count, etc. and we don't // create the vector, we get it passed in. It's not a big deal as we want to touch all the elements // to check for 0's anyway. - for (size_t i = 0; i < NUM_MRW_FREQS; ++i) + for (size_t i = 0; i < i_hw_freqs.size(); ++i) { // Funky if-tree makes things clearer than a combinatorialy explosive conditional - if (i_mrw_freqs[i] == 0) + if (i_hw_freqs[i] == 0) { // Skip 0's continue; } - if (i_mrw_freqs[i] > l_our_max_freq) + if (i_hw_freqs[i] > l_our_max_freq) { // Skip freqs larger than our max continue; } // Add this freq if we're not in sync mode, or, if we are, add it if it matches a nest freq - switch (i_req_sync_mode) + FAPI_INF("attribute required sync mode %d for %s", i_req_sync_mode, mss::c_str(i_target)); + + if( i_req_sync_mode && !is_nest_freq_valid(i_hw_freqs[i]) ) { - case true : - if (is_nest_freq_valid(i_mrw_freqs[i])) - { - o_freqs.push_back(i_mrw_freqs[i]); - } + continue; + } - break; + o_freqs.push_back(i_hw_freqs[i]); - case false : - o_freqs.push_back(i_mrw_freqs[i]); - break; - } + }//end for + + { + // Doing this because the HB compiler freaks out if we have it within the FAPI_ASSERT. + // Outputting the value and then incrementing the iterator, that's why it's a post increment + // We have at most 4 memory freqs (1866, 2133, 2400, & 2666), if we ever get a list with < 4 items + // a value of 0 is logged in FFDC once we hit i_hw_freqs.end()...which is better than no logging. + auto l_supported = i_hw_freqs.begin(); + + const auto l_freq0 = (l_supported != i_hw_freqs.end()) ? *(l_supported++) : 0; + const auto l_freq1 = (l_supported != i_hw_freqs.end()) ? *(l_supported++) : 0; + const auto l_freq2 = (l_supported != i_hw_freqs.end()) ? *(l_supported++) : 0; + const auto l_freq3 = (l_supported != i_hw_freqs.end()) ? *(l_supported++) : 0; + + // If we have an empty set, we have a problem + FAPI_ASSERT(o_freqs.size() != 0, + fapi2::MSS_MRW_FREQ_MAX_FREQ_EMPTY_SET() + .set_MSS_VPD_FREQ_0(l_freq0) + .set_MSS_VPD_FREQ_1(l_freq1) + .set_MSS_VPD_FREQ_2(l_freq2) + .set_MSS_VPD_FREQ_3(l_freq3) + .set_MSS_MAX_FREQ_0(i_max_mrw_freqs[0]) + .set_MSS_MAX_FREQ_1(i_max_mrw_freqs[1]) + .set_MSS_MAX_FREQ_2(i_max_mrw_freqs[2]) + .set_MSS_MAX_FREQ_3(i_max_mrw_freqs[3]) + .set_MSS_MAX_FREQ_4(i_max_mrw_freqs[4]) + .set_MSS_NEST_FREQ_0(fapi2::ENUM_ATTR_FREQ_PB_MHZ_1600) + .set_MSS_NEST_FREQ_1(fapi2::ENUM_ATTR_FREQ_PB_MHZ_1866) + .set_MSS_NEST_FREQ_2(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2000) + .set_MSS_NEST_FREQ_3(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2133) + .set_MSS_NEST_FREQ_4(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2400) + .set_REQUIRED_SYNC_MODE(i_req_sync_mode) + .set_MAX_FREQ_FROM_DIMM(l_our_max_freq) + .set_MCBIST_TARGET(i_target), + "%s didn't find a frequency which was in VPD and was allowable max", mss::c_str(i_target)); } // We now know o_freqs contains valid frequencies for this DIMM config, system contraints, and sync mode. // Sort it so we know supported min is o_freq.begin and supported max is o_freq.end - 1 std::sort(o_freqs.begin(), o_freqs.end()); - // If we have an empty set, we have a problem - FAPI_ASSERT(o_freqs.size() != 0, - fapi2::MSS_MRW_FREQ_MAX_FREQ_EMPTY_SET() - .set_MSS_MRW_FREQ_0(i_mrw_freqs[0]) - .set_MSS_MRW_FREQ_1(i_mrw_freqs[1]) - .set_MSS_MRW_FREQ_2(i_mrw_freqs[2]) - .set_MSS_MRW_FREQ_3(i_mrw_freqs[3]) - .set_MSS_MAX_FREQ_0(i_max_freqs[0]) - .set_MSS_MAX_FREQ_1(i_max_freqs[1]) - .set_MSS_MAX_FREQ_2(i_max_freqs[2]) - .set_MSS_MAX_FREQ_3(i_max_freqs[3]) - .set_MSS_MAX_FREQ_4(i_max_freqs[4]) - .set_MSS_NEST_FREQ_0(fapi2::ENUM_ATTR_FREQ_PB_MHZ_1600) - .set_MSS_NEST_FREQ_1(fapi2::ENUM_ATTR_FREQ_PB_MHZ_1866) - .set_MSS_NEST_FREQ_2(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2000) - .set_MSS_NEST_FREQ_3(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2133) - .set_MSS_NEST_FREQ_4(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2400) - .set_REQUIRED_SYNC_MODE(i_req_sync_mode) - .set_MAX_FREQ_FROM_DIMM(l_our_max_freq) - .set_MCA_TARGET(i_target), - "%s didn't find a frequency which was in VPD and was allowable max", mss::c_str(i_target)); - fapi_try_exit: return fapi2::current_err; } -/// -/// @brief Return whether a given freq is supported -/// @param[in] a freq to check for -/// @param[in] reference to a std::vector of freqs -/// @return bool, true iff input freq is supported -/// -bool is_freq_supported(const uint32_t i_freq, const std::vector& i_freqs) -{ - return std::binary_search(i_freqs.begin(), i_freqs.end(), i_freq); -} - }// mss 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 3c3b89d7e..ea057431b 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 @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -27,7 +27,7 @@ /// @brief Synchronous function implementations /// // *HWP HWP Owner: Andre Marin -// *HWP HWP Backup: Jacob Harvey +// *HWP HWP Backup: Louis Stermole // *HWP Team: Memory // *HWP Level: 3 // *HWP Consumed by: HB:FSP @@ -45,8 +45,17 @@ namespace mss enum class speed_equality : uint8_t { - NOT_EQUAL_DIMM_SPEEDS = 0, - EQUAL_DIMM_SPEEDS = 1, + NOT_EQUAL_DIMM_SPEEDS = 0, ///< denotes all DIMMs don't have the same speed + EQUAL_DIMM_SPEEDS = 1, ///< denotes all DIMMs have the same speed +}; + +// DDR4 speed NIMBUS supports +static const std::vector NIMBUS_SUPPORTED_FREQS = +{ + fapi2::ENUM_ATTR_MSS_FREQ_MT1866, + fapi2::ENUM_ATTR_MSS_FREQ_MT2133, + fapi2::ENUM_ATTR_MSS_FREQ_MT2400, + fapi2::ENUM_ATTR_MSS_FREQ_MT2666, }; /// @@ -62,8 +71,8 @@ inline bool is_nest_freq_valid (const uint64_t i_proposed_freq) fapi2::ENUM_ATTR_FREQ_PB_MHZ_2133, fapi2::ENUM_ATTR_FREQ_PB_MHZ_2400 }; - std::sort(l_nest_freqs_supported.begin(), l_nest_freqs_supported.end()); + std::sort(l_nest_freqs_supported.begin(), l_nest_freqs_supported.end()); return ( std::binary_search(l_nest_freqs_supported.begin(), l_nest_freqs_supported.end(), i_proposed_freq) ); } @@ -107,93 +116,69 @@ fapi2::ReturnCode select_sync_mode(const std::map< fapi2::Target space to put the sorted vector +/// @brief Return whether a given freq is supported +/// @param[in] a freq to check for +/// @param[in] reference to a std::vector of supported freqs (sorted) +/// @return bool true iff input freq is supported +/// +bool is_freq_supported(const uint32_t i_freq, const std::vector& i_freqs); + +/// @brief Create a vector of support freq based on VPD config +/// @param[in] MCBIST target for which to get the DIMM configs +/// @param[out] reference to a std::vector of supported VPD frequencies /// @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_helper(const fapi2::Target& i_target, - const std::vector& i_freqs, - const std::vector& i_max_freqs, - const bool i_req_sync_mode, - std::vector& o_freqs); +fapi2::ReturnCode vpd_supported_freqs( const fapi2::Target& i_target, + std::vector& o_vpd_supported_freqs); + +/// +/// @brief Removes frequencies unsupported by SPD from a sorted list of supported freqs -- helper function for testing +/// @param[in] i_target the MCBIST target +/// @param[in] i_highest_freq largest SPD supported freq +/// @param[in,out] io_freqs std::vector of VPD supported freqs (sorted) +/// +void rm_unsupported_spd_freqs(const fapi2::Target& i_target, + const uint32_t l_current_freq, + std::vector& io_freqs); + +/// +/// @brief Retrieves largest supported frequency the MC supports due to DIMM SPD +/// @param[in] i_target the MCBIST target +/// @param[out] o_highest_freq the largest SPD supported freq +/// @return FAPI2_RC_SUCCESS iff okay +/// +fapi2::ReturnCode largest_spd_supported_freq(const fapi2::Target& i_target, + uint32_t& o_highest_freq); /// /// @brief Create and sort a vector of supported MT/s (freq) -/// @param[in] MCA target for which to get the DIMM configs -/// @param[out] reference to a std::vector space to put the sorted vector +/// @param[in] i_target MCA target for which to get the DIMM configs +/// @param[out] o_freqs reference to a std::vector 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 +/// @note Taken from VPD supported freqs. 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& o_freqs); /// -/// @brief Return whether a given freq is supported -/// @param[in] a freq to check for -/// @param[in] reference to a std::vector of freqs -/// @return bool, true iff input freq is supported -/// -bool is_freq_supported(const uint32_t i_freq, const std::vector& i_freqs); - -/// -/// @brief Selects DIMM frequency to run based on supported system frequencies -/// @tparam T the fapi2::TargetType for which the DIMM information exists. -/// @param[in] target from which to get the dimm information -/// @param[in,out] io_dimm_freq input is current dimm freq & output is next -/// lowest dimm freq between 1866 MT/s (-5% margin) - 2666 MT/s (+5% margin) -/// @return FAPI2_RC_SUCCESS iff ok -/// @note Frequency values obtained from: -/// @note From P9 User's Manual Version 0.8 - June 08, 2015 -/// @note Memory Controller Unit - page 199 of 456 +/// @brief Create and sort a vector of supported MT/s (freq) - helper for testing purposes +/// @param[in] MCA target for which to get the DIMM configs +/// @param[in] vector of VPD freqs +/// @param[in] vector of max allowed freqs +/// @param[in] bool whether or not we're forced into sync mode +/// @param[out] reference to a std::vector to put the sorted vector +/// @return FAPI2_RC_SUCCESS iff ok +/// @note the attributes which drive this are read-only so they're hard to change when +/// 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.) /// -template< fapi2::TargetType T > -inline fapi2::ReturnCode select_supported_freq(const fapi2::Target& i_target, uint64_t& io_dimm_freq) -{ - std::vector l_freqs; - - FAPI_TRY( mss::supported_freqs(i_target, l_freqs) ); - - { - // supported_freqs sorts so upper_bound is valid. - auto iterator = std::upper_bound(l_freqs.begin(), l_freqs.end(), io_dimm_freq); - - auto l_supported = l_freqs.begin(); - - // Doing this because the HB compiler freaks out if we have it within the FAPI_ASSERT. - // Outputting the value and then incrementing the iterator, that's why it's a post increment - const auto l_0 = (l_supported != l_freqs.end()) ? *(l_supported++) : 0; - const auto l_1 = (l_supported != l_freqs.end()) ? *(l_supported++) : 0; - const auto l_2 = (l_supported != l_freqs.end()) ? *(l_supported++) : 0; - const auto l_3 = (l_supported != l_freqs.end()) ? *(l_supported++) : 0; - - FAPI_ASSERT( (iterator != l_freqs.begin() && l_freqs.size() != 0), - fapi2::MSS_SELECTED_FREQ_NOT_SUPPORTED() - .set_FREQ(io_dimm_freq) - .set_SUPPORTED_FREQ_0( l_0 ) - .set_SUPPORTED_FREQ_1( l_1 ) - .set_SUPPORTED_FREQ_2( l_2 ) - .set_SUPPORTED_FREQ_3( l_3 ) - .set_TARGET(i_target), - "%s Error finding selected freq (%d) from list", - mss::c_str(i_target), - io_dimm_freq ); - // Upper bound checks just greater than, not equals. Return one up - io_dimm_freq = *(--iterator); - } - -fapi_try_exit: - return fapi2::current_err; -} - +fapi2::ReturnCode supported_freqs_helper(const fapi2::Target& i_target, + const std::vector& i_vpd_freqs, + const std::vector& i_max_freqs, + const bool i_req_sync_mode, + std::vector& o_freqs); }// mss #endif diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H b/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H index cee0e9b84..60aaa2f00 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H @@ -184,6 +184,13 @@ enum ffdc_function_codes READ_RD_VREF_VALUES_FOR_DRAM = 93, GET_DRAM_DISABLE_REG_AND_POS = 94, GET_STARTING_WR_DQ_DELAY_VALUE = 95, + + GET_TAAMIN = 96, + GET_TCKMIN = 97, + GET_TCKMAX = 98, + + SUPPORTED_FREQS = 99, + SELECT_SUPPORTED_FREQ = 100, }; enum states 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 92a3402cf..f57d414c0 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 @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -52,6 +52,7 @@ #include #include #include +#include using fapi2::TARGET_TYPE_MCA; using fapi2::TARGET_TYPE_MCS; @@ -60,6 +61,135 @@ using fapi2::FAPI2_RC_SUCCESS; namespace mss { + + +/// +/// @brief Helper function to retrieves medium and fine timebase values +/// @param[in] i_pDecoder the SPD decoder +/// @param[out] o_mtb the medium timebase (MTB) from SPD +/// @param[out] o_ftb the fine timebase (FTB) from SPD +/// @return FAPI2_RC_SUCCESS iff ok +/// +static fapi2::ReturnCode get_timebases( const std::shared_ptr& i_pDecoder, + int64_t& o_mtb, + int64_t& o_ftb ) +{ + // Retrieve timing parameters + const auto l_target = i_pDecoder->iv_target; + + FAPI_TRY( i_pDecoder->medium_timebase(o_mtb), + "%s. Failed medium_timebase()", mss::c_str(l_target) ); + FAPI_TRY( i_pDecoder->fine_timebase(o_ftb), + "%s. Failed fine_timebase()", mss::c_str(l_target) ); + + FAPI_INF("MTB: %d, FTB: %d for %s", o_mtb, o_ftb, mss::c_str(l_target)); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Retrieves SDRAM Minimum Cycle Time (tCKmin) from SPD +/// @param[in] i_pDecoder the SPD decoder +/// @param[out] o_value tCKmin value in ps +/// @return FAPI2_RC_SUCCESS iff ok +/// +fapi2::ReturnCode get_tckmin( const std::shared_ptr& i_pDecoder, + uint64_t& o_value ) +{ + int64_t l_timing_ftb = 0; + int64_t l_timing_mtb = 0; + int64_t l_medium_timebase = 0; + int64_t l_fine_timebase = 0; + int64_t l_temp = 0; + + // Retrieve timing parameters + const auto l_target = i_pDecoder->iv_target; + + FAPI_TRY( get_timebases(i_pDecoder, l_medium_timebase, l_fine_timebase), + "%s. Failed get_timebases", mss::c_str(l_target) ); + FAPI_TRY( i_pDecoder->min_tck(l_timing_mtb), + "%s. Failed min_tck()", mss::c_str(l_target) ); + FAPI_TRY( i_pDecoder->fine_offset_min_tck(l_timing_ftb), + "%s. Failed fine_offset_min_tck()", mss::c_str(l_target) ); + + // Calculate timing value + l_temp = spd::calc_timing_from_timebase(l_timing_mtb, + l_medium_timebase, + l_timing_ftb, + l_fine_timebase); + + // Sanity check + FAPI_ASSERT(l_temp > 0, + fapi2::MSS_INVALID_TIMING_VALUE(). + set_VALUE(l_temp). + set_FUNCTION(GET_TCKMIN). + set_DIMM_TARGET(l_target), + "%s. tCKmin invalid (<= 0) : %d", + mss::c_str(l_target), + l_temp); + + o_value = l_temp; + + FAPI_INF("%s. tCKmin (ps): %d", + mss::c_str(l_target), + o_value ); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Retrieves SDRAM Maximum Cycle Time (tCKmax) from SPD +/// @param[in] i_pDecoder SPD decoder +/// @param[out] o_value tCKmax value in ps +/// @return FAPI2_RC_SUCCESS iff ok +/// +fapi2::ReturnCode get_tckmax( const std::shared_ptr& i_pDecoder, + uint64_t& o_value ) +{ + int64_t l_timing_ftb = 0; + int64_t l_timing_mtb = 0; + int64_t l_medium_timebase = 0; + int64_t l_fine_timebase = 0; + int64_t l_temp = 0; + + // Retrieve timing parameters + const auto l_target = i_pDecoder->iv_target; + + FAPI_TRY( get_timebases(i_pDecoder, l_medium_timebase, l_fine_timebase), + "%s. Failed get_timebases", mss::c_str(l_target) ); + FAPI_TRY( i_pDecoder->max_tck(l_timing_mtb), + "%s. Failed max_tck()", mss::c_str(l_target) ); + FAPI_TRY( i_pDecoder->fine_offset_max_tck(l_timing_ftb), + "%s. Failed fine_offset_max_tck()", mss::c_str(l_target) ); + + // Calculate timing value + l_temp = spd::calc_timing_from_timebase(l_timing_mtb, + l_medium_timebase, + l_timing_ftb, + l_fine_timebase); + + // Sanity check + FAPI_ASSERT(l_temp > 0, + fapi2::MSS_INVALID_TIMING_VALUE(). + set_VALUE(l_temp). + set_FUNCTION(GET_TCKMAX). + set_DIMM_TARGET(l_target), + "%s. tCKmax invalid (<= 0) : %d", + mss::c_str(l_target), + l_temp); + + o_value = l_temp; + + FAPI_INF( "%s. tCKmax (ps): %d", + mss::c_str(l_target), + o_value); + +fapi_try_exit: + return fapi2::current_err; +} + namespace spd { 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 281916d0b..88dbd1f03 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 @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -257,6 +257,25 @@ fapi_try_exit: } }// spd + +/// +/// @brief Retrieves SDRAM Minimum Cycle Time (tCKmin) from SPD +/// @param[in] i_pDecoder the SPD decoder +/// @param[out] o_value tCKmin value in ps +/// @return FAPI2_RC_SUCCESS iff ok +/// +fapi2::ReturnCode get_tckmin(const std::shared_ptr& i_pDecoder, + uint64_t& o_value); + +/// +/// @brief Retrieves SDRAM Maximum Cycle Time (tCKmax) from SPD +/// @param[in] i_pDecoder SPD decoder +/// @param[out] o_value tCKmax value in ps +/// @return FAPI2_RC_SUCCESS iff ok +/// +fapi2::ReturnCode get_tckmax(const std::shared_ptr& i_pDecoder, + uint64_t& o_value); + }// mss #endif //_MSS_SPD_FACTORY_H_ 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 86ef6f407..ce2bb06e1 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 @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* Contributors Listed Below - COPYRIGHT 2015,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -78,11 +78,9 @@ extern "C" // So for now, iterate over all the MCBIST. This isn't great as we do this work // twice for every MC. However, attribute access is cheap so this will suffice for // the time being. - - 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); + std::vector< std::vector > l_min_dimm_freq(mss::MCS_PER_MC, std::vector (mss::PORTS_PER_MCS, 0) ); + std::vector l_supported_freqs; // If there are no DIMM, we can just get out. if (mss::count_dimm(l_mcbist) == 0) @@ -91,6 +89,9 @@ extern "C" return FAPI2_RC_SUCCESS; } + // Get supported freqs for this MCBIST + FAPI_TRY( mss::supported_freqs(l_mcbist, l_supported_freqs) ); + for (const auto& l_mcs : mss::find_targets(l_mcbist)) { const auto l_mcs_index = mss::index(l_mcs); @@ -99,65 +100,59 @@ extern "C" for (const auto& l_mca : mss::find_targets(l_mcs) ) { - const auto l_index = mss::index(l_mca); - - // Get cached decoder + const auto l_mca_index = mss::index(l_mca); std::vector< std::shared_ptr > l_factory_caches; + fapi2::ReturnCode l_rc; + // Get cached decoder FAPI_TRY( mss::spd::populate_decoder_caches(l_mca, l_factory_caches), "%s. Failed to populate decoder cache", mss::c_str(l_mca) ); - { - // 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(l_mca) ); + // Instantiation of class that calculates CL algorithm + mss::cas_latency l_cas_latency( l_mca, l_factory_caches, l_supported_freqs, l_rc ); - if(l_cas_latency.iv_dimm_list_empty) - { - // Cannot fail out for an empty DIMM configuration, so default values are set - FAPI_INF("%s. DIMM list is empty! Setting default values for CAS latency and DIMM speed.", - mss::c_str(l_mca) ); - } - else - { - // We set this to a non-0 so we avoid divide-by-zero errors in the conversions which - // go from clocks to time (and vice versa.) We have other bugs if there was really - // no MT/s determined and there really is a DIMM installed, so this is ok. - // We pick the maximum frequency supported by the system as the default. - uint64_t l_desired_cl = 0; + FAPI_TRY( l_rc, "%s. Failed to initialize cas_latency ctor", mss::c_str(l_mca) ); - l_min_dimm_freq[l_mcs_index][l_index] = fapi2::ENUM_ATTR_MSS_FREQ_MT2666; + if(l_cas_latency.iv_dimm_list_empty) + { + // Cannot fail out for an empty DIMM configuration, so default values are set + FAPI_INF("%s. DIMM list is empty! Setting default values for CAS latency and DIMM speed.", + mss::c_str(l_mca) ); + } - uint64_t l_tCKmin = 0; + else + { + // We set this to a non-0 so we avoid divide-by-zero errors in the conversions which + // go from clocks to time (and vice versa.) We have other bugs if there was really + // no MT/s determined and there really is a DIMM installed, so this is ok. + // We pick the maximum frequency supported by the system as the default. + uint64_t l_desired_cl = 0; - // Find CAS latency using JEDEC algorithm - FAPI_TRY( l_cas_latency.find_cl(l_desired_cl, l_tCKmin) ); + l_min_dimm_freq[l_mcs_index][l_mca_index] = fapi2::ENUM_ATTR_MSS_FREQ_MT2666; - FAPI_INF("%s. Result from CL algorithm, CL (nck): %d, tCK (ps): %d", - mss::c_str(l_mca), l_desired_cl, l_tCKmin); + uint64_t l_tCKmin = 0; - l_desired_cas_latency.push_back(std::make_pair(l_desired_cl, l_mca) ); + // Find CAS latency using JEDEC algorithm + FAPI_TRY( l_cas_latency.find_cl(l_desired_cl, 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(l_mca) ); + FAPI_INF("%s. Result from CL algorithm, CL (nck): %d, tCK (ps): %d", + mss::c_str(l_mca), l_desired_cl, l_tCKmin); - 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)); + l_desired_cas_latency.push_back(std::make_pair(l_desired_cl, 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)); + // Find dimm transfer speed from selected tCK + FAPI_TRY( mss::ps_to_freq(l_tCKmin, l_min_dimm_freq[l_mcs_index][l_mca_index]), + "%s. Failed ps_to_freq()", mss::c_str(l_mca) ); - FAPI_INF("%s. Selected DIMM speed from supported speeds: %d", - mss::c_str(l_mca), l_min_dimm_freq[l_mcs_index][l_index]); + FAPI_INF("DIMM speed from selected tCK (ps): %d for %s", + l_min_dimm_freq[l_mcs_index][l_mca_index], + mss::c_str(l_mca)); - }// end else + FAPI_INF("%s. Selected DIMM speed from supported speeds: %d", + mss::c_str(l_mca), l_min_dimm_freq[l_mcs_index][l_mca_index]); - } // close scope - } // End + }// end else + } // mca FAPI_TRY(mss::set_CL_attr(l_mcs, l_desired_cas_latency), "%s. Failed set_CL_attr()", mss::c_str(i_target) ); 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 d259105a2..64286aadd 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,2017 */ +/* Contributors Listed Below - COPYRIGHT 2015,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -113,6 +113,7 @@ inline fapi2::ReturnCode set_freq_attrs(const fapi2::Target - + @@ -81,7 +81,6 @@ TAAMIN PROPOSED_TCK IS_3DS - FREQUENCY CODE HIGH @@ -127,22 +126,12 @@ RC_MSS_FAILED_TO_FIND_SUPPORTED_CL - Desired frequency from MRW is not supported by the DIMMS installed - Checked via comparing Cas Latencies supported by DIMM and by CL calculated from MRW FREQ + Desired CAS latency isn't supported in the common CAS latency bin retrieved from SPD. DESIRED_CAS_LATENCY COMMON_CLS TAA TCK - MSS_MRW_FREQ_0 - MSS_MRW_FREQ_1 - MSS_MRW_FREQ_2 - MSS_MRW_FREQ_3 - MSS_MAX_FREQ_0 - MSS_MAX_FREQ_1 - MSS_MAX_FREQ_2 - MSS_MAX_FREQ_3 - MSS_MAX_FREQ_4 CODE HIGH @@ -332,10 +321,10 @@ remaining If sync mode required, frequencies have to match a nest frequency - MSS_MRW_FREQ_0 - MSS_MRW_FREQ_1 - MSS_MRW_FREQ_2 - MSS_MRW_FREQ_3 + MSS_VPD_FREQ_0 + MSS_VPD_FREQ_1 + MSS_VPD_FREQ_2 + MSS_VPD_FREQ_3 MSS_MAX_FREQ_0 MSS_MAX_FREQ_1 MSS_MAX_FREQ_2 @@ -354,7 +343,7 @@ - MCA_TARGET + MCBIST_TARGET TARGET_TYPE_DIMM MEDIUM diff --git a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_general_errors.xml b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_general_errors.xml index 9c94d8bd1..dbd872155 100644 --- a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_general_errors.xml +++ b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_general_errors.xml @@ -5,7 +5,7 @@ - + @@ -35,6 +35,22 @@ + + RC_MSS_EMPTY_VECTOR + + Empty vector conditional failed. + + RECEIVED + FUNCTION + + TARGET + MEDIUM + + + CODE + LOW + + RC_MSS_INVALID_DIMM_TYPE -- cgit v1.2.1