diff options
author | Stephen Glancy <sglancy@us.ibm.com> | 2018-08-24 13:51:23 -0500 |
---|---|---|
committer | Christian R. Geddes <crgeddes@us.ibm.com> | 2018-09-07 15:21:29 -0500 |
commit | 6a6d637366355b8c14ba53f83e2a14dade48135c (patch) | |
tree | 885bf60d62032e729a96708ab2026e027172c00d /src | |
parent | 30603769812267f6c947357fce6a6edff50e27d2 (diff) | |
download | talos-hostboot-6a6d637366355b8c14ba53f83e2a14dade48135c.tar.gz talos-hostboot-6a6d637366355b8c14ba53f83e2a14dade48135c.zip |
Moves CAS latency algorithm to generic folder
Change-Id: Ie2a7e7f7b1f1e0f78716d458531715016a539ec0
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/65187
Dev-Ready: STEPHEN GLANCY <sglancy@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: HWSV CI <hwsv-ci+hostboot@us.ibm.com>
Reviewed-by: Louis Stermole <stermole@us.ibm.com>
Reviewed-by: ANDRE A. MARIN <aamarin@us.ibm.com>
Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com>
Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com>
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/65210
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
Diffstat (limited to 'src')
12 files changed, 1036 insertions, 1075 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 deleted file mode 100644 index 1e1494560..000000000 --- a/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.C +++ /dev/null @@ -1,504 +0,0 @@ -/* IBM_PROLOG_BEGIN_TAG */ -/* This is an automatically generated prolog. */ -/* */ -/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.C $ */ -/* */ -/* OpenPOWER HostBoot Project */ -/* */ -/* Contributors Listed Below - COPYRIGHT 2016,2018 */ -/* [+] International Business Machines Corp. */ -/* */ -/* */ -/* Licensed under the Apache License, Version 2.0 (the "License"); */ -/* you may not use this file except in compliance with the License. */ -/* You may obtain a copy of the License at */ -/* */ -/* http://www.apache.org/licenses/LICENSE-2.0 */ -/* */ -/* Unless required by applicable law or agreed to in writing, software */ -/* distributed under the License is distributed on an "AS IS" BASIS, */ -/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ -/* implied. See the License for the specific language governing */ -/* permissions and limitations under the License. */ -/* */ -/* IBM_PROLOG_END_TAG */ - -/// -/// @file cas_latency.C -/// @brief CAS latency class implementation -/// -// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com> -// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com> -// *HWP Team: Memory -// *HWP Level: 3 -// *HWP Consumed by: HB:FSP - -// std lib -#include <limits.h> -#include <algorithm> - -// fapi2 -#include <fapi2.H> - -// mss lib -#include <lib/freq/cas_latency.H> -#include <generic/memory/lib/data_engine/pre_data_init.H> -#include <lib/eff_config/timing.H> -#include <generic/memory/lib/spd/spd_utils.H> -#include <generic/memory/lib/utils/find.H> -#include <lib/utils/checker.H> - -using fapi2::TARGET_TYPE_DIMM; -using fapi2::TARGET_TYPE_MCS; -using fapi2::TARGET_TYPE_MCA; - -namespace mss -{ - -///////////////////////// -// 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 -/// @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<fapi2::TARGET_TYPE_MCA>& i_target, - const std::vector< spd::facade >& i_caches, - const std::vector<uint32_t>& 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_bitmap(UINT64_MAX), - iv_supported_freqs(i_supported_freqs) -{ - o_rc = fapi2::FAPI2_RC_SUCCESS; - - if( i_caches.empty() ) - { - FAPI_INF("cas latency ctor seeing no SPD caches for %s", mss::c_str(i_target) ); - iv_dimm_list_empty = true; - return; - } - - for ( const auto& l_cache : i_caches ) - { - // Retrieve timing values from the SPD - const auto l_target = l_cache.get_dimm_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(l_target) ); - FAPI_TRY( spd::get_tckmax(l_cache, l_tckmax_in_ps), - "%s. Failed to get tCKmax", mss::c_str(l_target) ); - FAPI_TRY( spd::get_tckmin(l_cache, l_tck_min_in_ps), - "%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); - - // Determine a proposed tCK value that is greater than or equal tCKmin - // But less than tCKmax - iv_proposed_tck = std::max(iv_proposed_tck, l_tck_min_in_ps); - iv_proposed_tck = std::min(iv_proposed_tck, l_tckmax_in_ps); - - // Collecting stack type - // If I have at least one 3DS DIMM connected I have - // to use 3DS tAAmax of 21.5 ps versus 18 ps for non-3DS DDR4 - if( iv_is_3ds != loading::IS_3DS) - { - uint8_t l_stack_type = 0; - FAPI_TRY( l_cache.prim_sdram_signal_loading(l_stack_type) ); - - // Is there a more algorithmic efficient approach? - AAM - iv_is_3ds = (l_stack_type == fapi2::ENUM_ATTR_EFF_PRIM_STACK_TYPE_3DS) ? - loading::IS_3DS : loading::NOT_3DS; - } - - { - // 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(l_target) ); - - // Bitwise ANDING the bitmap from all modules creates a bitmap w/a common CL - iv_common_cl_bitmap &= l_dimm_supported_cl; - } - }// caches - - // 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_bitmap != 0, - fapi2::MSS_NO_COMMON_SUPPORTED_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("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; - return; -}// ctor - - -/// -/// @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<fapi2::TARGET_TYPE_MCA>& 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 uint8_t i_req_sync_mode, - const std::vector<uint32_t>& 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_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<TARGET_TYPE_DIMM>(iv_target); - - if(l_dimm_list.empty()) - { - 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. -/// @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 -/// -fapi2::ReturnCode cas_latency::find_cl(uint64_t& o_cas_latency, - uint64_t& o_tck) -{ - fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; - - // 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) - { - // 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; - } - - 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<HIGHEST_COMMON>(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<BIN_DOWN>(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) ); - - // Choose an actual CAS Latency (CLactual) that is greater than or equal to CLdesired - // and is supported by all modules on the memory channel - 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. - 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 - o_cas_latency = l_desired_cas_latency; - o_tck = iv_proposed_tck; - -fapi_try_exit: - return fapi2::current_err; -} - -/// -/// @brief Retrieves SDRAM Minimum CAS Latency Time (tAAmin) from SPD -/// @param[in] i_spd_decoder the SPD decoder -/// @param[out] o_value tCKmin value in ps -/// @return FAPI2_RC_SUCCESS iff ok -/// -fapi2::ReturnCode cas_latency::get_taamin( const mss::spd::facade& i_spd_decoder, - 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_spd_decoder.get_dimm_target(); - - FAPI_TRY( get_timebases(i_spd_decoder, l_medium_timebase, l_fine_timebase), - "%s. Failed Failed get_timebases", mss::c_str(l_target) ); - - FAPI_TRY( i_spd_decoder.min_taa(l_timing_mtb), - "%s. Failed min_taa()", mss::c_str(l_target) ); - FAPI_TRY( i_spd_decoder.fine_offset_min_taa(l_timing_ftb), - "%s. Failed fine_offset_min_taa()", 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(o_value). - set_FUNCTION(GET_TAAMIN). - set_DIMM_TARGET(l_target), - "%s. tAAmin invalid (<= 0) : %d", - mss::c_str(l_target), - l_temp); - - o_value = l_temp; - FAPI_INF( "%s. tAAmin (ps): %d", - mss::c_str(l_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 -/// -inline uint64_t cas_latency::get_max_cl(const fapi2::buffer<uint64_t> i_supported_cl) const -{ - // If the last of Byte 23 of the SPD is 1, this selects CL values - // in the High CL range (23 to 52) - - // If the last bit of Byte 23 of the SPD is 0, this selects CL values - // in the Low CL range (7 to 36) - //Assuming bitmap is right aligned - return i_supported_cl.getBit<CAS_LAT_RANGE_BIT>() ? HIGH_RANGE_MAX_CL_DDR4 : LOW_RANGE_MAX_CL_DDR4; -} - -/// -/// @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<uint64_t>& i_supported_cl) const -{ - // If the last of Byte 23 of the SPD is 1, this selects CL values - // in the High CL range (23 to 52) - - // If the last bit of Byte 23 of the SPD is 0, this selects CL values - // in the Low CL range (7 to 36) - return i_supported_cl.getBit<CAS_LAT_RANGE_BIT>() ? HIGH_RANGE_MIN_CL_DDR4 : LOW_RANGE_MIN_CL_DDR4; - -} - -/// -/// @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 fapi2::ReturnCode cas_latency::calc_cas_latency(const uint64_t i_taa, - const uint64_t i_tck, - uint64_t& o_cas_latency) const -{ - FAPI_TRY( spd::calc_nck(i_taa, i_tck, spd::INVERSE_DDR4_CORRECTION_FACTOR, o_cas_latency) ); - - FAPI_INF("%s. tAA (ps): %d, tCK (ps): %d, CL (nck): %d", - mss::c_str(iv_target), - i_taa, - i_tck, - o_cas_latency); - -fapi_try_exit: - return fapi2::current_err; -} - -/// -/// @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<uint64_t> cas_latency::integral_bitmap_to_vector(const uint64_t i_common_cl) const -{ - std::vector<uint64_t> l_vector; - fapi2::buffer<uint64_t> l_cl_mask(i_common_cl); - - 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), l_min_cl); - FAPI_INF("%s. max CL %lu", mss::c_str(iv_target), l_max_cl); - - 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 - l_min_cl); - - // Traversing through buffer one bit at a time - // 0 means unsupported CAS latency - // 1 means supported CAS latency - // We are pushing supported CAS latencies into a vector for direct use - 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 (0x%llX)", - mss::c_str(iv_target), l_cas_latency, i_common_cl ); - - l_vector.push_back(l_cas_latency); - } - } - - return l_vector; -} - -/// -/// @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 bool cas_latency::is_cl_supported_in_common(const std::vector<uint64_t>& i_common_cls, - const uint64_t i_cas_latency) const -{ - const bool l_found = std::binary_search(i_common_cls.begin(), i_common_cls.end(), i_cas_latency); - - 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)); - - 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 true iff CL exceeds tAAmax, false otherwise -/// -inline bool cas_latency::is_cl_exceeding_taa_max(const uint64_t i_cas_latency, - const uint64_t i_tck) const -{ - // 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 ? %s", - mss::c_str(iv_target), - i_cas_latency, - i_tck, - i_cas_latency * i_tck, - l_taa_max, - l_is_cl_exceeding_taa ? "yes" : "no"); - - 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 deleted file mode 100644 index 9b5688756..000000000 --- a/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.H +++ /dev/null @@ -1,399 +0,0 @@ -/* IBM_PROLOG_BEGIN_TAG */ -/* This is an automatically generated prolog. */ -/* */ -/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.H $ */ -/* */ -/* OpenPOWER HostBoot Project */ -/* */ -/* Contributors Listed Below - COPYRIGHT 2016,2018 */ -/* [+] International Business Machines Corp. */ -/* */ -/* */ -/* Licensed under the Apache License, Version 2.0 (the "License"); */ -/* you may not use this file except in compliance with the License. */ -/* You may obtain a copy of the License at */ -/* */ -/* http://www.apache.org/licenses/LICENSE-2.0 */ -/* */ -/* Unless required by applicable law or agreed to in writing, software */ -/* distributed under the License is distributed on an "AS IS" BASIS, */ -/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ -/* implied. See the License for the specific language governing */ -/* permissions and limitations under the License. */ -/* */ -/* IBM_PROLOG_END_TAG */ - -/// -/// @file cas_latency.H -/// @brief CAS latency class declaration -/// -// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com> -// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com> -// *HWP Team: Memory -// *HWP Level: 3 -// *HWP Consumed by: HB:FSP - -#ifndef _MSS_CAS_LATENCY_H_ -#define _MSS_CAS_LATENCY_H_ - -// std lib -#include <map> -#include <memory> -#include <cstdint> - -// fapi2 -#include <fapi2.H> - -// mss lib -#include <generic/memory/lib/spd/spd_facade.H> -#include <lib/utils/mss_nimbus_conversions.H> -#include <lib/freq/sync.H> - -namespace mss -{ - - -// I choose enumerations over boolean because I feel -// it makes the interface clearer than could be depicted -// by 'true' and 'false' alone. -enum class loading : size_t -{ - NOT_3DS, - 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<uint32_t>::const_iterator search_list( const std::vector<uint32_t>& 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<uint32_t>::const_iterator search_list<BIN_DOWN>( const std::vector<uint32_t>& 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<uint32_t>::const_iterator search_list<HIGHEST_COMMON>( const std::vector<uint32_t>& - 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 -/// -class cas_latency -{ - public: - bool iv_dimm_list_empty; - - ///////////////////////// - // Public Member Methods - ///////////////////////// - - // Default constructor - // class dependent on SPD data obtained internally - // won't work when instantiated w/o neccesary params - 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 - /// @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<fapi2::TARGET_TYPE_MCA>& i_target_mcs, - const std::vector< spd::facade >& i_caches, - const std::vector<uint32_t>& i_supported_freqs, - fapi2::ReturnCode& o_rc); - - /// - /// @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<fapi2::TARGET_TYPE_MCA>& 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 uint8_t i_req_sync_mode = fapi2::ENUM_ATTR_REQUIRED_SYNCH_MODE_UNDETERMINED, - const std::vector<uint32_t>& i_supported_freqs = NIMBUS_SUPPORTED_FREQS); - - /// - /// @brief Default destructor - /// - ~cas_latency() = default; - - /// - /// @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 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<uint32_t>& 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<TT>(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 - { - // From JEDEC Standard No. 79-4A - // Speed Bins pg. 164 - /// Time in picoseconds - TAA_MAX_DDR4 = 18000, - - // From JEDEC Standard No. 79-4 3DS - // Speed Bins pg. 135 - /// Time in picoseconds - TAA_MAX_DDR4_3DS = 21500, - - // Low range CAS latency from SPD - LOW_RANGE_MIN_CL_DDR4 = 7, - LOW_RANGE_MAX_CL_DDR4 = 36, - - // High range CAS latency SPD - HIGH_RANGE_MIN_CL_DDR4 = 23, - HIGH_RANGE_MAX_CL_DDR4 = 52, - - CAS_LAT_RANGE_BIT = 31, - }; - - ///////////////////////// - // Private variables - ///////////////////////// - fapi2::Target<fapi2::TARGET_TYPE_MCA> iv_target; - uint64_t iv_largest_taamin;// cas latency time - uint64_t iv_proposed_tck;// cycle time - loading iv_is_3ds; - uint64_t iv_common_cl_bitmap; - bool iv_enable_freq_overrides; - std::vector<uint64_t> iv_common_cl; // common cas latency - uint8_t iv_req_sync_mode; - std::vector<uint32_t> iv_supported_freqs; - - /// - /// @brief Retrieves SDRAM Minimum CAS Latency Time (tAAmin) from SPD - /// @param[in] i_spd_decoder the SPD decoder - /// @param[out] o_value tCKmin value in ps - /// @return FAPI2_RC_SUCCESS iff ok - /// - fapi2::ReturnCode get_taamin(const mss::spd::facade& i_spd_decoder, - uint64_t& o_value); - - /// - /// @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 - /// - uint64_t get_max_cl(const fapi2::buffer<uint64_t> i_supported_cl) 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 - /// - uint64_t get_min_cl(const fapi2::buffer<uint64_t>& i_supported_cl) 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 - /// - fapi2::ReturnCode calc_cas_latency(const uint64_t i_taa, - const uint64_t i_tck, - uint64_t& o_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 - /// - std::vector<uint64_t> integral_bitmap_to_vector(const uint64_t i_bitmap) 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 true iff desired CL was found in the bitmap of common CLs, false otherwise - /// - bool is_cl_supported_in_common(const std::vector<uint64_t>& i_common_cls, - const uint64_t i_cas_latency) const; - - /// - /// @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 - /// - bool is_cl_exceeding_taa_max(const uint64_t i_cas_latency, - const uint64_t i_tck) const; - - /// - /// @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 - /// - template< freq_select TT > - inline fapi2::ReturnCode select_supported_freq(uint64_t& io_dimm_freq) - { - FAPI_TRY( (select_supported_freq_helper<TT>(iv_supported_freqs, io_dimm_freq)) ); - - fapi_try_exit: - return fapi2::current_err; - } - - /// - /// @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 - /// - 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) ); - - FAPI_TRY( (select_supported_freq<T>(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 - -#endif //_MSS_CAS_LATENCY_H_ 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 1a0ee8165..54a100e10 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 @@ -38,13 +38,14 @@ #include <algorithm> #include <vector> #include <map> -#include <mss.H> #include <lib/freq/sync.H> #include <generic/memory/lib/utils/find.H> #include <lib/utils/assert_noexit.H> #include <generic/memory/lib/utils/count_dimm.H> #include <generic/memory/lib/spd/spd_facade.H> #include <generic/memory/lib/spd/spd_utils.H> +#include <generic/memory/lib/utils/conversions.H> +#include <lib/mss_attribute_accessors.H> using fapi2::TARGET_TYPE_DIMM; using fapi2::TARGET_TYPE_MCS; 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 9161bdb39..c05d1cb8e 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 @@ -191,7 +191,6 @@ enum ffdc_function_codes GET_STARTING_WR_DQ_DELAY_VALUE = 95, SUPPORTED_FREQS = 99, - SELECT_SUPPORTED_FREQ = 100, // WR VREF functions DRAM_TO_RP_REG = 101, 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 15d956308..aa54ff774 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 @@ -46,7 +46,7 @@ // mss lib #include <generic/memory/lib/spd/spd_facade.H> -#include <lib/freq/cas_latency.H> +#include <generic/memory/lib/utils/freq/cas_latency.H> #include <lib/freq/sync.H> #include <lib/workarounds/freq_workarounds.H> #include <generic/memory/lib/utils/c_str.H> @@ -128,7 +128,7 @@ extern "C" FAPI_TRY( get_spd_decoder_list(l_mca, l_spd_facades) ); // Instantiation of class that calculates CL algorithm - mss::cas_latency l_cas_latency( l_mca, l_spd_facades, l_supported_freqs, l_rc ); + mss::cas_latency<mss::mc_type::NIMBUS> l_cas_latency( l_mca, l_spd_facades, l_supported_freqs, l_rc ); FAPI_TRY( l_rc, "%s. Failed to initialize cas_latency ctor", mss::c_str(l_mca) ); 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 0222c7b25..6a1651df2 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 @@ -55,127 +55,6 @@ </hwpError> <hwpError> - <rc>RC_MSS_INVALID_TIMING_VALUE</rc> - <description>Invalid value calculated for timing value based on MTB and FTB from SPD.</description> - <ffdc>VALUE</ffdc> - <ffdc>FUNCTION</ffdc> - <callout> - <target>DIMM_TARGET</target> - <priority>HIGH</priority> - </callout> - <deconfigure> - <target>DIMM_TARGET</target> - </deconfigure> - <gard> - <target>DIMM_TARGET</target> - </gard> - </hwpError> - - <hwpError> - <rc>RC_MSS_INVALID_CALCULATED_TCK</rc> - <description> - Invalid value clock period (less than equal 0). - Should be code bug and error comparing MRW and VPD SUPPRTED_FREQS - Caused by bad MRW values for MSS_MRW_SUPPORTED_FREQ - </description> - <ffdc>TAAMIN</ffdc> - <ffdc>PROPOSED_TCK</ffdc> - <ffdc>IS_3DS</ffdc> - <callout> - <procedure>CODE</procedure> - <priority>HIGH</priority> - </callout> - <callout> - <childTargets> - <parent>MCA_TARGET</parent> - <childType>TARGET_TYPE_DIMM</childType> - </childTargets> - <priority>MEDIUM</priority> - </callout> - </hwpError> - - <hwpError> - <rc>RC_MSS_NO_COMMON_SUPPORTED_CL</rc> - <description> - Current Configuration has no common supported CL values. - Caused by bad SPD on one of the plugged DIMMS - or DIMM configuration is not supported - </description> - <ffdc>CL_SUPPORTED</ffdc> - <callout> - <childTargets> - <parent>MCA_TARGET</parent> - <childType>TARGET_TYPE_DIMM</childType> - </childTargets> - <priority>HIGH</priority> - </callout> - <deconfigure> - <childTargets> - <parent>MCA_TARGET</parent> - <childType>TARGET_TYPE_DIMM</childType> - </childTargets> - </deconfigure> - <gard> - <childTargets> - <parent>MCA_TARGET</parent> - <childType>TARGET_TYPE_DIMM</childType> - </childTargets> - </gard> - </hwpError> - - <hwpError> - <rc>RC_MSS_FAILED_TO_FIND_SUPPORTED_CL</rc> - <description> - Desired CAS latency isn't supported in the common CAS latency bin retrieved from SPD. - </description> - <ffdc>DESIRED_CAS_LATENCY</ffdc> - <ffdc>COMMON_CLS</ffdc> - <ffdc>TAA</ffdc> - <ffdc>TCK</ffdc> - <callout> - <procedure>CODE</procedure> - <priority>HIGH</priority> - </callout> - <callout> - <childTargets> - <parent>MCA_TARGET</parent> - <childType>TARGET_TYPE_DIMM</childType> - </childTargets> - <priority>MEDIUM</priority> - </callout> - <deconfigure> - <childTargets> - <parent>MCA_TARGET</parent> - <childType>TARGET_TYPE_DIMM</childType> - </childTargets> - </deconfigure> - <gard> - <childTargets> - <parent>MCA_TARGET</parent> - <childType>TARGET_TYPE_DIMM</childType> - </childTargets> - </gard> - </hwpError> - - <hwpError> - <rc>RC_MSS_CL_EXCEEDS_TAA_MAX</rc> - <description> - Calculated Cas Latency exceeds JEDEC value for TAA Max - desired (and DIMM supported) cas_latency * proposed tck from mss freq attributes > jedec taa_max - Probably due to MRW/ VPD freqs being too high - </description> - <ffdc>CAS_LATENCY</ffdc> - <ffdc>TCK</ffdc> - <ffdc>TAA_MAX</ffdc> - <ffdc>COMPARE</ffdc> - <ffdc>IS_3DS</ffdc> - <callout> - <procedure>CODE</procedure> - <priority>HIGH</priority> - </callout> - </hwpError> - - <hwpError> <rc>RC_MSS_FREQ_NOT_EQUAL_NEST_FREQ</rc> <description> Case when mss_freq speeds are different and sync mode is required, @@ -472,27 +351,6 @@ </hwpError> <hwpError> - <rc>RC_MSS_SELECTED_FREQ_NOT_SUPPORTED</rc> - <description>Selected freq based on calculations from the DIMM and VPD is not supported</description> - <ffdc>SUPPORTED_FREQ_0</ffdc> - <ffdc>SUPPORTED_FREQ_1</ffdc> - <ffdc>SUPPORTED_FREQ_2</ffdc> - <ffdc>SUPPORTED_FREQ_3</ffdc> - <ffdc>FREQ</ffdc> - <callout> - <procedure>CODE</procedure> - <priority>HIGH</priority> - </callout> - <callout> - <childTargets> - <parent>TARGET</parent> - <childType>TARGET_TYPE_DIMM</childType> - </childTargets> - <priority>MEDIUM</priority> - </callout> - </hwpError> - - <hwpError> <rc>RC_MSS_FREQ_TO_NEST_FREQ_RATIO_TOO_LARGE</rc> <description> Case when mss_freq to nest freq is above the maximum allowed. 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 fc5d460eb..4460b4008 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 @@ -53,23 +53,6 @@ </deconfigure> </hwpError> - <hwpError> - <rc>RC_MSS_EMPTY_VECTOR</rc> - <description> - Empty vector conditional failed. - </description> - <ffdc>RECEIVED</ffdc> - <ffdc>FUNCTION</ffdc> - <callout> - <target>TARGET</target> - <priority>MEDIUM</priority> - </callout> - <callout> - <procedure>CODE</procedure> - <priority>LOW</priority> - </callout> - </hwpError> - <hwpError> <rc>RC_MSS_INVALID_RTT_WR_ENCODING</rc> <description> diff --git a/src/import/generic/memory/lib/utils/freq/cas_latency.C b/src/import/generic/memory/lib/utils/freq/cas_latency.C new file mode 100644 index 000000000..7ba2ddee9 --- /dev/null +++ b/src/import/generic/memory/lib/utils/freq/cas_latency.C @@ -0,0 +1,64 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/import/generic/memory/lib/utils/freq/cas_latency.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +/// +/// @file cas_latency.C +/// @brief CAS latency class implementation +/// +// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com> +// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 3 +// *HWP Consumed by: HB:FSP + +// std lib +#include <limits.h> +#include <algorithm> + +// fapi2 +#include <fapi2.H> + +// mss lib +#include <generic/memory/lib/utils/freq/cas_latency.H> + +namespace mss +{ + +const std::vector< uint32_t > CasLatencyTraits<mc_type::NIMBUS>::SUPPORTED_FREQS = +{ + DIMM_SPEED_1866, + DIMM_SPEED_2133, + DIMM_SPEED_2400, + DIMM_SPEED_2666, +}; + +const std::vector< uint32_t > CasLatencyTraits<mc_type::EXPLORER>::SUPPORTED_FREQS = +{ + DIMM_SPEED_2666, + DIMM_SPEED_2933, + DIMM_SPEED_3200, +}; + +}// mss diff --git a/src/import/generic/memory/lib/utils/freq/cas_latency.H b/src/import/generic/memory/lib/utils/freq/cas_latency.H new file mode 100644 index 000000000..83ae824c9 --- /dev/null +++ b/src/import/generic/memory/lib/utils/freq/cas_latency.H @@ -0,0 +1,785 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/import/generic/memory/lib/utils/freq/cas_latency.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +/// +/// @file cas_latency.H +/// @brief CAS latency class declaration +/// +// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com> +// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 3 +// *HWP Consumed by: HB:FSP + +#ifndef _MSS_CAS_LATENCY_H_ +#define _MSS_CAS_LATENCY_H_ + +// std lib +#include <map> +#include <memory> +#include <cstdint> + +// fapi2 +#include <fapi2.H> + +// mss generic lib +#include <generic/memory/lib/spd/spd_facade.H> +#include <generic/memory/lib/utils/conversions.H> +#include <generic/memory/lib/utils/shared/mss_generic_consts.H> +#include <generic/memory/lib/spd/spd_utils.H> + +namespace mss +{ + +// I choose enumerations over boolean because I feel +// it makes the interface clearer than could be depicted +// by 'true' and 'false' alone. +enum class loading : size_t +{ + NOT_3DS, + 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<uint32_t>::const_iterator search_list( const std::vector<uint32_t>& 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<uint32_t>::const_iterator search_list<BIN_DOWN>( const std::vector<uint32_t>& 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<uint32_t>::const_iterator search_list<HIGHEST_COMMON>( const std::vector<uint32_t>& + i_supported_freqs, + const uint32_t i_dimm_freq) +{ + return std::upper_bound(i_supported_freqs.begin(), i_supported_freqs.end(), i_dimm_freq); +} + +/// +/// @brief Traits based upon the memory controller type for allowed frequencies +/// @tparam MC Memory Controller type +/// @note Given that one target type can have multiple controllers associated with it (DIMM, OCMB, MEMPORT, etc) MC is used to differentiate the controller type rather than target type +/// We need to be able to distinguish between the MC types to determine the supported set of frequencies. We also use the MC type to derive what target type to use. +/// +template <mc_type MC> +class CasLatencyTraits +{}; + +/// +/// @brief Traits based upon the memory controller type for allowed frequencies - specialization for NIMBUS +/// +template <> +class CasLatencyTraits<mc_type::NIMBUS> +{ + public: + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::TARGET_TYPE_MCA; + static const std::vector<uint32_t> SUPPORTED_FREQS; + static constexpr const char* MC_STR = "NIMBUS"; +}; + +/// +/// @brief Traits based upon the memory controller type for allowed frequencies - specialization for EXPLORER +/// +template <> +class CasLatencyTraits<mc_type::EXPLORER> +{ + public: + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::TARGET_TYPE_OCMB_CHIP; + static const std::vector<uint32_t> SUPPORTED_FREQS; + static constexpr const char* MC_STR = "EXPLORER"; +}; + +/// +/// @class cas_latency +/// @brief CAS latency class that encapsulates JEDEC calculation algorithm +/// @tparam MC the memory controller type +/// @tparam TT the CasLatencyTraits - defaulted to be the traits associated with the MC +/// @note Using spd::c_str as the frequency isn't setup yet, and that might be required for c_str prints +/// +template<mss::mc_type MC, typename TT = CasLatencyTraits<MC>> +class cas_latency +{ + public: + bool iv_dimm_list_empty; + + ///////////////////////// + // Public Member Methods + ///////////////////////// + + // Default constructor + // class dependent on SPD data obtained internally + // won't work when instantiated w/o neccesary params + 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 + /// @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<TT::TARGET_TYPE>& i_target, + const std::vector< spd::facade >& i_caches, + const std::vector<uint32_t>& 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_bitmap(UINT64_MAX), + iv_supported_freqs(i_supported_freqs) + { + o_rc = fapi2::FAPI2_RC_SUCCESS; + + if( i_caches.empty() ) + { + FAPI_INF("cas latency ctor seeing no SPD caches for %s", mss::spd::c_str(i_target) ); + iv_dimm_list_empty = true; + return; + } + + for ( const auto& l_cache : i_caches ) + { + // Retrieve timing values from the SPD + const auto l_target = l_cache.get_dimm_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::spd::c_str(l_target) ); + FAPI_TRY( spd::get_tckmax(l_cache, l_tckmax_in_ps), + "%s. Failed to get tCKmax", mss::spd::c_str(l_target) ); + FAPI_TRY( spd::get_tckmin(l_cache, l_tck_min_in_ps), + "%s. Failed to get tCKmin", mss::spd::c_str(l_target) ); + + // Determine largest tAAmin value + iv_largest_taamin = std::max(iv_largest_taamin, l_taa_min_in_ps); + + // Determine a proposed tCK value that is greater than or equal tCKmin + // But less than tCKmax + iv_proposed_tck = std::max(iv_proposed_tck, l_tck_min_in_ps); + iv_proposed_tck = std::min(iv_proposed_tck, l_tckmax_in_ps); + + // Collecting stack type + // If I have at least one 3DS DIMM connected I have + // to use 3DS tAAmax of 21.5 ps versus 18 ps for non-3DS DDR4 + // iv_is_3ds isn't setup until below. how is this not a bug?? + // if( iv_is_3ds != loading::IS_3DS) + { + uint8_t l_stack_type = 0; + FAPI_TRY( l_cache.prim_sdram_signal_loading(l_stack_type) ); + + // Is there a more algorithmic efficient approach? - AAM + iv_is_3ds = (l_stack_type == fapi2::ENUM_ATTR_EFF_PRIM_STACK_TYPE_3DS) ? + loading::IS_3DS : loading::NOT_3DS; + } + + { + // 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::spd::c_str(l_target) ); + + // Bitwise ANDING the bitmap from all modules creates a bitmap w/a common CL + iv_common_cl_bitmap &= l_dimm_supported_cl; + } + }// caches + + // 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_bitmap != 0, + fapi2::MSS_FREQ_NO_COMMON_SUPPORTED_CL(). + set_MC_TYPE(MC). + set_CL_SUPPORTED(iv_common_cl_bitmap). + set_PORT_TARGET(iv_target), + "%s. MC type: %s No common CAS latencies (CL bitmap = 0)", + mss::spd::c_str(iv_target), TT::MC_STR ); + + 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::spd::c_str(iv_target)); + + iv_common_cl = integral_bitmap_to_vector(iv_common_cl_bitmap); + + fapi_try_exit: + o_rc = fapi2::current_err; + return; + }// ctor + + /// + /// @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_supported_freqs vector of supported frequencies - defaulted to the traits supported frequencies + /// + cas_latency(const fapi2::Target<TT::TARGET_TYPE>& 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 std::vector<uint32_t>& i_supported_freqs = TT::SUPPORTED_FREQS): + iv_dimm_list_empty(false), + iv_target(i_target), + iv_largest_taamin(i_taa_min), + iv_proposed_tck(i_tck_min), + iv_is_3ds(i_is_3ds), + iv_common_cl_bitmap(i_common_cl_mask), + iv_supported_freqs(i_supported_freqs) + { + const auto l_dimm_list = find_targets<fapi2::TARGET_TYPE_DIMM>(iv_target); + + if(l_dimm_list.empty()) + { + FAPI_INF("cas latency ctor seeing no DIMM on %s", mss::spd::c_str(iv_target)); + iv_dimm_list_empty = true; + } + + iv_common_cl = integral_bitmap_to_vector(iv_common_cl_bitmap); + } + + /// + /// @brief Default destructor + /// + ~cas_latency() = default; + + /// + /// @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 iff ok + /// + fapi2::ReturnCode find_cl(uint64_t& o_cas_latency, + uint64_t& o_tck) + { + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + // 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) + { + // If the inputted target 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; + } + + 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<HIGHEST_COMMON>(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<BIN_DOWN>(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::spd::c_str(iv_target) ); + + // Choose an actual CAS Latency (CLactual) that is greater than or equal to CLdesired + // and is supported by all modules on the memory channel + 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("%s Desired CL isn't supported by all DIMMs, choosing a higher tCK", mss::spd::c_str(iv_target)); + continue; + } + + // Once the calculation of CLactual is completed + // verify that this CAS Latency value does not exceed tAAmax. + 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_FREQ_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) + .set_PORT_TARGET(iv_target) + .set_MC_TYPE(MC), + "%s: mc_type: %s Calculated Cas Latency (CL %d * tCK %d) exceeds JEDEC value of tAAmax %d", + mss::spd::c_str(iv_target), TT::MC_STR, + 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_FREQ_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_PORT_TARGET(iv_target) + .set_MC_TYPE(MC), + "%s. mc_type %s Failed to find a common CAS latency supported among all modules" + "Desired %d, common CL's %016lx", + mss::spd::c_str(iv_target), + TT::MC_STR, + l_desired_cas_latency, + iv_common_cl_bitmap); + + // Update output values after all criteria is met + o_cas_latency = l_desired_cas_latency; + o_tck = iv_proposed_tck; + + fapi_try_exit: + return fapi2::current_err; + } + + /// + /// @brief Selects DIMM frequency to run based on supported system frequencies -- helper function for testing + /// @tparam F 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 + /// @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 F > + inline fapi2::ReturnCode select_supported_freq_helper( const std::vector<uint32_t>& 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::spd::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::spd::c_str(iv_target) ); + } + + FAPI_DBG("Input frequency %d for %s", io_dimm_freq, mss::spd::c_str(iv_target) ); + { + auto l_iterator = search_list<F>(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, 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_FREQ_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) + .set_MC_TYPE(MC), + "%s mc_type: %s Error finding selected freq (%d) from list", + mss::spd::c_str(iv_target), + TT::MC_STR, + 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::spd::c_str(iv_target) ); + } + + return fapi2::FAPI2_RC_SUCCESS; + + fapi_try_exit: + return fapi2::current_err; + } + + private: + + enum + { + // From JEDEC Standard No. 79-4A + // Speed Bins pg. 164 + /// Time in picoseconds + TAA_MAX_DDR4 = 18000, + + // From JEDEC Standard No. 79-4 3DS + // Speed Bins pg. 135 + /// Time in picoseconds + TAA_MAX_DDR4_3DS = 21500, + + // Low range CAS latency from SPD + LOW_RANGE_MIN_CL_DDR4 = 7, + LOW_RANGE_MAX_CL_DDR4 = 36, + + // High range CAS latency SPD + HIGH_RANGE_MIN_CL_DDR4 = 23, + HIGH_RANGE_MAX_CL_DDR4 = 52, + + CAS_LAT_RANGE_BIT = 31, + }; + + ///////////////////////// + // Private variables + ///////////////////////// + fapi2::Target<TT::TARGET_TYPE> iv_target; + uint64_t iv_largest_taamin;// cas latency time + uint64_t iv_proposed_tck;// cycle time + loading iv_is_3ds; + uint64_t iv_common_cl_bitmap; + bool iv_enable_freq_overrides; + std::vector<uint64_t> iv_common_cl; // common cas latency + std::vector<uint32_t> iv_supported_freqs; + + /// + /// @brief Retrieves SDRAM Minimum CAS Latency Time (tAAmin) from SPD + /// @param[in] i_spd_decoder the SPD decoder + /// @param[out] o_value tCKmin value in ps + /// @return FAPI2_RC_SUCCESS iff ok + /// + fapi2::ReturnCode get_taamin(const mss::spd::facade& i_spd_decoder, + 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_spd_decoder.get_dimm_target(); + + FAPI_TRY( get_timebases(i_spd_decoder, l_medium_timebase, l_fine_timebase), + "%s. Failed Failed get_timebases", mss::spd::c_str(l_target) ); + + FAPI_TRY( i_spd_decoder.min_taa(l_timing_mtb), + "%s. Failed min_taa()", mss::spd::c_str(l_target) ); + FAPI_TRY( i_spd_decoder.fine_offset_min_taa(l_timing_ftb), + "%s. Failed fine_offset_min_taa()", mss::spd::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_TAAMIN). + set_DIMM_TARGET(l_target), + "%s. tAAmin invalid (<= 0) : %d", + mss::spd::c_str(l_target), + l_temp); + + o_value = l_temp; + FAPI_INF( "%s. tAAmin (ps): %d", + mss::spd::c_str(l_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 + /// + uint64_t get_max_cl(const fapi2::buffer<uint64_t> i_supported_cl) const + { + // If the last of Byte 23 of the SPD is 1, this selects CL values + // in the High CL range (23 to 52) + + // If the last bit of Byte 23 of the SPD is 0, this selects CL values + // in the Low CL range (7 to 36) + //Assuming bitmap is right aligned + return i_supported_cl.getBit<CAS_LAT_RANGE_BIT>() ? HIGH_RANGE_MAX_CL_DDR4 : LOW_RANGE_MAX_CL_DDR4; + } + + /// + /// @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 + /// + uint64_t get_min_cl(const fapi2::buffer<uint64_t>& i_supported_cl) const + { + // If the last of Byte 23 of the SPD is 1, this selects CL values + // in the High CL range (23 to 52) + + // If the last bit of Byte 23 of the SPD is 0, this selects CL values + // in the Low CL range (7 to 36) + return i_supported_cl.getBit<CAS_LAT_RANGE_BIT>() ? HIGH_RANGE_MIN_CL_DDR4 : LOW_RANGE_MIN_CL_DDR4; + + } + + /// + /// @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 + /// + fapi2::ReturnCode calc_cas_latency(const uint64_t i_taa, + const uint64_t i_tck, + uint64_t& o_cas_latency) const + { + FAPI_TRY( spd::calc_nck(i_taa, i_tck, spd::INVERSE_DDR4_CORRECTION_FACTOR, o_cas_latency) ); + + FAPI_INF("%s. tAA (ps): %d, tCK (ps): %d, CL (nck): %d", + mss::spd::c_str(iv_target), + i_taa, + i_tck, + o_cas_latency); + + fapi_try_exit: + return fapi2::current_err; + } + + /// + /// @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<uint64_t> integral_bitmap_to_vector(const uint64_t i_common_cl) const + { + std::vector<uint64_t> l_vector; + fapi2::buffer<uint64_t> l_cl_mask(i_common_cl); + + 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::spd::c_str(iv_target), l_min_cl); + FAPI_INF("%s. max CL %lu", mss::spd::c_str(iv_target), l_max_cl); + + 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 - l_min_cl); + + // Traversing through buffer one bit at a time + // 0 means unsupported CAS latency + // 1 means supported CAS latency + // We are pushing supported CAS latencies into a vector for direct use + 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 (0x%llX)", + mss::spd::c_str(iv_target), l_cas_latency, i_common_cl ); + + l_vector.push_back(l_cas_latency); + } + } + + return l_vector; + } + + /// + /// @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 + /// + bool is_cl_supported_in_common(const std::vector<uint64_t>& i_common_cls, + const uint64_t i_cas_latency) const + { + const bool l_found = std::binary_search(i_common_cls.begin(), i_common_cls.end(), i_cas_latency); + + 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::spd::c_str(iv_target)); + + 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 true iff CL exceeds tAAmax, false otherwise + /// + bool is_cl_exceeding_taa_max(const uint64_t i_cas_latency, + const uint64_t i_tck) const + { + // JEDEC SPD spec requirement + const auto l_cas_latency_time = i_cas_latency * i_tck; + 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 = l_cas_latency_time > l_taa_max; + + FAPI_INF("%s. CL (%d) * tCK (%d) = %d > %d ? %s", + mss::spd::c_str(iv_target), + i_cas_latency, + i_tck, + l_cas_latency_time, + l_taa_max, + l_is_cl_exceeding_taa ? "yes" : "no"); + + return l_is_cl_exceeding_taa; + } + + /// + /// @brief Selects DIMM frequency to run based on supported system frequencies + /// @tparam F 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 + /// + template< freq_select F > + inline fapi2::ReturnCode select_supported_freq(uint64_t& io_dimm_freq) + { + FAPI_TRY( (select_supported_freq_helper<F>(iv_supported_freqs, io_dimm_freq)) ); + + fapi_try_exit: + return fapi2::current_err; + } + + /// + /// @brief Limits tCK to system constraints (VPD and MRW) + /// @tparam F 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 + /// + template< freq_select F > + 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) ); + + FAPI_TRY( (select_supported_freq<F>(l_proposed_freq)), + "%s. Failed select_supported_freq()", mss::spd::c_str(iv_target) ); + + FAPI_TRY( freq_to_ps(l_proposed_freq, io_tck), + "%s. Failed freq_to_ps()", mss::spd::c_str(iv_target) ); + + FAPI_INF("%s Supported dimm speed override %d MT/s (Clock period %d in ps)", + mss::spd::c_str(iv_target), l_proposed_freq, io_tck); + + // Sanity check + FAPI_ASSERT(io_tck > 0, + fapi2::MSS_FREQ_INVALID_CALCULATED_TCK() + .set_TAAMIN(iv_largest_taamin) + .set_PROPOSED_TCK(io_tck) + .set_IS_3DS(iv_is_3ds) + .set_PORT_TARGET(iv_target) + .set_MC_TYPE(MC), + "%s. mc_type: %s Invalid calculated clock period(<= 0 nCK) : %d", + mss::spd::c_str(iv_target), + TT::MC_STR, + io_tck); + + fapi_try_exit: + return fapi2::current_err; + } + +};// cas_latency + +}// mss + +#endif //_MSS_CAS_LATENCY_H_ diff --git a/src/import/generic/memory/lib/utils/shared/mss_generic_consts.H b/src/import/generic/memory/lib/utils/shared/mss_generic_consts.H index 1710a6181..adc56d990 100644 --- a/src/import/generic/memory/lib/utils/shared/mss_generic_consts.H +++ b/src/import/generic/memory/lib/utils/shared/mss_generic_consts.H @@ -117,6 +117,8 @@ enum generic_ffdc_codes BASE_MODULE_TYPE = 0x101C, BAD_SPD_DATA = 0x101D, SET_FIELD = 0x101E, + + SELECT_SUPPORTED_FREQ = 0x101F, }; /// @@ -133,9 +135,9 @@ enum proc_type /// enum class mc_type { - NIMBUS, - CENTAUR, - EXPLORER, + NIMBUS = 0, + CENTAUR = 1, + EXPLORER = 2, }; /// diff --git a/src/import/generic/procedures/xml/error_info/generic_error.xml b/src/import/generic/procedures/xml/error_info/generic_error.xml index 34aacaa28..57b6685c9 100644 --- a/src/import/generic/procedures/xml/error_info/generic_error.xml +++ b/src/import/generic/procedures/xml/error_info/generic_error.xml @@ -37,12 +37,166 @@ <hwpErrors> + <hwpError> + <rc>RC_MSS_EMPTY_VECTOR</rc> + <description> + Empty vector conditional failed. + </description> + <ffdc>RECEIVED</ffdc> + <ffdc>FUNCTION</ffdc> + <callout> + <target>TARGET</target> + <priority>MEDIUM</priority> + </callout> + <callout> + <procedure>CODE</procedure> + <priority>LOW</priority> + </callout> + </hwpError> + + <hwpError> + <rc>RC_MSS_FREQ_CL_EXCEEDS_TAA_MAX</rc> + <description> + Calculated Cas Latency exceeds JEDEC value for TAA Max + desired (and DIMM supported) cas_latency * proposed tck from mss freq attributes > jedec taa_max + Probably due to MRW/ VPD freqs being too high + </description> + <ffdc>CAS_LATENCY</ffdc> + <ffdc>TCK</ffdc> + <ffdc>TAA_MAX</ffdc> + <ffdc>COMPARE</ffdc> + <ffdc>IS_3DS</ffdc> + <ffdc>MC_TYPE</ffdc> + <callout> + <procedure>CODE</procedure> + <priority>HIGH</priority> + </callout> + <callout> + <childTargets> + <parent>PORT_TARGET</parent> + <childType>TARGET_TYPE_DIMM</childType> + </childTargets> + <priority>LOW</priority> + </callout> + </hwpError> + + <hwpError> + <rc>RC_MSS_FREQ_FAILED_TO_FIND_SUPPORTED_CL</rc> + <description> + Desired CAS latency isn't supported in the common CAS latency bin retrieved from SPD. + </description> + <ffdc>DESIRED_CAS_LATENCY</ffdc> + <ffdc>COMMON_CLS</ffdc> + <ffdc>TAA</ffdc> + <ffdc>TCK</ffdc> + <ffdc>MC_TYPE</ffdc> + <callout> + <procedure>CODE</procedure> + <priority>HIGH</priority> + </callout> + <callout> + <childTargets> + <parent>PORT_TARGET</parent> + <childType>TARGET_TYPE_DIMM</childType> + </childTargets> + <priority>MEDIUM</priority> + </callout> + <deconfigure> + <childTargets> + <parent>PORT_TARGET</parent> + <childType>TARGET_TYPE_DIMM</childType> + </childTargets> + </deconfigure> + <gard> + <childTargets> + <parent>PORT_TARGET</parent> + <childType>TARGET_TYPE_DIMM</childType> + </childTargets> + </gard> + </hwpError> + + <hwpError> + <rc>RC_MSS_FREQ_INVALID_CALCULATED_TCK</rc> + <description> + Invalid value clock period (less than equal 0). + Should be code bug and error comparing MRW and VPD SUPPRTED_FREQS + Caused by bad MRW values for MSS_MRW_SUPPORTED_FREQ + </description> + <ffdc>TAAMIN</ffdc> + <ffdc>PROPOSED_TCK</ffdc> + <ffdc>IS_3DS</ffdc> + <ffdc>MC_TYPE</ffdc> + <callout> + <procedure>CODE</procedure> + <priority>HIGH</priority> + </callout> + <callout> + <childTargets> + <parent>PORT_TARGET</parent> + <childType>TARGET_TYPE_DIMM</childType> + </childTargets> + <priority>MEDIUM</priority> + </callout> + </hwpError> + + <hwpError> + <rc>RC_MSS_FREQ_NO_COMMON_SUPPORTED_CL</rc> + <description> + Current Configuration has no common supported CL values. + Caused by bad SPD on one of the plugged DIMMS + or DIMM configuration is not supported + </description> + <ffdc>MC_TYPE</ffdc> + <ffdc>CL_SUPPORTED</ffdc> + <callout> + <childTargets> + <parent>PORT_TARGET</parent> + <childType>TARGET_TYPE_DIMM</childType> + </childTargets> + <priority>HIGH</priority> + </callout> + <deconfigure> + <childTargets> + <parent>PORT_TARGET</parent> + <childType>TARGET_TYPE_DIMM</childType> + </childTargets> + </deconfigure> + <gard> + <childTargets> + <parent>PORT_TARGET</parent> + <childType>TARGET_TYPE_DIMM</childType> + </childTargets> + </gard> + </hwpError> + + <hwpError> + <rc>RC_MSS_FREQ_SELECTED_FREQ_NOT_SUPPORTED</rc> + <description>Selected freq based on calculations from the DIMM and VPD is not supported</description> + <ffdc>SUPPORTED_FREQ_0</ffdc> + <ffdc>SUPPORTED_FREQ_1</ffdc> + <ffdc>SUPPORTED_FREQ_2</ffdc> + <ffdc>SUPPORTED_FREQ_3</ffdc> + <ffdc>FREQ</ffdc> + <ffdc>MC_TYPE</ffdc> + <callout> + <procedure>CODE</procedure> + <priority>HIGH</priority> + </callout> + <callout> + <childTargets> + <parent>TARGET</parent> + <childType>TARGET_TYPE_DIMM</childType> + </childTargets> + <priority>MEDIUM</priority> + </callout> + </hwpError> + <hwpError> - <rc>RC_MSS_INVALID_FREQUENCY</rc> + <rc>RC_MSS_INVALID_CLOCK_PERIOD</rc> <description> - An invalid frequency was passed to frequency to clock period + An invalid clock period was passed to clock period to frequency </description> - <ffdc>FREQ</ffdc> + <ffdc>CLOCK_PERIOD</ffdc> <callout> <procedure>CODE</procedure> <priority>HIGH</priority> @@ -50,15 +204,32 @@ </hwpError> <hwpError> - <rc>RC_MSS_INVALID_CLOCK_PERIOD</rc> + <rc>RC_MSS_INVALID_FREQUENCY</rc> <description> - An invalid clock period was passed to clock period to frequency + An invalid frequency was passed to frequency to clock period </description> - <ffdc>CLOCK_PERIOD</ffdc> + <ffdc>FREQ</ffdc> <callout> <procedure>CODE</procedure> <priority>HIGH</priority> </callout> </hwpError> + <hwpError> + <rc>RC_MSS_INVALID_TIMING_VALUE</rc> + <description>Invalid value calculated for timing value based on MTB and FTB from SPD.</description> + <ffdc>VALUE</ffdc> + <ffdc>FUNCTION</ffdc> + <callout> + <target>DIMM_TARGET</target> + <priority>HIGH</priority> + </callout> + <deconfigure> + <target>DIMM_TARGET</target> + </deconfigure> + <gard> + <target>DIMM_TARGET</target> + </gard> + </hwpError> + </hwpErrors> diff --git a/src/usr/isteps/mss/makefile b/src/usr/isteps/mss/makefile index ff39a7404..24dd0062b 100644 --- a/src/usr/isteps/mss/makefile +++ b/src/usr/isteps/mss/makefile @@ -58,6 +58,7 @@ MSS_LIB += ${ROOTPATH}/src/import/generic/memory/lib/spd/common/ddr4/ MSS_LIB += ${ROOTPATH}/src/import/generic/memory/lib/spd/ MSS_LIB += ${ROOTPATH}/src/import/generic/memory/lib/utils/ MSS_LIB += ${ROOTPATH}/src/import/generic/memory/lib/utils/shared/ +MSS_LIB += ${ROOTPATH}/src/import/generic/memory/lib/utils/freq/ EXTRAINCDIR += ${MSS_LIB} |