diff options
author | Louis Stermole <stermole@us.ibm.com> | 2019-06-07 15:44:22 -0400 |
---|---|---|
committer | Christian R. Geddes <crgeddes@us.ibm.com> | 2019-07-09 10:18:24 -0500 |
commit | d9bbcfabbc2f041ba85095ac70dc27c37cb87755 (patch) | |
tree | 7d1270c8dc0939956034a7ab1f6cddb45a33ac72 | |
parent | 491995a6a3ed6062169c2818c89db7a85da9e448 (diff) | |
download | talos-hostboot-d9bbcfabbc2f041ba85095ac70dc27c37cb87755.tar.gz talos-hostboot-d9bbcfabbc2f041ba85095ac70dc27c37cb87755.zip |
Add missing timing attrs to p9a_eff_config
Change-Id: I0270bec76fa1146c3c74cc125f838f5602b8a5b8
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/78564
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com>
Tested-by: HWSV CI <hwsv-ci+hostboot@us.ibm.com>
Reviewed-by: STEPHEN GLANCY <sglancy@us.ibm.com>
Reviewed-by: Mark Pizzutillo <mark.pizzutillo@ibm.com>
Reviewed-by: Jennifer A Stofer <stofer@us.ibm.com>
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/78576
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
10 files changed, 2529 insertions, 967 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/eff_dimm.C b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/eff_dimm.C index baac38c30..74e3182ee 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/eff_dimm.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/eff_dimm.C @@ -366,16 +366,6 @@ enum invalid_freq_function_encoding : uint8_t F0BC6X = 0x60, }; -/// -/// @brief encoding for MSS_INVALID_TIMING so we can look up functions based on encoding -/// -enum invalid_timing_function_encoding : uint8_t -{ - TRRD_S = 0, - TRRD_L = 1, - TFAW = 2, -}; - ///////////////////////// // Non-member function implementations ///////////////////////// @@ -4098,7 +4088,7 @@ fapi2::ReturnCode eff_dimm::dram_trrd_s() l_trrd_s_in_nck); } - FAPI_TRY( trrd_s( iv_dimm, iv_dram_width, l_jedec_trrd) ); + FAPI_TRY( trrd_s( iv_dimm, iv_dram_width, iv_freq, l_jedec_trrd) ); // Taking the worst case between the required minimum JEDEC value and the proposed value from SPD if (l_jedec_trrd != l_trrd_s_in_nck) @@ -4174,7 +4164,7 @@ fapi2::ReturnCode eff_dimm::dram_trrd_l() l_trrd_l_in_nck); } - FAPI_TRY( trrd_l( iv_dimm, iv_dram_width, l_jedec_trrd) ); + FAPI_TRY( trrd_l( iv_dimm, iv_dram_width, iv_freq, l_jedec_trrd) ); // Taking the worst case between the required minimum JEDEC value and the proposed value from SPD if (l_jedec_trrd != l_trrd_l_in_nck) @@ -4273,7 +4263,7 @@ fapi2::ReturnCode eff_dimm::dram_tfaw() l_tfaw_in_nck); } - FAPI_TRY( mss::tfaw(iv_dimm, iv_dram_width, l_jedec_tfaw_in_nck), "Failed tfaw()" ); + FAPI_TRY( mss::tfaw(iv_dimm, iv_dram_width, iv_freq, l_jedec_tfaw_in_nck), "Failed tfaw()" ); // Taking the worst case between the required minimum JEDEC value and the proposed value from SPD if (l_jedec_tfaw_in_nck != l_tfaw_in_nck) @@ -4342,11 +4332,15 @@ fapi2::ReturnCode eff_dimm::dram_tras() // which will give the best timing value for the dimm // (like 2400 MT/s) which may be different than the system // speed (if we were being limited by VPD or MRW restrictions) - const uint64_t l_tras_in_ps = mss::tras(iv_dimm); + uint64_t l_tras_in_ps; + uint64_t l_freq = 0; + uint8_t l_tras_in_nck = 0; // Calculate nck std::vector<uint8_t> l_attrs_dram_tras(PORTS_PER_MCS, 0); - uint8_t l_tras_in_nck = 0; + + FAPI_TRY( freq(mss::find_target<fapi2::TARGET_TYPE_MCBIST>(iv_dimm), l_freq) ); + l_tras_in_ps = mss::tras(iv_dimm, l_freq); // Cast needed for calculations to be done on the same integral type // as required by template deduction. We have iv_tCK_in_ps as a signed diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.C b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.C index ebc203f2e..1f2920c7b 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -37,167 +37,4 @@ namespace mss { -enum temp_mode : uint8_t -{ - NORMAL = 1, - EXTENDED = 2, -}; - -// Proposed DDR4 Full spec update(79-4B) -// Item No. 1716.78C -// pg.46 -// Table 24 - tREFI and tRFC parameters (in ps) -constexpr uint64_t TREFI_BASE = 7800000; - -// Proposed DDR4 3DS Addendum -// Item No. 1727.58A -// pg. 69 - 71 -// Table 42 - Refresh parameters by logical rank density -static const std::vector<std::pair<uint8_t, uint64_t> > TRFC_DLR1 = -{ - // { density in GBs, tRFC4(min) in picoseconds } - {4, 90000}, - {8, 120000}, - {16, 185000}, -}; - -// Proposed DDR4 3DS Addendum -// Item No. 1727.58A -// pg. 69 - 71 -// Table 42 - Refresh parameters by logical rank density -static const std::vector<std::pair<uint8_t, uint64_t> > TRFC_DLR2 = -{ - // { density in GBs, tRFC4(min) in picoseconds } - {4, 55000}, - {8, 90000}, - {16, 120000}, -}; - -// Proposed DDR4 3DS Addendum -// Item No. 1727.58A -// pg. 69 - 71 -// Table 42 - Refresh parameters by logical rank density -static const std::vector<std::pair<uint8_t, uint64_t> > TRFC_DLR4 = -{ - // { density in GBs, tRFC4(min) in picoseconds } - {4, 40000}, - {8, 55000}, - {16, 90000}, -}; - -/// -/// @brief Calculates refresh interval time -/// @param[in] i_mode fine refresh rate mode -/// @param[in] i_refresh_request_rate refresh rate -/// @param[out] o_value timing val in ps -/// @return fapi2::ReturnCode -/// -fapi2::ReturnCode calc_trefi( const refresh_rate i_mode, - const uint8_t i_refresh_request_rate, - uint64_t& o_timing ) -{ - uint64_t l_refresh_request = 0; - constexpr double TEN_PERCENT_FASTER = 0.90; - - switch(i_refresh_request_rate) - { - case fapi2::ENUM_ATTR_MSS_MRW_REFRESH_RATE_REQUEST_SINGLE: - l_refresh_request = TREFI_BASE; - break; - - case fapi2::ENUM_ATTR_MSS_MRW_REFRESH_RATE_REQUEST_DOUBLE: - // We are truncating but there is no remainder with TREFI_BASE, so we are okay - l_refresh_request = TREFI_BASE / 2; - break; - - case fapi2::ENUM_ATTR_MSS_MRW_REFRESH_RATE_REQUEST_SINGLE_10_PERCENT_FASTER: - // We are truncating but there is no remainder with TREFI_BASE, so we are okay - // 10% faster so 100% - 10% = 90% - l_refresh_request = TREFI_BASE * TEN_PERCENT_FASTER; - break; - - case fapi2::ENUM_ATTR_MSS_MRW_REFRESH_RATE_REQUEST_DOUBLE_10_PERCENT_FASTER: - // We are truncating but there is no remainder with TREFI_BASE, so we are okay - // 10% faster so 100% - 10% = 90% - l_refresh_request = (TREFI_BASE / 2) * TEN_PERCENT_FASTER; - break; - - default: - // Will catch incorrect MRW value set - FAPI_ASSERT(false, - fapi2::MSS_INVALID_REFRESH_RATE_REQUEST().set_REFRESH_RATE_REQUEST(i_refresh_request_rate), - "Incorrect refresh request rate received: %d ", i_refresh_request_rate); - break; - } - - o_timing = (l_refresh_request / i_mode); - - FAPI_INF( "tREFI (ps): %d, refresh request (ps): %d, tREFI_base (ps): %d, REF%dX", - o_timing, l_refresh_request, TREFI_BASE, i_mode ); - - // FAPI_ASSERT doesn't set current_err as good - return fapi2::FAPI2_RC_SUCCESS; - -fapi_try_exit: - return fapi2::current_err; -} - -/// @brief Calculates Minimum Refresh Recovery Delay Time (different logical rank) -/// @param[in] i_mode fine refresh rate mode -/// @param[in] i_density SDRAM density -/// @param[out] o_trfc_in_ps timing val in ps -/// @return fapi2::FAPI2_RC_SUCCESS iff okay -/// -fapi2::ReturnCode calc_trfc_dlr(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, - const uint8_t i_refresh_mode, - const uint8_t i_density, - uint64_t& o_trfc_in_ps) -{ - bool l_is_val_found = 0; - - // Selects appropriate tRFC based on fine refresh mode - switch(i_refresh_mode) - { - case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_NORMAL: - l_is_val_found = find_value_from_key(TRFC_DLR1, i_density, o_trfc_in_ps); - break; - - case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_2X: - case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_2X: - l_is_val_found = find_value_from_key(TRFC_DLR2, i_density, o_trfc_in_ps); - break; - - case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_4X: - case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_4X: - l_is_val_found = find_value_from_key(TRFC_DLR4, i_density, o_trfc_in_ps); - break; - - default: - // Fine Refresh Mode will be a platform attribute set by the MRW, - // which they "shouldn't" mess up as long as use "attribute" enums. - // if openpower messes this up we can at least catch it - FAPI_ASSERT( false, - fapi2::MSS_INVALID_FINE_REFRESH() - .set_REFRESH_MODE(i_refresh_mode), - "Incorrect Fine Refresh Mode received: %d ", - i_refresh_mode); - break; - }// switch - - FAPI_ASSERT( l_is_val_found, - fapi2::MSS_FAILED_TO_FIND_TRFC() - .set_SDRAM_DENSITY(i_density) - .set_REFRESH_MODE(i_refresh_mode) - .set_DIMM_TARGET(i_target), - "%s: Unable to find tRFC (ps) from map with SDRAM density key %d with %d refresh mode", - mss::c_str(i_target), - i_density, - i_refresh_mode); - - // Again, FAPI_ASSERT doesn't set current_err to good, only to bad - return fapi2::FAPI2_RC_SUCCESS; -fapi_try_exit: - return fapi2::current_err; -} - }// mss diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H index 8b8215b96..d748400cb 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H @@ -40,104 +40,13 @@ #include <lib/mss_attribute_accessors.H> #include <generic/memory/lib/utils/find.H> #include <generic/memory/lib/utils/shared/mss_generic_consts.H> +#include <generic/memory/lib/utils/dimm/mss_timing.H> #include <lib/utils/mss_nimbus_conversions.H> namespace mss { /// -/// @brief Enums for ffdc error callout so we know which function had the error -/// -enum functions -{ - TRAS = 0, - TFAW_HALF_KB_PAGE_HELPER = 1, - TFAW_ONE_KB_PAGE_HELPER = 2, - TFAW_TW_KB_PAGE_HELPER = 3, - TFAW_SLR_X4_HELPER = 4, - TFAW_SLR_X8_HELPER = 5, - TRRD_S_SLR = 6, - TRRD_L_SLR = 7, - TRRD_L_HALF_AND_1KB_PAGE_HELPER = 8, - TRRD_S_HALF_AND_1KB_PAGE_HELPER = 9, - TRRD_S_2KB_PAGE_HELPER = 10, - TDLLK = 11, -}; - -enum refresh_rate : uint8_t -{ - REF1X = 1, ///< Refresh rate 1X - REF2X = 2, ///< Refresh rate 2X - REF4X = 4, ///< Refresh rate 4X -}; - -namespace spd -{ - -/// -/// @brief Returns clock cycles form picoseconds based on speed bin -/// Uses SPD rounding algorithm for DDR4 -/// @tparam T the target type from which to get the mt/s -/// @tparam OT the output type, derrived from the parameters -/// @param[in] i_target target for the frequency attribute -/// @param[in] timing_in_ps timing parameter in ps -/// @return the clock cycles of timing parameter (provided in ps) -/// @note Uses DDR4 SPD Contents Rounding Algorithm -/// @note Item 2220.46 -/// -template<fapi2::TargetType T, typename OT> -inline OT ps_to_nck( const fapi2::Target<T>& i_target, const OT& i_timing_in_ps) -{ - uint64_t l_freq = 0; - OT l_tck_in_ps = 0; - OT l_temp_nck = 0; - - FAPI_TRY( mss::freq( find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq) ); - - // No time if MT/s is 0 (well, infinite really but shut up) - if (l_freq == 0) - { - return 0; - } - - FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), - "Failed freq() accessor" ); - FAPI_TRY( calc_nck(i_timing_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_temp_nck), - "Failed calc_nck()" ); - - return l_temp_nck; - -fapi_try_exit: - // We simply can't work if we can't get the frequency or - // if we get an unsupported value that can't be converted to a valid tCK (clock period) - // ...so this should be ok - FAPI_ERR("Can't get MSS_FREQ, obtained an invalid MSS_FREQ (%d), or overflow occurred - stopping", l_freq); - fapi2::Assert(false); - - // Keeps compiler happy - return 0; -} - -/// -/// @brief Returns clock cycles from nanoseconds -/// Uses SPD rounding algorithm for DDR4 -/// @tparam T the target type from which to get the mt/s -/// @tparam OT the output type, derrived from the parameters -/// @param[in] timing_in_ps timing parameter in ps -/// @param[out] o_value_nck the end calculation in nck -/// @return the clock cycles of timing parameter (provided in ps)F -/// @note Uses DDR4 SPD Contents Rounding Algorithm -/// @note Item 2220.46 -/// -template<fapi2::TargetType T, typename OT> -inline OT ns_to_nck( const fapi2::Target<T>& i_target, const OT& i_timing_in_ns) -{ - return ps_to_nck(i_target, i_timing_in_ns * CONVERT_PS_IN_A_NS); -} - -}// spd - -/// /// @brief Returns application clock period (tCK) based on dimm transfer rate /// @tparam T the fapi2 target /// @tparam OT output type @@ -159,30 +68,6 @@ fapi_try_exit: } /// -/// @brief Calculates refresh interval time -/// @param[in] i_mode fine refresh rate mode -/// @param[in] i_temp_refresh_range temperature refresh range -/// @param[out] o_value timing val in ps -/// @return fapi2::ReturnCode -/// -fapi2::ReturnCode calc_trefi( const refresh_rate i_mode, - const uint8_t i_temp_refresh_range, - uint64_t& o_timing ); - -/// -/// @brief Calculates Minimum Refresh Recovery Delay Time (different logical rank) -/// @param[in] i_target a target for attributes -/// @param[in] i_mode fine refresh rate mode -/// @param[in] i_density SDRAM density -/// @param[out] o_trfc_in_ps timing val in ps -/// @return fapi2::FAPI2_RC_SUCCESS iff okay -/// -fapi2::ReturnCode calc_trfc_dlr( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, - const uint8_t i_refresh_mode, - const uint8_t i_density, - uint64_t& o_trfc_in_ps ); - -/// /// @brief DLL locking time *in clocks* /// @tparam T the fapi2::TargetType of i_target /// @tparam OT the type of the output location @@ -582,602 +467,6 @@ fapi_try_exit: } /// -/// @brief tRTP *in ps* -/// @return constexpr value of RTP = 7500 ps -/// -constexpr uint64_t trtp() -{ - // Per JEDEC spec, defaults to 7500 ps for all frequencies. - // (technically max of 7.5 ns or 4 nclk, which is always 7.5ns for DDR4) - return 7500; -} - -/// -/// @brief Return the minimum allowable tRAS in picoseconds -/// @param[in] i_target the fapi2 target -/// @return value in picoseconds -/// -inline uint64_t tras(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target) -{ - uint64_t l_freq = 0; - uint64_t l_tras = 0; - - // Frequency is used to determine tRAS - FAPI_TRY( freq(mss::find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq) ); - - switch(l_freq) - { - case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: - l_tras = 34000; - break; - - case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: - l_tras = 33000; - break; - - case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: - case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: - l_tras = 32000; - break; - - default: - FAPI_ASSERT( false, - fapi2::MSS_INVALID_FREQ_PASSED_IN() - .set_FREQ(l_freq) - .set_FUNCTION(TRAS) - .set_DIMM_TARGET(i_target), - "%s Invalid frequency %lu", - mss::c_str(i_target), - l_freq); - } - - return l_tras; - -fapi_try_exit: - - // We simply can't work if we can't get the frequency or - // if we get an unsupported value that can't be converted to a valid tCK (clock period) - // ...so this should be ok - FAPI_ERR("Can't get MSS_FREQ or obtained an invalid MSS_FREQ (%d) - stopping", l_freq); - fapi2::Assert(false); - - // Keeps compiler happy - return 0; -} - -/// -/// @brief Helper function to find tFAW based speed (MT/s) for 1/2 KB page -/// @tparam T the fapi2::TargetType of a type from which we can get MT/s -/// @param[in] i_target the fapi2 target -/// @param[out] o_output timing in clocks (nck) -/// @return FAPI2_RC_SUCCESS iff okay -/// @note this is only for non-3DS DIMM -/// -template< fapi2::TargetType T > -static fapi2::ReturnCode tfaw_half_kb_page_helper(const fapi2::Target<T>& i_target, - uint64_t& o_output) -{ - // Values derived from DDR4 Spec (79-4A) - // 13.3 Timing Parameters by Speed Grade - // Table 132. Pg 240 - fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; - - uint64_t l_freq = 0; - FAPI_TRY( freq(find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq), - "Failed to invoke freq accessor" ); - - // It could have been more "efficient" to hand-calculate the answer and - // use compile time constants to return the answer. To avoid magic - // numbers and to align (more closely) with the DDR4 JEDEC spec, - // we let the std library do the work for us for maintainability. - // Could have used compile-time constants to denote the numbers below - // but they are "random" and vary. - switch(l_freq) - { - // static_cast is needed for template deduction of std::max API - case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: - o_output = std::max( 16, spd::ns_to_nck(i_target, 17) ); - break; - - case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: - o_output = std::max( 16, spd::ns_to_nck(i_target, 15) ); - break; - - case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: - o_output = std::max( 16, spd::ns_to_nck(i_target, 13) ); - break; - - case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: - o_output = std::max( 16, spd::ns_to_nck(i_target, 12) ); - break; - - default: - FAPI_ASSERT( false, - fapi2::MSS_INVALID_FREQ_PASSED_IN() - .set_FREQ(l_freq) - .set_FUNCTION(TFAW_HALF_KB_PAGE_HELPER) - .set_DIMM_TARGET(i_target), - "%s Invalid frequency %lu", - mss::c_str(i_target), - l_freq); - } - -fapi_try_exit: - return fapi2::current_err; -} - -/// -/// @brief Helper function to find tFAW based speed (MT/s) for 1KB page -/// @tparam T the fapi2::TargetType of a type from which we can get MT/s -/// @param[in] i_target the fapi2 target -/// @param[out] o_output timing in clocks (nck) -/// @return FAPI2_RC_SUCCESS iff okay -/// @note this is only for non-3DS DIMM -/// -template< fapi2::TargetType T > -static fapi2::ReturnCode tfaw_1kb_page_helper(const fapi2::Target<T>& i_target, - uint64_t& o_output) -{ - // Values derived from DDR4 Spec (79-4A) - // 13.3 Timing Parameters by Speed Grade - // Table 132. Pg 240 - fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; - - uint64_t l_freq = 0; - FAPI_TRY( freq(find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq), - "Failed to invoke freq accessor" ); - - // It could have been more "efficient" to hand-calculate the answer and - // use compile time constants to return the answer. To avoid magic - // numbers and to align (more closely) with the DDR4 JEDEC spec, - // we let the std library do the work for us for maintainability (and ease of debug?). - // Could have used compile-time constants to denote the numbers below - // but they are "random" and vary. - switch(l_freq) - { - case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: - o_output = std::max( 20, spd::ns_to_nck(i_target, 23) ); - break; - - case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: - case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: - case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: - o_output = std::max( 20, spd::ns_to_nck(i_target, 21) ); - break; - - default: - FAPI_ASSERT( false, - fapi2::MSS_INVALID_FREQ_PASSED_IN() - .set_FREQ(l_freq) - .set_FUNCTION(TFAW_ONE_KB_PAGE_HELPER) - .set_DIMM_TARGET(i_target), - "%s Invalid frequency %lu", - mss::c_str(i_target), - l_freq); - break; - } - -fapi_try_exit: - return fapi2::current_err; -} - -/// -/// @brief Helper function to find tFAW based speed (MT/s) for 2KB page -/// @tparam T the fapi2::TargetType of a type from which we can get MT/s -/// @param[in] i_target the fapi2 target -/// @param[out] o_output timing in clocks (nck) -/// @return FAPI2_RC_SUCCESS iff okay -/// @note this is only for non-3DS DIMM -/// -template< fapi2::TargetType T > -static fapi2::ReturnCode tfaw_2kb_page_helper(const fapi2::Target<T>& i_target, - uint64_t& o_output) -{ - - // Values derived from DDR4 Spec (79-4A) - // 13.3 Timing Parameters by Speed Grade - // Table 132. Pg 240 - fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; - - // It could have been more "efficient" to hand-calculate the answer and - // use compile time constants to return the answer. To avoid magic - // numbers and to align (more closely) with the DDR4 JEDEC spec, - // we let the std library do the work for us for maintainability. - // Could have used compile-time constants to denote the numbers below - // but they are "random" and vary. - uint64_t l_freq = 0; - FAPI_TRY( freq(find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq), - "Failed to invoke freq accessor" ); - - switch(l_freq) - { - case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: - case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: - case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: - case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: - o_output = std::max( 28, spd::ns_to_nck(i_target, 30) ); - break; - - default: - FAPI_ASSERT( false, - fapi2::MSS_INVALID_FREQ_PASSED_IN() - .set_FREQ(l_freq) - .set_FUNCTION(TFAW_TW_KB_PAGE_HELPER) - .set_DIMM_TARGET(i_target), - "%s Invalid frequency %lu", - mss::c_str(i_target), - l_freq); - break; - } - -fapi_try_exit: - return fapi2::current_err; -} - -/// -/// @brief Return the minimum allowable tFAW in nck -/// @tparam T the fapi2::TargetType of a type from which we can get MT/s -/// @param[in] i_target the fapi2 target -/// @param[in] i_dram_width the page size -/// @param[out] o_tFAW timing in clocks (nck) -/// @return FAPI2_RC_SUCCESS iff okay -// -template< fapi2::TargetType T > -fapi2::ReturnCode tfaw( const fapi2::Target<T>& i_target, - const uint8_t i_dram_width, - uint64_t& o_tFAW ) -{ - switch(i_dram_width) - { - case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X4: - FAPI_TRY( tfaw_half_kb_page_helper(i_target, o_tFAW) ); - break; - - case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8: - FAPI_TRY( tfaw_1kb_page_helper(i_target, o_tFAW) ); - break; - - case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X16: - FAPI_TRY( tfaw_2kb_page_helper(i_target, o_tFAW) ); - break; - - default: - FAPI_ASSERT( false, - fapi2::MSS_INVALID_DRAM_WIDTH() - .set_DRAM_WIDTH(i_dram_width) - .set_DIMM_TARGET(i_target), - "Invalid DRAM width with %d for target %s", - i_dram_width, - mss::c_str(i_target)); - break; - } - -fapi_try_exit: - return fapi2::current_err; -} - -/// -/// @brief tFAW_dlr *in nck* -/// @return 16nck -/// @note From DDR4 3DS Spec -/// 12.2 Timing Parameters by Speed Grade -/// -constexpr uint64_t tfaw_dlr() -{ - return 16; -} - -/// -/// @brief tRRD_dlr *in nck* -/// @return 4nck -/// @note From DDR4 3DS Spec -/// 12.2 Timing Parameters by Speed Grade -/// -constexpr uint64_t trrd_dlr() -{ - return 4; -} - -/// -/// @brief Helper function to find tRRD_L based speed (MT/s) for 1KB page -/// @tparam T the fapi2::TargetType of a type from which we can get MT/s -/// @param[in] i_target the fapi2 target -/// @param[out] o_output timing in clocks (nck) -/// @return FAPI2_RC_SUCCESS iff okay -/// @note this is only for non-3DS DIMM -/// -template< fapi2::TargetType T > -static fapi2::ReturnCode trrd_l_half_and_1kb_page_helper(const fapi2::Target<T>& i_target, - uint64_t& o_output) -{ - // Values derived from DDR4 Spec (79-4A) - // 13.3 Timing Parameters by Speed Grade - // Table 132. Pg 240 - fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; - - uint64_t l_freq = 0; - FAPI_TRY( freq(find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq), - "Failed to invoke freq accessor" ); - - // It could have been more "efficient" to hand-calculate the answer and - // use compile time constants to return the answer. To avoid magic - // numbers and to align (more closely) with the DDR4 JEDEC spec, - // we let the std library do the work for us for maintainability (and ease of debug?). - // Could have used compile-time constants to denote the numbers below - // but they are "random" and vary. - switch(l_freq) - { - case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: - case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: - // From the spec: Max(4nCK,5.3ns) - o_output = std::max( 4, spd::ps_to_nck(i_target, 5300) ); - break; - - case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: - case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: - // Max(4nCK,4.9ns) - o_output = std::max( 4, spd::ps_to_nck(i_target, 4900) ); - break; - - default: - FAPI_ASSERT( false, - fapi2::MSS_INVALID_FREQ_PASSED_IN() - .set_FREQ(l_freq) - .set_FUNCTION(TRRD_L_HALF_AND_1KB_PAGE_HELPER) - .set_DIMM_TARGET(i_target), - "%s Invalid frequency %lu", - mss::c_str(i_target), - l_freq); - } - - return fapi2::FAPI2_RC_SUCCESS; -fapi_try_exit: - return fapi2::current_err; -} - -/// -/// @brief Helper function to find tRRD_L based speed (MT/s) for 2KB page -/// @tparam T the fapi2::TargetType of a type from which we can get MT/s -/// @param[in] i_target the fapi2 target -/// @param[out] o_output timing in clocks (nck) -/// @return FAPI2_RC_SUCCESS iff okay -/// @note this is only for non-3DS DIMM -/// -template< fapi2::TargetType T > -static fapi2::ReturnCode trrd_l_2kb_page_helper(const fapi2::Target<T>& i_target, - uint64_t& o_output) -{ - - // Values derived from DDR4 Spec (79-4A) - // 13.3 Timing Parameters by Speed Grade - // Table 132. Pg 240 - fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; - - uint64_t l_freq = 0; - FAPI_TRY( freq(find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq), - "Failed to invoke freq accessor" ); - - // It could have been more "efficient" to hand-calculate the answer and - // use compile time constants to return the answer. To avoid magic - // numbers and to align (more closely) with the DDR4 JEDEC spec, - // we let the std library do the work for us for maintainability (and ease of debug?). - // Could have used compile-time constants to denote the numbers below - // but they are "random" and vary. - switch(l_freq) - { - case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: - case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: - case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: - case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: - o_output = std::max( 4, spd::ps_to_nck(i_target, 6400) ); - break; - - default: - FAPI_TRY(fapi2::FAPI2_RC_INVALID_PARAMETER, "%s Invalid frequency %lu", mss::c_str(i_target), l_freq); - break; - } - -fapi_try_exit: - return fapi2::current_err; -} - -/// -/// @brief Return the minimum allowable tRRD_L in nck -/// @tparam T the fapi2::TargetType of a type from which we can get MT/s -/// @param[in] i_target the fapi2 target -/// @param[in] i_dram_width the page size -/// @param[out] o_output timing in clocks (nck) -/// @return FAPI2_RC_SUCCESS iff okay -/// @note this is only for non-3DS DIMM -/// -template< fapi2::TargetType T > -fapi2::ReturnCode trrd_l( const fapi2::Target<T>& i_target, - const uint8_t i_dram_width, - uint64_t& o_tRRD_L ) -{ - switch(i_dram_width) - { - case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X4: - case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8: - FAPI_TRY( trrd_l_half_and_1kb_page_helper(i_target, o_tRRD_L), "Error calculating trrd l for half and 1kb page" ); - break; - - case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X16: - FAPI_TRY( trrd_l_2kb_page_helper(i_target, o_tRRD_L) ); - break; - - default: - FAPI_ASSERT( false, - fapi2::MSS_INVALID_PAGE_SIZE() - .set_DRAM_WIDTH(i_dram_width) - .set_DIMM_TARGET(i_target), - "%s Recieved an invalid page size: %lu", - mss::c_str(i_target), - i_dram_width); - break; - } - - return fapi2::FAPI2_RC_SUCCESS; -fapi_try_exit: - return fapi2::current_err; -} - -/// -/// @brief Helper function to find tRRD_S based speed (MT/s) for 1KB page -/// @tparam T the fapi2::TargetType of a type from which we can get MT/s -/// @param[in] i_target the fapi2 target -/// @param[out] o_output timing in clocks (nck) -/// @return FAPI2_RC_SUCCESS iff okay -/// @note this is only for non-3DS DIMM -/// -template< fapi2::TargetType T > -static fapi2::ReturnCode trrd_s_half_and_1kb_page_helper(const fapi2::Target<T>& i_target, - uint64_t& o_output) -{ - // Values derived from DDR4 Spec (79-4A) - // 13.3 Timing Parameters by Speed Grade - // Table 132. Pg 240 - fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; - - uint64_t l_freq = 0; - FAPI_TRY( freq(find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq), - "Failed to invoke freq accessor" ); - - // It could have been more "efficient" to hand-calculate the answer and - // use compile time constants to return the answer. To avoid magic - // numbers and to align (more closely) with the DDR4 JEDEC spec, - // we let the std library do the work for us for maintainability (and ease of debug?). - // Could have used compile-time constants to denote the numbers below - // but they are "random" and vary. - switch(l_freq) - { - case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: - o_output = std::max( 4, spd::ps_to_nck(i_target, 4200) ); - break; - - case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: - o_output = std::max( 4, spd::ps_to_nck(i_target, 3700) ); - break; - - case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: - o_output = std::max( 4, spd::ps_to_nck(i_target, 3300) ); - break; - - case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: - o_output = std::max( 4, spd::ps_to_nck(i_target, 3000) ); - break; - - default: - FAPI_ASSERT( false, - fapi2::MSS_INVALID_FREQ_PASSED_IN() - .set_FREQ(l_freq) - .set_FUNCTION(TRRD_S_HALF_AND_1KB_PAGE_HELPER) - .set_DIMM_TARGET(i_target), - "%s Invalid frequency %lu", - mss::c_str(i_target), - l_freq); - } - - return fapi2::FAPI2_RC_SUCCESS; -fapi_try_exit: - return fapi2::current_err; -} - -/// -/// @brief Helper function to find tRRD_S based speed (MT/s) for 2KB page -/// @tparam T the fapi2::TargetType of a type from which we can get MT/s -/// @param[in] i_target the fapi2 target -/// @param[out] o_output timing in clocks (nck) -/// @return FAPI2_RC_SUCCESS iff okay -/// @note this is only for non-3DS DIMM -/// -template< fapi2::TargetType T > -static fapi2::ReturnCode trrd_s_2kb_page_helper(const fapi2::Target<T>& i_target, - uint64_t& o_output) -{ - // Values derived from DDR4 Spec (79-4A) - // 13.3 Timing Parameters by Speed Grade - // Table 132. Pg 240 - fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; - - uint64_t l_freq = 0; - FAPI_TRY( freq(find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq), - "Failed to invoke freq accessor" ); - - // It could have been more "efficient" to hand-calculate the answer and - // use compile time constants to return the answer. To avoid magic - // numbers and to align (more closely) with the DDR4 JEDEC spec, - // we let the std library do the work for us for maintainability (and ease of debug?). - // Could have used compile-time constants to denote the numbers below - // but they are "random" and vary. - switch(l_freq) - { - case fapi2::ENUM_ATTR_MSS_FREQ_MT1866: - case fapi2::ENUM_ATTR_MSS_FREQ_MT2133: - case fapi2::ENUM_ATTR_MSS_FREQ_MT2400: - case fapi2::ENUM_ATTR_MSS_FREQ_MT2666: - o_output = std::max( 4, spd::ps_to_nck(i_target, 5300) ); - break; - - default: - FAPI_ASSERT( false, - fapi2::MSS_INVALID_FREQ_PASSED_IN() - .set_FREQ(l_freq) - .set_FUNCTION(TRRD_S_2KB_PAGE_HELPER) - .set_DIMM_TARGET(i_target), - "%s Invalid frequency %lu", - mss::c_str(i_target), - l_freq); - break; - } - - return fapi2::FAPI2_RC_SUCCESS; -fapi_try_exit: - return fapi2::current_err; -} - -/// -/// @brief Return the minimum allowable tRRD_S in nck -/// @tparam T the fapi2::TargetType of a type from which we can get MT/s -/// @param[in] i_target the fapi2 target -/// @param[in] i_dram_width the page size -/// @param[out] o_tRRD_S timing in clocks (nck) -/// @return FAPI2_RC_SUCCESS iff okay -/// @note this is only for non-3DS DIMM -/// -template< fapi2::TargetType T > -fapi2::ReturnCode trrd_s( const fapi2::Target<T>& i_target, - const uint8_t i_dram_width, - uint64_t& o_tRRD_S ) -{ - switch(i_dram_width) - { - case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X4: - case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8: - FAPI_TRY( trrd_s_half_and_1kb_page_helper(i_target, o_tRRD_S), "Error calculating trrd_s for half and 1kb page" ); - break; - - case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X16: - FAPI_TRY( trrd_s_2kb_page_helper(i_target, o_tRRD_S) ); - break; - - default: - FAPI_ASSERT( false, - fapi2::MSS_INVALID_PAGE_SIZE() - .set_DRAM_WIDTH(i_dram_width) - .set_DIMM_TARGET(i_target), - "%s Recieved an invalid page size: %lu", - mss::c_str(i_target), - i_dram_width); - break; - } - - return fapi2::FAPI2_RC_SUCCESS; -fapi_try_exit: - return fapi2::current_err; -} - -/// /// @brief VREF DQ Enter time *in clocks* /// @tparam T the fapi2::TargetType of i_target /// @param[in] i_target a target for attributes @@ -1215,25 +504,5 @@ constexpr uint64_t tccd_s() return 4; } -namespace lrdimm -{ - -/// -/// @brief Return the VREF to VREF change time long -/// @tparam fapi2::TargetType T - type of the target on which to operate -/// @param[in] i_target the fapi2 target -/// @return value in clocks -/// @note VREF time change long is used for changing by more than one VREF tick -/// -template< fapi2::TargetType T > -inline uint64_t vref_time_long(const fapi2::Target<T>& i_target) -{ - // Taken from the LRDIMM spec - constexpr uint64_t VREF_TIME_LONG_NS = 500; - return mss::spd::ns_to_nck(i_target, VREF_TIME_LONG_NS); -} - -} // ns lrdimm - } // mss #endif diff --git a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_eff_config.xml b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_eff_config.xml index 56fb232dc..4bd96d9f7 100644 --- a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_eff_config.xml +++ b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_eff_config.xml @@ -37,18 +37,6 @@ <hwpErrors> <hwpError> - <rc>RC_MSS_INVALID_FINE_REFRESH_MODE</rc> - <description> - Invalid fine refresh mode received from the mrw - </description> - <ffdc>FINE_REF_MODE</ffdc> - <callout> - <procedure>CODE</procedure> - <priority>HIGH</priority> - </callout> - </hwpError> - - <hwpError> <rc>RC_MSS_INVALID_FINE_REFRESH_MODE_WITH_TEMP_REFRESH_MODE_ENABLED</rc> <description> Invalid fine refresh mode received due to temperature refresh mode being enabled @@ -383,19 +371,6 @@ </hwpError> <hwpError> - <rc>RC_MSS_INVALID_REFRESH_RATE_REQUEST</rc> - <description> - Invalid refresh request rate received. - Possibly due to bad MRW setting for ATTR_MSS_MRW_REFRESH_RATE_REQUEST. - </description> - <ffdc>REFRESH_RATE_REQUEST</ffdc> - <callout> - <procedure>CODE</procedure> - <priority>HIGH</priority> - </callout> - </hwpError> - - <hwpError> <rc>RC_MSS_INVALID_FINE_REFRESH</rc> <description> Incorrect FINE Refresh Mode received @@ -408,26 +383,6 @@ </hwpError> <hwpError> - <rc>RC_MSS_FAILED_TO_FIND_TRFC</rc> - <description> - Unable to find tRFC (ps) from map with SDRAM density key - </description> - <ffdc>SDRAM_DENSITY</ffdc> - <ffdc>REFRESH_MODE</ffdc> - <callout> - <target>DIMM_TARGET</target> - <priority>MEDIUM</priority> - </callout> - <deconfigure> - <target>DIMM_TARGET</target> - </deconfigure> - <callout> - <procedure>CODE</procedure> - <priority>HIGH</priority> - </callout> - </hwpError> - - <hwpError> <rc>RC_MSS_INVALID_PAGE_SIZE</rc> <description> Invalid page size diff --git a/src/import/generic/memory/lib/data_engine/attr_engine_traits.H b/src/import/generic/memory/lib/data_engine/attr_engine_traits.H index 44f6674d5..5de4f0da2 100644 --- a/src/import/generic/memory/lib/data_engine/attr_engine_traits.H +++ b/src/import/generic/memory/lib/data_engine/attr_engine_traits.H @@ -41,9 +41,12 @@ #include <generic/memory/lib/data_engine/data_engine_utils.H> #include <generic/memory/lib/mss_generic_attribute_getters.H> #include <generic/memory/lib/mss_generic_attribute_setters.H> +#include <generic/memory/lib/mss_generic_system_attribute_getters.H> #include <generic/memory/lib/spd/ddimm/efd_decoder.H> #include <generic/memory/lib/spd/spd_facade.H> #include <generic/memory/lib/utils/buffer_ops.H> +#include <generic/memory/lib/utils/dimm/mss_timing.H> +#include <generic/memory/lib/spd/spd_utils.H> namespace mss { @@ -1599,7 +1602,7 @@ struct attrEngineTraits<attr_engine_derived_fields, LOGICAL_RANKS> // Value of 1 has no meaning and is used for calculation purposes as defined by the SPD spec. const auto l_multiplier = (l_prim_stack_type == fapi2::ENUM_ATTR_MEM_EFF_PRIM_STACK_TYPE_3DS) ? l_die_count : 1; o_setting = (l_master_ranks * l_multiplier); - FAPI_DBG("Num Logical Ranks %d", o_setting); + FAPI_DBG("%s Num Logical Ranks %d", spd::c_str(i_target), o_setting); } fapi_try_exit: @@ -1668,8 +1671,8 @@ struct attrEngineTraits<attr_engine_derived_fields, MEM_DIMM_SIZE> // Total = SDRAM Capacity / 8 * Primary Bus Width / SDRAM Width * Logical Ranks per DIMM o_setting = (l_dram_density * l_bus_width * l_logical_rank_per_dimm) / (8 * l_dram_width); - FAPI_DBG("DIMM size = %d => (%d * %d * %d) / (8 * %d)", - o_setting, l_dram_density, l_bus_width, l_logical_rank_per_dimm, l_dram_width); + FAPI_DBG("%s DIMM size = %d => (%d * %d * %d) / (8 * %d)", + spd::c_str(i_target), o_setting, l_dram_density, l_bus_width, l_logical_rank_per_dimm, l_dram_width); fapi_try_exit: return fapi2::current_err; @@ -1748,6 +1751,1547 @@ struct attrEngineTraits<attr_engine_derived_fields, HEIGHT_3DS> } }; +/// +/// @brief Traits for attrEngineTraits +/// @class attrEngineTraits +/// @note attrEngineTraits, DRAM_CWL specialization +/// +template<> +struct attrEngineTraits<attr_eff_engine_fields, DRAM_CWL> +{ + using attr_type = fapi2::ATTR_MEM_DRAM_CWL_Type; + using attr_integral_type = std::remove_all_extents<attr_type>::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_DRAM_CWL_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_CWL; + + /// + /// @brief attribute getter + /// @param[in] i_target the attr target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& o_setting) + { + return mss::attr::get_dram_cwl(i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the attr target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& i_setting) + { + return mss::attr::set_dram_cwl(i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[out] o_setting value we want to set attr with + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data, + attr_integral_type& o_setting) + { + // Taken from DDR4 JEDEC spec 1716.78C + // Proposed DDR4 Full spec update(79-4A) + // Page 26, Table 7 + static const std::vector<std::pair<uint64_t, uint8_t> > CWL_TABLE_1 = + { + {1866, 10}, + {2133, 11}, + {2400, 12}, + {2666, 14}, + {2933, 16}, + {3200, 16}, + }; + + static const std::vector<std::pair<uint64_t, uint8_t> > CWL_TABLE_2 = + { + // Note that 2tCK write preamble is not valid for 1866 or 2133 speed grades + {2400, 14}, + {2666, 16}, + {2933, 18}, + {3200, 18}, + }; + + const auto& l_dimm = i_spd_data.get_dimm_target(); + // TK This could change but not sure where to get this from + constexpr size_t MAX_RANKS_PER_DIMM = 4; + uint64_t l_freq = 0; + uint8_t l_preambles[MAX_RANKS_PER_DIMM] = {0}; + fapi2::buffer<uint8_t> l_preamble; + + FAPI_TRY( mss::attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) ); + FAPI_TRY( mss::attr::get_si_dram_preamble(l_dimm, l_preambles) ); + + // TK Using the preamble for rank0 for now + l_preamble = l_preambles[0]; + + if (!l_preamble.getBit<fapi2::ENUM_ATTR_MEM_SI_DRAM_PREAMBLE_WRITE_PREAMBLE_BIT>()) + { + FAPI_TRY(lookup_table_check(l_dimm, CWL_TABLE_1, FFDC_CODE, l_freq, o_setting)); + } + else + { + FAPI_TRY(lookup_table_check(l_dimm, CWL_TABLE_2, FFDC_CODE, l_freq, o_setting)); + } + + FAPI_DBG("%s DRAM CWL %d", spd::c_str(l_dimm), o_setting); + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for attrEngineTraits +/// @class attrEngineTraits +/// @note attrEngineTraits, DRAM_TREFI specialization +/// +template<> +struct attrEngineTraits<attr_eff_engine_fields, DRAM_TREFI> +{ + using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TREFI_Type; + using attr_integral_type = std::remove_all_extents<attr_type>::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TREFI_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TREFI; + + /// + /// @brief attribute getter + /// @param[in] i_target the attr target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& o_setting) + { + return mss::attr::get_dram_trefi(i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the attr target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& i_setting) + { + return mss::attr::set_dram_trefi(i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[out] o_setting value we want to set attr with + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data, + attr_integral_type& o_setting) + { + const auto& l_dimm = i_spd_data.get_dimm_target(); + uint8_t l_refresh_mode = 0; + uint8_t l_refresh_rate = 0; + uint64_t l_trefi_in_ps = 0; + int64_t l_tck_in_ps = 0; + uint64_t l_freq = 0; + + FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) ); + FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), + "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) ); + + FAPI_TRY( mss::attr::get_mrw_fine_refresh_mode(l_refresh_mode) ); + FAPI_TRY( mss::attr::get_mrw_refresh_rate_request(l_refresh_rate) ); + + switch(l_refresh_mode) + { + case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_NORMAL: + + FAPI_TRY( calc_trefi( mss::refresh_rate::REF1X, + l_refresh_rate, + l_trefi_in_ps), + "%s Failed to calculate tREF1", spd::c_str(l_dimm) ); + break; + + case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_2X: + case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_2X: + + FAPI_TRY( calc_trefi( mss::refresh_rate::REF2X, + l_refresh_rate, + l_trefi_in_ps), + "%s Failed to calculate tREF2", spd::c_str(l_dimm) ); + break; + + case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_4X: + case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_4X: + + FAPI_TRY( calc_trefi( mss::refresh_rate::REF4X, + l_refresh_rate, + l_trefi_in_ps), + "%s Failed to calculate tREF4", spd::c_str(l_dimm) ); + break; + + default: + // Fine Refresh Mode will be a platform attribute set by the MRW, + // which they "shouldn't" mess up as long as use "attribute" enums. + // if openpower messes this up we can at least catch it + FAPI_ASSERT(false, + fapi2::MSS_INVALID_FINE_REFRESH_MODE(). + set_FINE_REF_MODE(l_refresh_mode), + "%s Incorrect Fine Refresh Mode received: %d ", + spd::c_str(l_dimm), + l_refresh_mode); + break; + }; + + { + // Calculate refresh cycle time in nCK & set attribute + constexpr double PERCENT_ADJUST = 0.99; + + // Calculate nck + uint64_t l_trefi_in_nck = 0; + FAPI_TRY( spd::calc_nck( l_trefi_in_ps, + static_cast<uint64_t>(l_tck_in_ps), + spd::INVERSE_DDR4_CORRECTION_FACTOR, + l_trefi_in_nck), + "%s Error in calculating tREFI, with value of l_trefi_in_ps: %d", spd::c_str(l_dimm), l_trefi_in_ps); + + // Lab requested 99% of tREFI calculation to avoid any latency impact and violation of any + // refresh specification (across all number of ranks and frequencies) observed + // during lab power/thermal tests. + + FAPI_INF("%s adjusting tREFI calculation by 99%, calculated tREFI (nck): %lu, adjusted tREFI (nck): %lu,", + spd::c_str(l_dimm), l_trefi_in_nck, l_trefi_in_nck * PERCENT_ADJUST); + + // The compiler does this under the covers but just to be explicit on intent: + // Floating point arithmetic and truncation of result saved to an unsigned integer + l_trefi_in_nck = static_cast<double>(l_trefi_in_nck * PERCENT_ADJUST); + + FAPI_INF("%s tCK (ps): %d, tREFI (ps): %d, tREFI (nck): %d", + spd::c_str(l_dimm), l_tck_in_ps, l_trefi_in_ps, l_trefi_in_nck); + + o_setting = l_trefi_in_nck; + FAPI_DBG("%s DRAM TREFI %d", spd::c_str(l_dimm), o_setting); + } + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for attrEngineTraits +/// @class attrEngineTraits +/// @note attrEngineTraits, DRAM_TCCD_L specialization +/// +template<> +struct attrEngineTraits<attr_eff_engine_fields, DRAM_TCCD_L> +{ + using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TCCD_L_Type; + using attr_integral_type = std::remove_all_extents<attr_type>::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TCCD_L_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TCCD_L; + + /// + /// @brief attribute getter + /// @param[in] i_target the attr target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& o_setting) + { + return mss::attr::get_dram_tccd_l(i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the attr target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& i_setting) + { + return mss::attr::set_dram_tccd_l(i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[out] o_setting value we want to set attr with + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data, + attr_integral_type& o_setting) + { + const auto& l_dimm = i_spd_data.get_dimm_target(); + int64_t l_tccd_in_ps = 0; + int64_t l_tck_in_ps = 0; + uint64_t l_freq = 0; + + FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) ); + FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), + "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) ); + + // Get the tCCD_L timing values + // tCCD_L is speed bin independent and is + // the same for all bins at a DRAM frequency. + // It is safe to read this from SPD because the correct nck + // value will be calulated based on our dimm speed. + + { + int64_t l_ftb = 0; + int64_t l_mtb = 0; + int64_t l_tccd_mtb = 0; + int64_t l_tccd_ftb = 0; + + FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) ); + FAPI_TRY( i_spd_data.min_tccd_l(l_tccd_mtb), + "%s Failed min_tccd_l()", spd::c_str(l_dimm) ); + FAPI_TRY( i_spd_data.fine_offset_min_tccd_l(l_tccd_ftb), + "%s Failed fine_offset_min_tccd_l()", spd::c_str(l_dimm) ); + + FAPI_INF("%s medium timebase (ps): %ld, fine timebase (ps): %ld, tCCD_L (MTB): %ld, tCCD_L(FTB): %ld", + spd::c_str(l_dimm), l_mtb, l_ftb, l_tccd_mtb, l_tccd_ftb ); + + l_tccd_in_ps = spd::calc_timing_from_timebase(l_tccd_mtb, l_mtb, l_tccd_ftb, l_ftb); + } + + { + // Calculate refresh cycle time in nCK & set attribute + uint8_t l_tccd_in_nck = 0; + + // Calculate nck + FAPI_TRY( spd::calc_nck(l_tccd_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_tccd_in_nck), + "%s Error in calculating tccd, with value of l_tccd_in_ps: %d", + spd::c_str(l_dimm), l_tccd_in_ps); + + FAPI_INF("%s tCK (ps): %d, tCCD_L (ps): %d, tCCD_L (nck): %d", + spd::c_str(l_dimm), l_tck_in_ps, l_tccd_in_ps, l_tccd_in_nck); + + o_setting = l_tccd_in_nck; + FAPI_DBG("%s DRAM TCCD_L %d", spd::c_str(l_dimm), o_setting); + } + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for attrEngineTraits +/// @class attrEngineTraits +/// @note attrEngineTraits, DRAM_TWTR_L specialization +/// +template<> +struct attrEngineTraits<attr_eff_engine_fields, DRAM_TWTR_L> +{ + using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TWTR_L_Type; + using attr_integral_type = std::remove_all_extents<attr_type>::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TWTR_L_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TWTR_L; + + /// + /// @brief attribute getter + /// @param[in] i_target the attr target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& o_setting) + { + return mss::attr::get_dram_twtr_l(i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the attr target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& i_setting) + { + return mss::attr::set_dram_twtr_l(i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[out] o_setting value we want to set attr with + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data, + attr_integral_type& o_setting) + { + const auto& l_dimm = i_spd_data.get_dimm_target(); + int64_t l_twtr_l_in_ps = 0; + int64_t l_tck_in_ps = 0; + uint64_t l_freq = 0; + + FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) ); + FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), + "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) ); + + // Calculate twtr_l (in ps) + { + int64_t l_ftb = 0; + int64_t l_mtb = 0; + constexpr int64_t l_twtr_l_ftb = 0; + int64_t l_twtr_l_mtb = 0; + + FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) ); + FAPI_TRY( i_spd_data.min_twtr_l(l_twtr_l_mtb) ); + + FAPI_INF("%s medium timebase (ps): %ld, fine timebase (ps): %ld, tWTR_L (MTB): %ld, tWTR_L (FTB): %ld", + spd::c_str(l_dimm), l_mtb, l_ftb, l_twtr_l_mtb, l_twtr_l_ftb ); + + l_twtr_l_in_ps = spd::calc_timing_from_timebase(l_twtr_l_mtb, l_mtb, l_twtr_l_ftb, l_ftb); + } + + { + uint8_t l_twtr_l_in_nck = 0; + + // Calculate nck + FAPI_TRY( spd::calc_nck(l_twtr_l_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_twtr_l_in_nck), + "%s Error in calculating tWTR_L, with value of l_twtr_in_ps: %d", + spd::c_str(l_dimm), l_twtr_l_in_ps ); + + FAPI_INF( "%s tCK (ps): %d, tWTR_L (ps): %d, tWTR_L (nck): %d", + spd::c_str(l_dimm), l_tck_in_ps, l_twtr_l_in_ps, l_twtr_l_in_nck ); + + o_setting = l_twtr_l_in_nck; + FAPI_DBG("%s DRAM TWTR_L %d", spd::c_str(l_dimm), o_setting); + } + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for attrEngineTraits +/// @class attrEngineTraits +/// @note attrEngineTraits, DRAM_TWTR_S specialization +/// +template<> +struct attrEngineTraits<attr_eff_engine_fields, DRAM_TWTR_S> +{ + using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TWTR_S_Type; + using attr_integral_type = std::remove_all_extents<attr_type>::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TWTR_S_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TWTR_S; + + /// + /// @brief attribute getter + /// @param[in] i_target the attr target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& o_setting) + { + return mss::attr::get_dram_twtr_s(i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the attr target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& i_setting) + { + return mss::attr::set_dram_twtr_s(i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[out] o_setting value we want to set attr with + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data, + attr_integral_type& o_setting) + { + const auto& l_dimm = i_spd_data.get_dimm_target(); + int64_t l_twtr_s_in_ps = 0; + int64_t l_tck_in_ps = 0; + uint64_t l_freq = 0; + + FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) ); + FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), + "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) ); + + // Calculate twtr_s (in ps) + { + int64_t l_ftb = 0; + int64_t l_mtb = 0; + constexpr int64_t l_twtr_s_ftb = 0; + int64_t l_twtr_s_mtb = 0; + + FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) ); + FAPI_TRY( i_spd_data.min_twtr_s(l_twtr_s_mtb) ); + + FAPI_INF("%s medium timebase (ps): %ld, fine timebase (ps): %ld, tWTR_S (MTB): %ld, tWTR_S (FTB): %ld", + spd::c_str(l_dimm), l_mtb, l_ftb, l_twtr_s_mtb, l_twtr_s_ftb ); + + l_twtr_s_in_ps = spd::calc_timing_from_timebase(l_twtr_s_mtb, l_mtb, l_twtr_s_ftb, l_ftb); + } + + { + int8_t l_twtr_s_in_nck = 0; + + // Calculate nck + FAPI_TRY( spd::calc_nck(l_twtr_s_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_twtr_s_in_nck), + "%s Error in calculating tWTR_S, with value of l_twtr_in_ps: %d", + spd::c_str(l_dimm), l_twtr_s_in_ps ); + + FAPI_INF( "%s tCK (ps): %d, tWTR_S (ps): %d, tWTR_S (nck): %d", + spd::c_str(l_dimm), l_tck_in_ps, l_twtr_s_in_ps, l_twtr_s_in_nck ); + + o_setting = l_twtr_s_in_nck; + FAPI_DBG("%s DRAM TWTR_S %d", spd::c_str(l_dimm), o_setting); + } + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for attrEngineTraits +/// @class attrEngineTraits +/// @note attrEngineTraits, DRAM_TFAW specialization +/// +template<> +struct attrEngineTraits<attr_eff_engine_fields, DRAM_TFAW> +{ + using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TFAW_Type; + using attr_integral_type = std::remove_all_extents<attr_type>::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TFAW_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TFAW; + + /// + /// @brief attribute getter + /// @param[in] i_target the attr target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& o_setting) + { + return mss::attr::get_dram_tfaw(i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the attr target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& i_setting) + { + return mss::attr::set_dram_tfaw(i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[out] o_setting value we want to set attr with + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data, + attr_integral_type& o_setting) + { + const auto& l_dimm = i_spd_data.get_dimm_target(); + uint64_t l_tfaw_in_nck = 0; + uint64_t l_jedec_tfaw_in_nck = 0; + int64_t l_tfaw_in_ps = 0; + int64_t l_tfaw_ftb = 0; + int64_t l_tck_in_ps = 0; + uint64_t l_freq = 0; + uint8_t l_dram_width = 0; + + FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) ); + FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), + "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) ); + + // Calculate tFAW + { + int64_t l_ftb = 0; + int64_t l_mtb = 0; + int64_t l_tfaw_mtb = 0; + + FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) ); + FAPI_TRY( i_spd_data.min_tfaw(l_tfaw_mtb), + "%s Failed min_tfaw()", spd::c_str(l_dimm) ); + + FAPI_INF("%s medium timebase (ps): %ld, fine timebase (ps): %ld, tfaw (MTB): %ld", + spd::c_str(l_dimm), l_mtb, l_ftb, l_tfaw_mtb); + + l_tfaw_in_ps = spd::calc_timing_from_timebase(l_tfaw_mtb, l_mtb, l_tfaw_ftb, l_ftb); + + FAPI_ASSERT( l_tfaw_in_ps >= 0, + fapi2::MSS_INVALID_TIMING_VALUE() + .set_VALUE(l_tfaw_in_ps) + .set_DIMM_TARGET(l_dimm) + .set_FUNCTION(TFAW), + "%s Error calculating tFAW (%d). Less than or equal to 0", + spd::c_str(l_dimm), + l_tfaw_in_ps); + + FAPI_DBG("%s TFAW in ps is %d", spd::c_str(l_dimm), l_tfaw_in_ps); + + FAPI_TRY( spd::calc_nck(l_tfaw_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_tfaw_in_nck), + "%s Error in calculating l_tFAW, with value of l_tfaw_in_ps: %d", + spd::c_str(l_dimm), + l_tfaw_in_nck); + } + + FAPI_TRY( attr::get_dram_width(l_dimm, l_dram_width) ); + FAPI_TRY( mss::tfaw(l_dimm, l_dram_width, l_freq, l_jedec_tfaw_in_nck), "Failed tfaw()" ); + + // Taking the worst case between the required minimum JEDEC value and the proposed value from SPD + if (l_jedec_tfaw_in_nck != l_tfaw_in_nck) + { + FAPI_INF("%s TFAW from JEDEC (%d) and from SPD (%d) don't match. Choosing worst case. dram width %d, freq %d", + spd::c_str(l_dimm), + l_jedec_tfaw_in_nck, + l_tfaw_in_nck, + l_dram_width, + l_freq); + + l_tfaw_in_nck = std::max(l_jedec_tfaw_in_nck, l_tfaw_in_nck); + } + + FAPI_INF("%s SDRAM width: %d, tFAW (nck): %d", + spd::c_str(l_dimm), l_dram_width, l_tfaw_in_nck); + o_setting = l_tfaw_in_nck; + FAPI_DBG("%s DRAM TFAW %d", spd::c_str(l_dimm), o_setting); + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for attrEngineTraits +/// @class attrEngineTraits +/// @note attrEngineTraits, DRAM_TRCD specialization +/// +template<> +struct attrEngineTraits<attr_eff_engine_fields, DRAM_TRCD> +{ + using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TRCD_Type; + using attr_integral_type = std::remove_all_extents<attr_type>::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TRCD_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TRCD; + + /// + /// @brief attribute getter + /// @param[in] i_target the attr target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& o_setting) + { + return mss::attr::get_dram_trcd(i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the attr target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& i_setting) + { + return mss::attr::set_dram_trcd(i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[out] o_setting value we want to set attr with + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data, + attr_integral_type& o_setting) + { + const auto& l_dimm = i_spd_data.get_dimm_target(); + int64_t l_tck_in_ps = 0; + uint64_t l_freq = 0; + int64_t l_trcd_in_ps = 0; + + FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) ); + FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), + "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) ); + + // Calculate tRCD (in ps) + // Get the tRCD timing values + // tRCD is speed bin dependent and has a unique + // value for each speed bin so it is safe to + // read from SPD because the correct nck + // value will be calulated based on our dimm speed. + { + int64_t l_ftb = 0; + int64_t l_mtb = 0; + int64_t l_trcd_mtb = 0; + int64_t l_trcd_ftb = 0; + + FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) ); + FAPI_TRY( i_spd_data.min_trcd(l_trcd_mtb), + "%s Failed min_trcd()", spd::c_str(l_dimm) ); + FAPI_TRY( i_spd_data.fine_offset_min_trcd(l_trcd_ftb), + "%s Failed fine_offset_min_trcd()", spd::c_str(l_dimm) ); + + FAPI_INF("%s medium timebase MTB (ps): %ld, fine timebase FTB (ps): %ld, tRCD (MTB): %ld, tRCD (FTB): %ld", + spd::c_str(l_dimm), l_mtb, l_ftb, l_trcd_mtb, l_trcd_ftb); + + l_trcd_in_ps = spd::calc_timing_from_timebase(l_trcd_mtb, l_mtb, l_trcd_ftb, l_ftb); + } + + { + uint8_t l_trcd_in_nck = 0; + + // Calculate nck + FAPI_TRY( spd::calc_nck(l_trcd_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_trcd_in_nck), + "%s Error in calculating trcd, with value of l_trcd_in_ps: %d", + spd::c_str(l_dimm), l_trcd_in_ps); + + FAPI_INF("%s tCK (ps): %d, tRCD (ps): %d, tRCD (nck): %d", + spd::c_str(l_dimm), l_tck_in_ps, l_trcd_in_ps, l_trcd_in_nck); + + o_setting = l_trcd_in_nck; + FAPI_DBG("%s DRAM TRCD %d", spd::c_str(l_dimm), o_setting); + } + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for attrEngineTraits +/// @class attrEngineTraits +/// @note attrEngineTraits, DRAM_TRP specialization +/// +template<> +struct attrEngineTraits<attr_eff_engine_fields, DRAM_TRP> +{ + using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TRP_Type; + using attr_integral_type = std::remove_all_extents<attr_type>::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TRP_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TRP; + + /// + /// @brief attribute getter + /// @param[in] i_target the attr target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& o_setting) + { + return mss::attr::get_dram_trp(i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the attr target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& i_setting) + { + return mss::attr::set_dram_trp(i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[out] o_setting value we want to set attr with + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data, + attr_integral_type& o_setting) + { + const auto& l_dimm = i_spd_data.get_dimm_target(); + int64_t l_tck_in_ps = 0; + uint64_t l_freq = 0; + int64_t l_trp_in_ps = 0; + + FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) ); + FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), + "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) ); + + // Calculate tRP (in ps) + { + int64_t l_ftb = 0; + int64_t l_mtb = 0; + int64_t l_trp_mtb = 0; + int64_t l_trp_ftb = 0; + + FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) ); + FAPI_TRY( i_spd_data.min_trp(l_trp_mtb), + "%s Failed min_trp()", spd::c_str(l_dimm) ); + + FAPI_TRY( i_spd_data.fine_offset_min_trp(l_trp_ftb), + "%s Failed fine_offset_min_trp()", spd::c_str(l_dimm) ); + + FAPI_INF("%s medium timebase (ps): %ld, fine timebase (ps): %ld, tRP (MTB): %ld, tRP(FTB): %ld", + spd::c_str(l_dimm), l_mtb, l_ftb, l_trp_mtb, l_trp_ftb); + + l_trp_in_ps = spd::calc_timing_from_timebase(l_trp_mtb, l_mtb, l_trp_ftb, l_ftb); + } + + // SPD spec gives us the minimum... compute our worstcase (maximum) from JEDEC + { + // Declaring as int64_t to fix std::max compile + const int64_t l_trp = mss::ps_to_cycles(l_tck_in_ps, mss::trtp()); + l_trp_in_ps = std::max(l_trp_in_ps, l_trp); + } + + { + uint8_t l_trp_in_nck = 0; + + // Calculate nck + FAPI_TRY( spd::calc_nck(l_trp_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_trp_in_nck), + "%s Error in calculating dram_tRP nck, with value of l_trp_in_ps: %d", + spd::c_str(l_dimm), l_trp_in_ps); + + FAPI_INF( "%s tCK (ps): %d, tRP (ps): %d, tRP (nck): %d", + spd::c_str(l_dimm), l_tck_in_ps, l_trp_in_ps, l_trp_in_nck ); + + o_setting = l_trp_in_nck; + FAPI_DBG("%s DRAM TRP %d", spd::c_str(l_dimm), o_setting); + } + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for attrEngineTraits +/// @class attrEngineTraits +/// @note attrEngineTraits, DRAM_TRAS specialization +/// +template<> +struct attrEngineTraits<attr_eff_engine_fields, DRAM_TRAS> +{ + using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TRAS_Type; + using attr_integral_type = std::remove_all_extents<attr_type>::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TRAS_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TRAS; + + /// + /// @brief attribute getter + /// @param[in] i_target the attr target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& o_setting) + { + return mss::attr::get_dram_tras(i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the attr target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& i_setting) + { + return mss::attr::set_dram_tras(i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[out] o_setting value we want to set attr with + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data, + attr_integral_type& o_setting) + { + const auto& l_dimm = i_spd_data.get_dimm_target(); + int64_t l_tck_in_ps = 0; + uint64_t l_freq = 0; + uint64_t l_tras_in_ps = 0; + uint8_t l_tras_in_nck = 0; + + // tRAS is bin independent so we don't read this from SPD + // which will give the best timing value for the dimm + // (like 2400 MT/s) which may be different than the system + // speed (if we were being limited by VPD or MRW restrictions) + FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) ); + l_tras_in_ps = mss::tras(l_dimm, l_freq); + + FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), + "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) ); + + // Cast needed for calculations to be done on the same integral type + // as required by template deduction. We have l_tck_in_ps as a signed + // integer because we have other timing values that calculations do + // addition with negative integers. + FAPI_TRY( spd::calc_nck(l_tras_in_ps, + static_cast<uint64_t>(l_tck_in_ps), + spd::INVERSE_DDR4_CORRECTION_FACTOR, + l_tras_in_nck), + "%s Error in calculating tras_l, with value of l_twtr_in_ps: %d", + spd::c_str(l_dimm), l_tras_in_ps); + + FAPI_INF("%s tCK (ps): %d, tRAS (ps): %d, tRAS (nck): %d", + spd::c_str(l_dimm), l_tck_in_ps, l_tras_in_ps, l_tras_in_nck); + + o_setting = l_tras_in_nck; + FAPI_DBG("%s DRAM TRAS %d", spd::c_str(l_dimm), o_setting); + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for attrEngineTraits +/// @class attrEngineTraits +/// @note attrEngineTraits, DRAM_TWR specialization +/// +template<> +struct attrEngineTraits<attr_eff_engine_fields, DRAM_TWR> +{ + using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TWR_Type; + using attr_integral_type = std::remove_all_extents<attr_type>::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TWR_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TWR; + + /// + /// @brief attribute getter + /// @param[in] i_target the attr target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& o_setting) + { + return mss::attr::get_dram_twr(i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the attr target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& i_setting) + { + return mss::attr::set_dram_twr(i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[out] o_setting value we want to set attr with + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data, + attr_integral_type& o_setting) + { + const auto& l_dimm = i_spd_data.get_dimm_target(); + int64_t l_tck_in_ps = 0; + uint64_t l_freq = 0; + int64_t l_twr_in_ps = 0; + + FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) ); + FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), + "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) ); + + // Get the tWR timing values + // tWR is speed bin independent and is + // the same for all bins within a speed grade. + // It is safe to read this from SPD because the correct nck + // value will be calulated based on our dimm speed. + { + constexpr int64_t l_twr_ftb = 0; + int64_t l_twr_mtb = 0; + int64_t l_ftb = 0; + int64_t l_mtb = 0; + + FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) ); + + FAPI_TRY( i_spd_data.min_twr(l_twr_mtb), + "%s Failed min_twr()", spd::c_str(l_dimm) ); + + FAPI_INF("%s medium timebase (ps): %ld, fine timebase (ps): %ld, tWR (MTB): %ld, tWR(FTB): %ld", + spd::c_str(l_dimm), l_mtb, l_ftb, l_twr_mtb, l_twr_ftb); + + // Calculate twr (in ps) + l_twr_in_ps = spd::calc_timing_from_timebase(l_twr_mtb, l_mtb, l_twr_ftb, l_ftb); + } + + { + uint8_t l_twr_in_nck = 0; + + // Calculate tNCK + FAPI_TRY( spd::calc_nck(l_twr_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_twr_in_nck), + "%s Error in calculating l_twr_in_nck, with value of l_twr_in_ps: %d", spd::c_str(l_dimm), l_twr_in_ps); + + FAPI_INF( "%s tCK (ps): %d, tWR (ps): %d, tWR (nck): %d", + spd::c_str(l_dimm), l_tck_in_ps, l_twr_in_ps, l_twr_in_nck ); + + o_setting = l_twr_in_nck; + FAPI_DBG("%s DRAM TWR %d", spd::c_str(l_dimm), o_setting); + } + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for attrEngineTraits +/// @class attrEngineTraits +/// @note attrEngineTraits, DRAM_TRTP specialization +/// +template<> +struct attrEngineTraits<attr_eff_engine_fields, DRAM_TRTP> +{ + using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TRTP_Type; + using attr_integral_type = std::remove_all_extents<attr_type>::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TRTP_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TRTP; + + /// + /// @brief attribute getter + /// @param[in] i_target the attr target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& o_setting) + { + return mss::attr::get_dram_trtp(i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the attr target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& i_setting) + { + return mss::attr::set_dram_trtp(i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[out] o_setting value we want to set attr with + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data, + attr_integral_type& o_setting) + { + const auto& l_dimm = i_spd_data.get_dimm_target(); + int64_t l_tck_in_ps = 0; + uint64_t l_freq = 0; + + // Values from proposed DDR4 Full spec update(79-4A) + // Item No. 1716.78C + // Page 241 & 246 + constexpr int64_t l_max_trtp_in_ps = trtp(); + uint8_t l_calc_trtp_in_nck = 0; + + FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) ); + FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), + "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) ); + + // Calculate nck + FAPI_TRY( spd::calc_nck(l_max_trtp_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_calc_trtp_in_nck), + "%s Error in calculating trtp, with value of l_twtr_in_ps: %d", + spd::c_str(l_dimm), l_max_trtp_in_ps); + + FAPI_INF("%s tCK (ps): %d, tRTP (ps): %d, tRTP (nck): %d", + spd::c_str(l_dimm), l_tck_in_ps, l_max_trtp_in_ps, l_calc_trtp_in_nck); + + o_setting = l_calc_trtp_in_nck; + FAPI_DBG("%s DRAM TRTP %d", spd::c_str(l_dimm), o_setting); + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for attrEngineTraits +/// @class attrEngineTraits +/// @note attrEngineTraits, DRAM_TRRD_S specialization +/// +template<> +struct attrEngineTraits<attr_eff_engine_fields, DRAM_TRRD_S> +{ + using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TRRD_S_Type; + using attr_integral_type = std::remove_all_extents<attr_type>::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TRRD_S_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TRRD_S; + + /// + /// @brief attribute getter + /// @param[in] i_target the attr target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& o_setting) + { + return mss::attr::get_dram_trrd_s(i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the attr target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& i_setting) + { + return mss::attr::set_dram_trrd_s(i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[out] o_setting value we want to set attr with + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data, + attr_integral_type& o_setting) + { + const auto& l_dimm = i_spd_data.get_dimm_target(); + int64_t l_tck_in_ps = 0; + uint64_t l_freq = 0; + uint64_t l_trrd_s_in_nck = 0; + int64_t l_trrd_s_in_ps = 0; + uint64_t l_jedec_trrd = 0; + uint8_t l_dram_width = 0; + + FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) ); + FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), + "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) ); + + // Calculate tRRD_S + { + int64_t l_trrd_s_mtb = 0; + int64_t l_trrd_s_ftb = 0; + int64_t l_ftb = 0; + int64_t l_mtb = 0; + + FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) ); + + FAPI_TRY( i_spd_data.min_trrd_s(l_trrd_s_mtb), + "%s Failed min_trrd_s()", spd::c_str(l_dimm) ); + + FAPI_TRY( i_spd_data.fine_offset_min_trrd_s(l_trrd_s_ftb), + "%s Failed fine_offset_min_trrd_s()", spd::c_str(l_dimm) ); + + FAPI_INF("%s medium timebase (ps): %ld, fine timebase (ps): %ld, trrd_s (MTB): %ld", + spd::c_str(l_dimm), l_mtb, l_ftb, l_trrd_s_mtb); + + l_trrd_s_in_ps = spd::calc_timing_from_timebase(l_trrd_s_mtb, l_mtb, l_trrd_s_ftb, l_ftb); + + FAPI_ASSERT( l_trrd_s_in_ps >= 0, + fapi2::MSS_INVALID_TIMING_VALUE() + .set_VALUE(l_trrd_s_in_ps) + .set_DIMM_TARGET(l_dimm) + .set_FUNCTION(TRRD_S), + "%s Error calculating tRRD_S (%d). Less than or equal to 0", + spd::c_str(l_dimm), + l_trrd_s_in_ps); + + FAPI_DBG("%s TRRD_S in ps is %d", spd::c_str(l_dimm), l_trrd_s_in_ps); + + FAPI_TRY( spd::calc_nck(l_trrd_s_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_trrd_s_in_nck), + "%s Error in calculating l_tRRD_S, with value of l_trrd_s_in_ps: %d", + spd::c_str(l_dimm), + l_trrd_s_in_nck); + } + + FAPI_TRY( attr::get_dram_width(l_dimm, l_dram_width) ); + FAPI_TRY( trrd_s( l_dimm, l_dram_width, l_freq, l_jedec_trrd) ); + + // Taking the worst case between the required minimum JEDEC value and the proposed value from SPD + if (l_jedec_trrd != l_trrd_s_in_nck) + { + FAPI_INF("%s TRRD_S from JEDEC (%d) and from SPD (%d) don't match. Choosing worst case. dram width %d, freq %d", + spd::c_str(l_dimm), + l_jedec_trrd, + l_trrd_s_in_nck, + l_dram_width, + l_freq); + + l_trrd_s_in_nck = std::max( l_jedec_trrd, l_trrd_s_in_nck); + } + + FAPI_INF("%s SDRAM width: %d, tRRD_S (nck): %d", + spd::c_str(l_dimm), l_dram_width, l_trrd_s_in_nck); + + o_setting = l_trrd_s_in_nck; + FAPI_DBG("%s DRAM TRRD_S %d", spd::c_str(l_dimm), o_setting); + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for attrEngineTraits +/// @class attrEngineTraits +/// @note attrEngineTraits, DRAM_TRRD_L specialization +/// +template<> +struct attrEngineTraits<attr_eff_engine_fields, DRAM_TRRD_L> +{ + using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TRRD_L_Type; + using attr_integral_type = std::remove_all_extents<attr_type>::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TRRD_L_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TRRD_L; + + /// + /// @brief attribute getter + /// @param[in] i_target the attr target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& o_setting) + { + return mss::attr::get_dram_trrd_l(i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the attr target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& i_setting) + { + return mss::attr::set_dram_trrd_l(i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[out] o_setting value we want to set attr with + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data, + attr_integral_type& o_setting) + { + const auto& l_dimm = i_spd_data.get_dimm_target(); + int64_t l_tck_in_ps = 0; + uint64_t l_freq = 0; + uint64_t l_trrd_l_in_nck = 0; + int64_t l_trrd_l_in_ps = 0; + uint64_t l_jedec_trrd = 0; + uint8_t l_dram_width = 0; + + FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) ); + FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), + "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) ); + + // Calculate tRRD_L + { + int64_t l_trrd_l_mtb = 0; + int64_t l_trrd_l_ftb = 0; + int64_t l_ftb = 0; + int64_t l_mtb = 0; + + FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) ); + + FAPI_TRY( i_spd_data.min_trrd_l(l_trrd_l_mtb), + "%s Failed min_trrd_l()", spd::c_str(l_dimm) ); + + FAPI_TRY( i_spd_data.fine_offset_min_trrd_l(l_trrd_l_ftb), + "%s Failed fine_offset_min_trrd_l()", spd::c_str(l_dimm) ); + + FAPI_INF("%s medium timebase (ps): %ld, fine timebase (ps): %ld, trrd_l (MTB): %ld", + spd::c_str(l_dimm), l_mtb, l_ftb, l_trrd_l_mtb); + + l_trrd_l_in_ps = spd::calc_timing_from_timebase(l_trrd_l_mtb, l_mtb, l_trrd_l_ftb, l_ftb); + + FAPI_ASSERT( l_trrd_l_in_ps >= 0, + fapi2::MSS_INVALID_TIMING_VALUE() + .set_VALUE(l_trrd_l_in_ps) + .set_DIMM_TARGET(l_dimm) + .set_FUNCTION(TRRD_L), + "%s Error calculating tRRD_L (%d). Less than or equal to 0", + spd::c_str(l_dimm), + l_trrd_l_in_ps); + + FAPI_DBG("%s TRRD_L in ps is %d", spd::c_str(l_dimm), l_trrd_l_in_ps); + + FAPI_TRY( spd::calc_nck(l_trrd_l_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_trrd_l_in_nck), + "%s Error in calculating l_tRRD_L, with value of l_trrd_l_in_ps: %d", + spd::c_str(l_dimm), + l_trrd_l_in_nck); + } + + FAPI_TRY( attr::get_dram_width(l_dimm, l_dram_width) ); + FAPI_TRY( trrd_l( l_dimm, l_dram_width, l_freq, l_jedec_trrd) ); + + // Taking the worst case between the required minimum JEDEC value and the proposed value from SPD + if (l_jedec_trrd != l_trrd_l_in_nck) + { + FAPI_INF("%s TRRD_L from JEDEC (%d) and from SPD (%d) don't match. Choosing worst case. dram width %d, freq %d", + spd::c_str(l_dimm), + l_jedec_trrd, + l_trrd_l_in_nck, + l_dram_width, + l_freq); + + l_trrd_l_in_nck = std::max( l_jedec_trrd, l_trrd_l_in_nck); + } + + FAPI_INF("%s SDRAM width: %d, tRRD_L (nck): %d", + spd::c_str(l_dimm), l_dram_width, l_trrd_l_in_nck); + + o_setting = l_trrd_l_in_nck; + FAPI_DBG("%s DRAM TRRD_L %d", spd::c_str(l_dimm), o_setting); + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for attrEngineTraits +/// @class attrEngineTraits +/// @note attrEngineTraits, DRAM_TRFC specialization +/// +template<> +struct attrEngineTraits<attr_eff_engine_fields, DRAM_TRFC> +{ + using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TRFC_Type; + using attr_integral_type = std::remove_all_extents<attr_type>::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TRFC_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TRFC; + + /// + /// @brief attribute getter + /// @param[in] i_target the attr target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& o_setting) + { + return mss::attr::get_dram_trfc(i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the attr target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& i_setting) + { + return mss::attr::set_dram_trfc(i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[out] o_setting value we want to set attr with + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data, + attr_integral_type& o_setting) + { + const auto& l_dimm = i_spd_data.get_dimm_target(); + int64_t l_tck_in_ps = 0; + uint64_t l_freq = 0; + uint8_t l_refresh_mode = 0; + int64_t l_trfc_mtb = 0; + int64_t l_trfc_in_ps = 0; + + FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) ); + FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), + "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) ); + + FAPI_TRY( mss::attr::get_mrw_fine_refresh_mode(l_refresh_mode) ); + + // Selects appropriate tRFC based on fine refresh mode + switch(l_refresh_mode) + { + case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_NORMAL: + FAPI_TRY( i_spd_data.min_trfc1(l_trfc_mtb), + "%s Failed to decode SPD for tRFC1", spd::c_str(l_dimm) ); + break; + + case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_2X: + case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_2X: + FAPI_TRY( i_spd_data.min_trfc2(l_trfc_mtb), + "%s Failed to decode SPD for tRFC2", spd::c_str(l_dimm) ); + break; + + case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_4X: + case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_4X: + FAPI_TRY( i_spd_data.min_trfc4(l_trfc_mtb), + "%s Failed to decode SPD for tRFC4", spd::c_str(l_dimm) ); + break; + + default: + // Fine Refresh Mode will be a platform attribute set by the MRW, + // which they "shouldn't" mess up as long as use "attribute" enums. + // if openpower messes this up we can at least catch it + FAPI_ASSERT(false, + fapi2::MSS_INVALID_FINE_REFRESH_MODE(). + set_FINE_REF_MODE(l_refresh_mode), + "%s Incorrect Fine Refresh Mode received: %d ", + spd::c_str(l_dimm), + l_refresh_mode); + break; + }// switch + + // Calculate trfc (in ps) + { + int64_t l_trfc_ftb = 0; + int64_t l_ftb = 0; + int64_t l_mtb = 0; + + FAPI_TRY( spd::get_timebases(i_spd_data, l_mtb, l_ftb) ); + + FAPI_INF( "%s medium timebase (ps): %ld, fine timebase (ps): %ld, tRFC (MTB): %ld, tRFC(FTB): %ld", + spd::c_str(l_dimm), l_mtb, l_ftb, l_trfc_mtb, l_trfc_ftb ); + + l_trfc_in_ps = spd::calc_timing_from_timebase(l_trfc_mtb, l_mtb, l_trfc_ftb, l_ftb); + } + + { + // Calculate refresh cycle time in nCK & set attribute + + uint16_t l_trfc_in_nck = 0; + + // Calculate nck + FAPI_TRY( spd::calc_nck(l_trfc_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_trfc_in_nck), + "%s Error in calculating l_tRFC, with value of l_trfc_in_ps: %d", spd::c_str(l_dimm), l_trfc_in_ps); + + FAPI_INF("%s tCK (ps): %d, tRFC (ps): %d, tRFC (nck): %d", + spd::c_str(l_dimm), l_tck_in_ps, l_trfc_in_ps, l_trfc_in_nck); + + o_setting = l_trfc_in_nck; + FAPI_DBG("%s DRAM TRFC %d", spd::c_str(l_dimm), o_setting); + } + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for attrEngineTraits +/// @class attrEngineTraits +/// @note attrEngineTraits, DRAM_TRFC_DLR specialization +/// +template<> +struct attrEngineTraits<attr_eff_engine_fields, DRAM_TRFC_DLR> +{ + using attr_type = fapi2::ATTR_MEM_EFF_DRAM_TRFC_DLR_Type; + using attr_integral_type = std::remove_all_extents<attr_type>::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_TRFC_DLR_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_TRFC_DLR; + + /// + /// @brief attribute getter + /// @param[in] i_target the attr target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& o_setting) + { + return mss::attr::get_dram_trfc_dlr(i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the attr target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target<TARGET_TYPE>& i_target, + attr_type& i_setting) + { + return mss::attr::set_dram_trfc_dlr(i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[out] o_setting value we want to set attr with + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_value_to_set(const spd::facade& i_spd_data, + attr_integral_type& o_setting) + { + const auto& l_dimm = i_spd_data.get_dimm_target(); + int64_t l_tck_in_ps = 0; + uint64_t l_freq = 0; + uint8_t l_refresh_mode = 0; + uint8_t l_dram_density = 0; + uint64_t l_trfc_dlr_in_ps = 0; + uint8_t l_trfc_dlr_in_nck = 0; + + FAPI_TRY( attr::get_freq(mss::find_target<fapi2::TARGET_TYPE_MEM_PORT>(l_dimm), l_freq) ); + FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), + "%s Failed to calculate clock period (tCK)", spd::c_str(l_dimm) ); + + FAPI_TRY( mss::attr::get_mrw_fine_refresh_mode(l_refresh_mode) ); + FAPI_TRY( mss::attr::get_dram_density(l_dimm, l_dram_density) ); + + // Calculate refresh cycle time in ps + FAPI_TRY( calc_trfc_dlr(l_dimm, l_refresh_mode, l_dram_density, l_trfc_dlr_in_ps), + "%s Failed calc_trfc_dlr()", spd::c_str(l_dimm) ); + + // Calculate refresh cycle time in nck + FAPI_TRY( spd::calc_nck(l_trfc_dlr_in_ps, static_cast<uint64_t>(l_tck_in_ps), spd::INVERSE_DDR4_CORRECTION_FACTOR, + l_trfc_dlr_in_nck)); + + FAPI_INF("%s tCK (ps): %d, tRFC_DLR (ps): %d, tRFC_DLR (nck): %d", + spd::c_str(l_dimm), l_tck_in_ps, l_trfc_dlr_in_ps, l_trfc_dlr_in_nck); + + o_setting = l_trfc_dlr_in_nck; + FAPI_DBG("%s DRAM TRFC_DLR %d", spd::c_str(l_dimm), o_setting); + + fapi_try_exit: + return fapi2::current_err; + } +}; + }//mss #endif diff --git a/src/import/generic/memory/lib/data_engine/data_engine_traits_def.H b/src/import/generic/memory/lib/data_engine/data_engine_traits_def.H index 911821b5f..702e0db9a 100644 --- a/src/import/generic/memory/lib/data_engine/data_engine_traits_def.H +++ b/src/import/generic/memory/lib/data_engine/data_engine_traits_def.H @@ -93,13 +93,28 @@ enum attr_eff_engine_fields ATTR_EFF_BASE_CASE = 0, // Attrs to set - DRAM_WIDTH = 1, - PRIM_BUS_WIDTH = 2, - DRAM_DENSITY = 3, - PRIMARY_DIE_COUNT = 4, - PRIM_STACK_TYPE = 5, - COLUMN_ADDR_BITS = 6, - ROW_ADDR_BITS = 7, + DRAM_CWL = 1, + DRAM_TREFI = 2, + DRAM_TCCD_L = 3, + DRAM_TWTR_L = 4, + DRAM_TWTR_S = 5, + DRAM_TFAW = 6, + DRAM_TRCD = 7, + DRAM_TRP = 8, + DRAM_TRAS = 9, + DRAM_TWR = 10, + DRAM_TRTP = 11, + DRAM_TRRD_S = 12, + DRAM_TRRD_L = 13, + DRAM_TRFC = 14, + DRAM_TRFC_DLR = 15, + DRAM_WIDTH = 16, + PRIM_BUS_WIDTH = 17, + DRAM_DENSITY = 18, + PRIMARY_DIE_COUNT = 19, + PRIM_STACK_TYPE = 20, + COLUMN_ADDR_BITS = 21, + ROW_ADDR_BITS = 22, // Dispatcher set to last enum value ATTR_EFF_DISPATCHER = ROW_ADDR_BITS, diff --git a/src/import/generic/memory/lib/utils/conversions.H b/src/import/generic/memory/lib/utils/conversions.H index 5981fe7b5..dc4290ea5 100644 --- a/src/import/generic/memory/lib/utils/conversions.H +++ b/src/import/generic/memory/lib/utils/conversions.H @@ -101,7 +101,7 @@ static const std::vector<std::pair<uint64_t, uint64_t>> FREQ_TO_CLOCK_PERIOD = {DIMM_SPEED_4400, 454}, // DDR5 {DIMM_SPEED_4800, 416}, // DDR5 }; -} +} // ns dram_freq /// /// @brief Return the number of picoseconds diff --git a/src/import/generic/memory/lib/utils/dimm/mss_timing.H b/src/import/generic/memory/lib/utils/dimm/mss_timing.H index 54fac6474..aa1915e3d 100644 --- a/src/import/generic/memory/lib/utils/dimm/mss_timing.H +++ b/src/import/generic/memory/lib/utils/dimm/mss_timing.H @@ -22,3 +22,891 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ + +/// +/// @file mss_timing.H +/// @brief Determine effective config for mss settings +/// +// *HWP HWP Owner: Louis Stermole <stermole@us.ibm.com> +// *HWP FW Owner: Stephen Glancy <sglancy@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 3 +// *HWP Consumed by: HB:FSP + +#ifndef _MSS_GEN_TIMING_H_ +#define _MSS_GEN_TIMING_H_ + +#include <cstdint> +#include <fapi2.H> +#include <generic/memory/lib/mss_generic_attribute_getters.H> +#include <generic/memory/lib/utils/find.H> +#include <generic/memory/lib/utils/shared/mss_generic_consts.H> +#include <generic/memory/lib/utils/conversions.H> +#include <generic/memory/lib/spd/spd_utils.H> + +namespace mss +{ + +/// +/// @brief Enums for ffdc error callout so we know which function had the error +/// +enum timing_ffdc_codes +{ + TRAS = 0, + TFAW_HALF_KB_PAGE_HELPER = 1, + TFAW_ONE_KB_PAGE_HELPER = 2, + TFAW_TW_KB_PAGE_HELPER = 3, + TFAW_SLR_X4_HELPER = 4, + TFAW_SLR_X8_HELPER = 5, + TRRD_S_SLR = 6, + TRRD_L_SLR = 7, + TRRD_L_HALF_AND_1KB_PAGE_HELPER = 8, + TRRD_S_HALF_AND_1KB_PAGE_HELPER = 9, + TRRD_S_2KB_PAGE_HELPER = 10, + TRRD_S = 11, + TRRD_L = 12, + TFAW = 13, + TDLLK = 14, +}; + +enum refresh_rate : uint8_t +{ + REF1X = 1, ///< Refresh rate 1X + REF2X = 2, ///< Refresh rate 2X + REF4X = 4, ///< Refresh rate 4X +}; + +namespace spd +{ + +/// +/// @brief Returns clock cycles form picoseconds based on speed bin +/// Uses SPD rounding algorithm for DDR4 +/// @tparam OT the output type, derrived from the parameters +/// @param[in] i_freq frequency of the DIMM +/// @param[in] timing_in_ps timing parameter in ps +/// @return the clock cycles of timing parameter (provided in ps) +/// @note Uses DDR4 SPD Contents Rounding Algorithm +/// @note Item 2220.46 +/// +template<typename OT> +inline OT ps_to_nck( const uint64_t i_freq, const OT& i_timing_in_ps) +{ + OT l_tck_in_ps = 0; + OT l_temp_nck = 0; + + // No time if MT/s is 0 (well, infinite really but shut up) + if (i_freq == 0) + { + return 0; + } + + FAPI_TRY( freq_to_ps(i_freq, l_tck_in_ps), + "Failed freq() accessor" ); + FAPI_TRY( calc_nck(i_timing_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, l_temp_nck), + "Failed calc_nck()" ); + + return l_temp_nck; + +fapi_try_exit: + // We simply can't work if we get an unsupported value that can't be converted to a valid tCK (clock period) + // ...so this should be ok + FAPI_ERR("Obtained an invalid MSS_FREQ (%d), or overflow occurred - stopping", i_freq); + fapi2::Assert(false); + + // Keeps compiler happy + return 0; +} + +/// +/// @brief Returns clock cycles from nanoseconds +/// Uses SPD rounding algorithm for DDR4 +/// @tparam OT the output type, derrived from the parameters +/// @param[in] i_freq frequency of the DIMM +/// @param[out] o_value_nck the end calculation in nck +/// @return the clock cycles of timing parameter (provided in ps) +/// @note Uses DDR4 SPD Contents Rounding Algorithm +/// @note Item 2220.46 +/// +template<typename OT> +inline OT ns_to_nck( const uint64_t i_freq, const OT& i_timing_in_ns) +{ + return ps_to_nck(i_freq, i_timing_in_ns * CONVERT_PS_IN_A_NS); +} + +}// spd + +/// +/// @brief Calculates refresh interval time +/// @param[in] i_mode fine refresh rate mode +/// @param[in] i_refresh_request_rate refresh rate +/// @param[out] o_value timing val in ps +/// @return fapi2::ReturnCode +/// +inline fapi2::ReturnCode calc_trefi( const refresh_rate i_mode, + const uint8_t i_refresh_request_rate, + uint64_t& o_timing ) +{ + // Proposed DDR4 Full spec update(79-4B) + // Item No. 1716.78C + // pg.46 + // Table 24 - tREFI and tRFC parameters (in ps) + constexpr uint64_t TREFI_BASE = 7800000; + + uint64_t l_refresh_request = 0; + constexpr double TEN_PERCENT_FASTER = 0.90; + + switch(i_refresh_request_rate) + { + case fapi2::ENUM_ATTR_MSS_MRW_REFRESH_RATE_REQUEST_SINGLE: + l_refresh_request = TREFI_BASE; + break; + + case fapi2::ENUM_ATTR_MSS_MRW_REFRESH_RATE_REQUEST_DOUBLE: + // We are truncating but there is no remainder with TREFI_BASE, so we are okay + l_refresh_request = TREFI_BASE / 2; + break; + + case fapi2::ENUM_ATTR_MSS_MRW_REFRESH_RATE_REQUEST_SINGLE_10_PERCENT_FASTER: + // We are truncating but there is no remainder with TREFI_BASE, so we are okay + // 10% faster so 100% - 10% = 90% + l_refresh_request = TREFI_BASE * TEN_PERCENT_FASTER; + break; + + case fapi2::ENUM_ATTR_MSS_MRW_REFRESH_RATE_REQUEST_DOUBLE_10_PERCENT_FASTER: + // We are truncating but there is no remainder with TREFI_BASE, so we are okay + // 10% faster so 100% - 10% = 90% + l_refresh_request = (TREFI_BASE / 2) * TEN_PERCENT_FASTER; + break; + + default: + // Will catch incorrect MRW value set + FAPI_ASSERT(false, + fapi2::MSS_INVALID_REFRESH_RATE_REQUEST().set_REFRESH_RATE_REQUEST(i_refresh_request_rate), + "Incorrect refresh request rate received: %d ", i_refresh_request_rate); + break; + } + + o_timing = (l_refresh_request / i_mode); + + FAPI_INF( "tREFI (ps): %d, refresh request (ps): %d, tREFI_base (ps): %d, REF%dX", + o_timing, l_refresh_request, TREFI_BASE, i_mode ); + + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + return fapi2::current_err; +} + +/// @brief Calculates Minimum Refresh Recovery Delay Time (different logical rank) +/// @param[in] i_mode fine refresh rate mode +/// @param[in] i_density SDRAM density +/// @param[out] o_trfc_in_ps timing val in ps +/// @return fapi2::FAPI2_RC_SUCCESS iff okay +/// +inline fapi2::ReturnCode calc_trfc_dlr(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + const uint8_t i_refresh_mode, + const uint8_t i_density, + uint64_t& o_trfc_in_ps) +{ + // Proposed DDR4 3DS Addendum + // Item No. 1727.58A + // pg. 69 - 71 + // Table 42 - Refresh parameters by logical rank density + static const std::vector<std::pair<uint8_t, uint64_t> > TRFC_DLR1 = + { + // { density in GBs, tRFC4(min) in picoseconds } + {4, 90000}, + {8, 120000}, + {16, 185000}, + }; + + // Proposed DDR4 3DS Addendum + // Item No. 1727.58A + // pg. 69 - 71 + // Table 42 - Refresh parameters by logical rank density + static const std::vector<std::pair<uint8_t, uint64_t> > TRFC_DLR2 = + { + // { density in GBs, tRFC4(min) in picoseconds } + {4, 55000}, + {8, 90000}, + {16, 120000}, + }; + + // Proposed DDR4 3DS Addendum + // Item No. 1727.58A + // pg. 69 - 71 + // Table 42 - Refresh parameters by logical rank density + static const std::vector<std::pair<uint8_t, uint64_t> > TRFC_DLR4 = + { + // { density in GBs, tRFC4(min) in picoseconds } + {4, 40000}, + {8, 55000}, + {16, 90000}, + }; + + bool l_is_val_found = 0; + + // Selects appropriate tRFC based on fine refresh mode + switch(i_refresh_mode) + { + case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_NORMAL: + l_is_val_found = find_value_from_key(TRFC_DLR1, i_density, o_trfc_in_ps); + break; + + case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_2X: + case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_2X: + l_is_val_found = find_value_from_key(TRFC_DLR2, i_density, o_trfc_in_ps); + break; + + case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_4X: + case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_4X: + l_is_val_found = find_value_from_key(TRFC_DLR4, i_density, o_trfc_in_ps); + break; + + default: + // Fine Refresh Mode will be a platform attribute set by the MRW, + // which they "shouldn't" mess up as long as use "attribute" enums. + // if openpower messes this up we can at least catch it + FAPI_ASSERT( false, + fapi2::MSS_INVALID_FINE_REFRESH() + .set_REFRESH_MODE(i_refresh_mode), + "Incorrect Fine Refresh Mode received: %d ", + i_refresh_mode); + break; + }// switch + + FAPI_ASSERT( l_is_val_found, + fapi2::MSS_FAILED_TO_FIND_TRFC() + .set_SDRAM_DENSITY(i_density) + .set_REFRESH_MODE(i_refresh_mode) + .set_DIMM_TARGET(i_target), + "%s: Unable to find tRFC (ps) from map with SDRAM density key %d with %d refresh mode", + mss::c_str(i_target), + i_density, + i_refresh_mode); + + // Again, FAPI_ASSERT doesn't set current_err to good, only to bad + return fapi2::FAPI2_RC_SUCCESS; +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief tRTP *in ps* +/// @return constexpr value of RTP = 7500 ps +/// +constexpr uint64_t trtp() +{ + // Per JEDEC spec, defaults to 7500 ps for all frequencies. + // (technically max of 7.5 ns or 4 nclk, which is always 7.5ns for DDR4) + return 7500; +} + +/// +/// @brief Return the minimum allowable tRAS in picoseconds +/// @param[in] i_target the fapi2 target +/// @param[in] i_freq freq for the DIMM +/// @return value in picoseconds +/// +inline uint64_t tras(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + const uint64_t i_freq) +{ + uint64_t l_tras = 0; + + switch(i_freq) + { + case 1866: + l_tras = 34000; + break; + + case 2133: + l_tras = 33000; + break; + + case 2400: + case 2666: + case 2933: + case 3200: + l_tras = 32000; + break; + + default: + FAPI_ASSERT( false, + fapi2::MSS_INVALID_FREQ_PASSED_IN() + .set_FREQ(i_freq) + .set_FUNCTION(TRAS) + .set_DIMM_TARGET(i_target), + "%s Invalid frequency %lu", + mss::c_str(i_target), + i_freq); + } + + return l_tras; + +fapi_try_exit: + + // We simply can't work if we can't get the frequency or + // if we get an unsupported value that can't be converted to a valid tCK (clock period) + // ...so this should be ok + FAPI_ERR("Obtained an invalid MSS_FREQ (%d) - stopping", i_freq); + fapi2::Assert(false); + + // Keeps compiler happy + return 0; +} + +/// +/// @brief Helper function to find tFAW based speed (MT/s) for 1/2 KB page +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[in] i_freq the DRAM frequency +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +static fapi2::ReturnCode tfaw_half_kb_page_helper(const fapi2::Target<T>& i_target, + const uint64_t i_freq, + uint64_t& o_output) +{ + // Values derived from DDR4 Spec (79-4A) + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability. + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + switch(i_freq) + { + // static_cast is needed for template deduction of std::max API + case 1866: + o_output = std::max( 16, spd::ps_to_nck(i_freq, 17000) ); + break; + + case 2133: + o_output = std::max( 16, spd::ps_to_nck(i_freq, 15000) ); + break; + + case 2400: + o_output = std::max( 16, spd::ps_to_nck(i_freq, 13000) ); + break; + + case 2666: + o_output = std::max( 16, spd::ps_to_nck(i_freq, 12000) ); + break; + + case 2933: + o_output = std::max( 16, spd::ps_to_nck(i_freq, 10875) ); + break; + + case 3200: + o_output = std::max( 16, spd::ps_to_nck(i_freq, 10000) ); + break; + + default: + FAPI_ASSERT( false, + fapi2::MSS_INVALID_FREQ_PASSED_IN() + .set_FREQ(i_freq) + .set_FUNCTION(TFAW_HALF_KB_PAGE_HELPER) + .set_DIMM_TARGET(i_target), + "%s Invalid frequency %lu", + mss::c_str(i_target), + i_freq); + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Helper function to find tFAW based speed (MT/s) for 1KB page +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[in] i_freq the DRAM frequency +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +static fapi2::ReturnCode tfaw_1kb_page_helper(const fapi2::Target<T>& i_target, + const uint64_t i_freq, + uint64_t& o_output) +{ + // Values derived from DDR4 Spec (79-4A) + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability (and ease of debug?). + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + switch(i_freq) + { + case 1866: + o_output = std::max( 20, spd::ns_to_nck(i_freq, 23) ); + break; + + case 2133: + case 2400: + case 2666: + case 2933: + case 3200: + o_output = std::max( 20, spd::ns_to_nck(i_freq, 21) ); + break; + + default: + FAPI_ASSERT( false, + fapi2::MSS_INVALID_FREQ_PASSED_IN() + .set_FREQ(i_freq) + .set_FUNCTION(TFAW_ONE_KB_PAGE_HELPER) + .set_DIMM_TARGET(i_target), + "%s Invalid frequency %lu", + mss::c_str(i_target), + i_freq); + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Helper function to find tFAW based speed (MT/s) for 2KB page +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[in] i_freq the DRAM frequency +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +static fapi2::ReturnCode tfaw_2kb_page_helper(const fapi2::Target<T>& i_target, + const uint64_t i_freq, + uint64_t& o_output) +{ + + // Values derived from DDR4 Spec (79-4A) + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability. + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + switch(i_freq) + { + case 1866: + case 2133: + case 2400: + case 2666: + case 2933: + case 3200: + o_output = std::max( 28, spd::ns_to_nck(i_freq, 30) ); + break; + + default: + FAPI_ASSERT( false, + fapi2::MSS_INVALID_FREQ_PASSED_IN() + .set_FREQ(i_freq) + .set_FUNCTION(TFAW_TW_KB_PAGE_HELPER) + .set_DIMM_TARGET(i_target), + "%s Invalid frequency %lu", + mss::c_str(i_target), + i_freq); + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Return the minimum allowable tFAW in nck +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[in] i_dram_width the page size +/// @param[in] i_freq the DRAM frequency +/// @param[out] o_tFAW timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +// +template< fapi2::TargetType T > +fapi2::ReturnCode tfaw( const fapi2::Target<T>& i_target, + const uint8_t i_dram_width, + const uint64_t i_freq, + uint64_t& o_tFAW ) +{ + switch(i_dram_width) + { + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X4: + FAPI_TRY( tfaw_half_kb_page_helper(i_target, i_freq, o_tFAW) ); + break; + + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8: + FAPI_TRY( tfaw_1kb_page_helper(i_target, i_freq, o_tFAW) ); + break; + + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X16: + FAPI_TRY( tfaw_2kb_page_helper(i_target, i_freq, o_tFAW) ); + break; + + default: + FAPI_ASSERT( false, + fapi2::MSS_INVALID_DRAM_WIDTH() + .set_DRAM_WIDTH(i_dram_width) + .set_DIMM_TARGET(i_target), + "Invalid DRAM width with %d for target %s", + i_dram_width, + mss::c_str(i_target)); + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief tFAW_dlr *in nck* +/// @return 16nck +/// @note From DDR4 3DS Spec +/// 12.2 Timing Parameters by Speed Grade +/// +constexpr uint64_t tfaw_dlr() +{ + return 16; +} + +/// +/// @brief tRRD_dlr *in nck* +/// @return 4nck +/// @note From DDR4 3DS Spec +/// 12.2 Timing Parameters by Speed Grade +/// +constexpr uint64_t trrd_dlr() +{ + return 4; +} + +/// +/// @brief Helper function to find tRRD_L based speed (MT/s) for 1KB page +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[in] i_freq the DRAM frequency +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +static fapi2::ReturnCode trrd_l_half_and_1kb_page_helper(const fapi2::Target<T>& i_target, + const uint64_t i_freq, + uint64_t& o_output) +{ + // Values derived from DDR4 Spec (79-4A) + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability (and ease of debug?). + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + switch(i_freq) + { + case 1866: + case 2133: + // From the spec: Max(4nCK,5.3ns) + o_output = std::max( 4, spd::ps_to_nck(i_freq, 5300) ); + break; + + case 2400: + case 2666: + case 2933: + case 3200: + // Max(4nCK,4.9ns) + o_output = std::max( 4, spd::ps_to_nck(i_freq, 4900) ); + break; + + default: + FAPI_ASSERT( false, + fapi2::MSS_INVALID_FREQ_PASSED_IN() + .set_FREQ(i_freq) + .set_FUNCTION(TRRD_L_HALF_AND_1KB_PAGE_HELPER) + .set_DIMM_TARGET(i_target), + "%s Invalid frequency %lu", + mss::c_str(i_target), + i_freq); + } + + return fapi2::FAPI2_RC_SUCCESS; +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Helper function to find tRRD_L based speed (MT/s) for 2KB page +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[in] i_freq the DRAM frequency +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +static fapi2::ReturnCode trrd_l_2kb_page_helper(const fapi2::Target<T>& i_target, + const uint64_t i_freq, + uint64_t& o_output) +{ + + // Values derived from DDR4 Spec (79-4A) + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability (and ease of debug?). + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + switch(i_freq) + { + case 1866: + case 2133: + case 2400: + case 2666: + case 2933: + case 3200: + o_output = std::max( 4, spd::ps_to_nck(i_freq, 6400) ); + break; + + default: + FAPI_TRY(fapi2::FAPI2_RC_INVALID_PARAMETER, "%s Invalid frequency %lu", mss::c_str(i_target), i_freq); + break; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Return the minimum allowable tRRD_L in nck +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[in] i_dram_width the page size +/// @param[in] i_freq the DRAM frequency +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +fapi2::ReturnCode trrd_l( const fapi2::Target<T>& i_target, + const uint8_t i_dram_width, + const uint64_t i_freq, + uint64_t& o_tRRD_L ) +{ + switch(i_dram_width) + { + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X4: + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8: + FAPI_TRY( trrd_l_half_and_1kb_page_helper(i_target, i_freq, o_tRRD_L), + "Error calculating trrd l for half and 1kb page" ); + break; + + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X16: + FAPI_TRY( trrd_l_2kb_page_helper(i_target, i_freq, o_tRRD_L) ); + break; + + default: + FAPI_ASSERT( false, + fapi2::MSS_INVALID_PAGE_SIZE() + .set_DRAM_WIDTH(i_dram_width) + .set_DIMM_TARGET(i_target), + "%s Recieved an invalid page size: %lu", + mss::c_str(i_target), + i_dram_width); + break; + } + + return fapi2::FAPI2_RC_SUCCESS; +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Helper function to find tRRD_S based speed (MT/s) for 1KB page +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[in] i_freq the DRAM frequency +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +static fapi2::ReturnCode trrd_s_half_and_1kb_page_helper(const fapi2::Target<T>& i_target, + const uint64_t i_freq, + uint64_t& o_output) +{ + // Values derived from DDR4 Spec (79-4A) + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability (and ease of debug?). + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + switch(i_freq) + { + case 1866: + o_output = std::max( 4, spd::ps_to_nck(i_freq, 4200) ); + break; + + case 2133: + o_output = std::max( 4, spd::ps_to_nck(i_freq, 3700) ); + break; + + case 2400: + o_output = std::max( 4, spd::ps_to_nck(i_freq, 3300) ); + break; + + case 2666: + o_output = std::max( 4, spd::ps_to_nck(i_freq, 3000) ); + break; + + case 2933: + o_output = std::max( 4, spd::ps_to_nck(i_freq, 2700) ); + break; + + case 3200: + o_output = std::max( 4, spd::ps_to_nck(i_freq, 2500) ); + break; + + default: + FAPI_ASSERT( false, + fapi2::MSS_INVALID_FREQ_PASSED_IN() + .set_FREQ(i_freq) + .set_FUNCTION(TRRD_S_HALF_AND_1KB_PAGE_HELPER) + .set_DIMM_TARGET(i_target), + "%s Invalid frequency %lu", + mss::c_str(i_target), + i_freq); + } + + return fapi2::FAPI2_RC_SUCCESS; +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Helper function to find tRRD_S based speed (MT/s) for 2KB page +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[in] i_freq the DRAM frequency +/// @param[out] o_output timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +static fapi2::ReturnCode trrd_s_2kb_page_helper(const fapi2::Target<T>& i_target, + const uint64_t i_freq, + uint64_t& o_output) +{ + // Values derived from DDR4 Spec (79-4A) + // 13.3 Timing Parameters by Speed Grade + // Table 132. Pg 240 + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + // It could have been more "efficient" to hand-calculate the answer and + // use compile time constants to return the answer. To avoid magic + // numbers and to align (more closely) with the DDR4 JEDEC spec, + // we let the std library do the work for us for maintainability (and ease of debug?). + // Could have used compile-time constants to denote the numbers below + // but they are "random" and vary. + switch(i_freq) + { + case 1866: + case 2133: + case 2400: + case 2666: + case 2933: + case 3200: + o_output = std::max( 4, spd::ps_to_nck(i_freq, 5300) ); + break; + + default: + FAPI_ASSERT( false, + fapi2::MSS_INVALID_FREQ_PASSED_IN() + .set_FREQ(i_freq) + .set_FUNCTION(TRRD_S_2KB_PAGE_HELPER) + .set_DIMM_TARGET(i_target), + "%s Invalid frequency %lu", + mss::c_str(i_target), + i_freq); + break; + } + + return fapi2::FAPI2_RC_SUCCESS; +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Return the minimum allowable tRRD_S in nck +/// @tparam T the fapi2::TargetType of a type from which we can get MT/s +/// @param[in] i_target the fapi2 target +/// @param[in] i_dram_width the page size +/// @param[in] i_freq the DRAM frequency +/// @param[out] o_tRRD_S timing in clocks (nck) +/// @return FAPI2_RC_SUCCESS iff okay +/// @note this is only for non-3DS DIMM +/// +template< fapi2::TargetType T > +fapi2::ReturnCode trrd_s( const fapi2::Target<T>& i_target, + const uint8_t i_dram_width, + const uint64_t i_freq, + uint64_t& o_tRRD_S ) +{ + switch(i_dram_width) + { + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X4: + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8: + FAPI_TRY( trrd_s_half_and_1kb_page_helper(i_target, i_freq, o_tRRD_S), + "Error calculating trrd_s for half and 1kb page" ); + break; + + case fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X16: + FAPI_TRY( trrd_s_2kb_page_helper(i_target, i_freq, o_tRRD_S) ); + break; + + default: + FAPI_ASSERT( false, + fapi2::MSS_INVALID_PAGE_SIZE() + .set_DRAM_WIDTH(i_dram_width) + .set_DIMM_TARGET(i_target), + "%s Recieved an invalid page size: %lu", + mss::c_str(i_target), + i_dram_width); + break; + } + + return fapi2::FAPI2_RC_SUCCESS; +fapi_try_exit: + return fapi2::current_err; +} + +} // mss +#endif 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 09182bb70..37901f21b 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 @@ -223,6 +223,21 @@ enum generic_ffdc_codes SET_COL_ADDR_BITS = 0x1082, SET_ROW_ADDR_BITS = 0x1083, SET_3DS_HEIGHT = 0x1084, + SET_DRAM_CWL = 0x1085, + SET_DRAM_TREFI = 0x1086, + SET_DRAM_TCCD_L = 0x1087, + SET_DRAM_TWTR_L = 0x1088, + SET_DRAM_TWTR_S = 0x1089, + SET_DRAM_TFAW = 0x108A, + SET_DRAM_TRCD = 0x108B, + SET_DRAM_TRP = 0x108C, + SET_DRAM_TRAS = 0x108D, + SET_DRAM_TWR = 0x108E, + SET_DRAM_TRTP = 0x108F, + SET_DRAM_TRRD_S = 0x1090, + SET_DRAM_TRRD_L = 0x1091, + SET_DRAM_TRFC = 0x1092, + SET_DRAM_TRFC_DLR = 0x1093, // Power thermal functions 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 a3f26ca8d..eed7aff57 100644 --- a/src/import/generic/procedures/xml/error_info/generic_error.xml +++ b/src/import/generic/procedures/xml/error_info/generic_error.xml @@ -89,6 +89,26 @@ </hwpError> <hwpError> + <rc>RC_MSS_FAILED_TO_FIND_TRFC</rc> + <description> + Unable to find tRFC (ps) from map with SDRAM density key + </description> + <ffdc>SDRAM_DENSITY</ffdc> + <ffdc>REFRESH_MODE</ffdc> + <callout> + <target>DIMM_TARGET</target> + <priority>MEDIUM</priority> + </callout> + <deconfigure> + <target>DIMM_TARGET</target> + </deconfigure> + <callout> + <procedure>CODE</procedure> + <priority>HIGH</priority> + </callout> + </hwpError> + + <hwpError> <rc>RC_MSS_FREQ_CL_EXCEEDS_TAA_MAX</rc> <description> Calculated Cas Latency exceeds JEDEC value for TAA Max @@ -374,6 +394,18 @@ </hwpError> <hwpError> + <rc>RC_MSS_INVALID_FINE_REFRESH_MODE</rc> + <description> + Invalid fine refresh mode received from the mrw + </description> + <ffdc>FINE_REF_MODE</ffdc> + <callout> + <procedure>CODE</procedure> + <priority>HIGH</priority> + </callout> + </hwpError> + + <hwpError> <rc>RC_MSS_INVALID_HYBRID_MODULE</rc> <description> Received an invalid or unsupported hybrid media (SPD byte 3, bits [6:4]) @@ -425,6 +457,19 @@ </hwpError> <hwpError> + <rc>RC_MSS_INVALID_REFRESH_RATE_REQUEST</rc> + <description> + Invalid refresh request rate received. + Possibly due to bad MRW setting for ATTR_MSS_MRW_REFRESH_RATE_REQUEST. + </description> + <ffdc>REFRESH_RATE_REQUEST</ffdc> + <callout> + <procedure>CODE</procedure> + <priority>HIGH</priority> + </callout> + </hwpError> + + <hwpError> <rc>RC_MSS_INVALID_SPD_PARAMETER_RECEIVED</rc> <description> Unable to fall back SPD decoder to the highest decoded |