diff options
Diffstat (limited to 'src/import/generic/memory/lib/data_engine/attr_engine_traits.H')
-rw-r--r-- | src/import/generic/memory/lib/data_engine/attr_engine_traits.H | 1550 |
1 files changed, 1547 insertions, 3 deletions
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 |