From e5a493e300da10cd6fe39ecb2e614d63dd11b9fb Mon Sep 17 00:00:00 2001 From: Andre Marin Date: Wed, 27 Feb 2019 13:58:49 -0600 Subject: Add attribute engine algorithm for eff_config and pre_eff_config Change-Id: I8498c143109fa1d1a2c9ad5492476e72f51ba509 Original-Change-Id: I2c89e6da17511462afbc661680d19df18a4708f4 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/72962 Tested-by: FSP CI Jenkins Reviewed-by: Louis Stermole Tested-by: Jenkins Server Tested-by: HWSV CI Tested-by: Hostboot CI Reviewed-by: STEPHEN GLANCY Reviewed-by: Jennifer A. Stofer Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/74689 Tested-by: Jenkins OP Build CI Reviewed-by: Christian R. Geddes --- .../procedures/hwp/memory/lib/shared/exp_consts.H | 40 +- .../p9a/procedures/hwp/memory/p9a_mss_eff_config.C | 68 +++- .../procedures/hwp/memory/p9a_mss_eff_config.mk | 2 +- .../chips/p9a/procedures/hwp/memory/p9a_mss_freq.C | 29 +- .../generic/memory/lib/data_engine/data_engine.H | 217 ++++++++++ .../lib/data_engine/data_engine_traits_def.H | 94 ++++- .../memory/lib/data_engine/data_engine_utils.H | 334 +++++++++++++++- .../lib/data_engine/p9a/p9a_data_init_traits.H | 444 +++++++++++++++++++++ .../generic/memory/lib/data_engine/pre_data_init.H | 1 - .../memory/lib/mss_generic_attribute_getters.H | 65 ++- .../memory/lib/spd/ddimm/ddr4/ddimm_decoder_ddr4.H | 4 +- .../ddimm/ddr4/efd_ddr4_custom_microchip_decoder.H | 6 +- .../generic/memory/lib/spd/ddimm/efd_decoder.H | 19 +- .../generic/memory/lib/spd/ddimm/efd_factory.H | 8 +- .../generic_memory_eff_attributes.xml | 16 +- .../generic_memory_si_attributes.xml | 8 +- 16 files changed, 1314 insertions(+), 41 deletions(-) diff --git a/src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/shared/exp_consts.H b/src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/shared/exp_consts.H index 7b394b7aa..8d8944890 100644 --- a/src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/shared/exp_consts.H +++ b/src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/shared/exp_consts.H @@ -33,8 +33,8 @@ // *HWP Level: 2 // *HWP Consumed by: CI -#ifndef EXP_CONSTS_H -#define EXP_CONSTS_H +#ifndef MSS_EXP_CONSTS_H +#define MSS_EXP_CONSTS_H #include @@ -48,6 +48,30 @@ namespace exp constexpr uint32_t OCMB_ADDR_SHIFT = 3; +/// +/// @brief enum list of explorer eff attributes to set +/// +enum attr_eff_engine_fields +{ + // Template recursive base case + ATTR_EFF_BASE_CASE = 0, + + // Attrs to set + BYTE_ENABLES = 1, + NIBBLE_ENABLES = 2, + SPD_TAA_MIN = 3, + FOUR_RANK_MODE = 4, + DDP_COMPATIBILITY = 5, + TSV_8H_SUPPORT = 6, + PSTATES = 7, + MRAM_SUPPORT = 8, + HEIGHT_3DS = 9, + SPD_CL_SUPPORTED = 10, + + // Dispatcher set to last enum value + ATTR_EFF_DISPATCHER = SPD_CL_SUPPORTED, +}; + /// /// @brief common explorer sizes /// @@ -66,6 +90,18 @@ enum ffdc_codes EXP_I2C_SET_FIELD = 0x0001, READ_HOST_FW_RESPONSE_STRUCT = 0x0003, READ_SENSOR_CACHE_STRUCT = 0x0004, + + SET_BYTE_ENABLES = 0x1041, + SET_NIBBLE_ENABLES = 0x1042, + SET_TAA_MIN = 0x1043, + SET_FOUR_RANK_MODE = 0x1044, + SET_DDP_COMPATIBILITY = 0x1045, + SET_TSV_8H_SUPPORT = 0x1046, + SET_VREF_DQ_TRAIN_RANGE = 0x1047, + SET_PSTATES = 0x1048, + SET_MRAM_SUPPORT = 0x1049, + SET_3DS_HEIGHT = 0x1050, + SET_SPD_CL_SUPPORTED = 0x1051, }; namespace i2c diff --git a/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_eff_config.C b/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_eff_config.C index cfa7b80b3..8a1e0a877 100644 --- a/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_eff_config.C +++ b/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_eff_config.C @@ -34,8 +34,14 @@ // *HWP Consumed by: FSP:HB // fapi2 +#include #include - +#include +#include +#include +#include +#include +#include /// /// @brief Configure the attributes for each controller @@ -44,5 +50,63 @@ /// fapi2::ReturnCode p9a_mss_eff_config( const fapi2::Target& i_target ) { - return fapi2::FAPI2_RC_SUCCESS; + // Workaround until DIMM level attrs work + uint8_t l_ranks[mss::exp::MAX_DIMM_PER_PORT] = {}; + + // Get EFD size - should only need to do it once + const auto l_ocmb = mss::find_target(i_target); + fapi2::MemVpdData_t l_vpd_type(fapi2::EFD); + fapi2::VPDInfo l_vpd_info(l_vpd_type); + FAPI_TRY( fapi2::getVPD(l_ocmb, l_vpd_info, nullptr) ); + + FAPI_TRY( mss::attr::get_num_master_ranks_per_dimm(i_target, l_ranks) ); + + for(const auto& dimm : mss::find_targets(i_target)) + { + uint8_t l_dimm_index = 0; + uint64_t l_freq = 0; + FAPI_TRY( mss::attr::get_freq(mss::find_target(dimm), l_freq) ); + + // Quick hack to get the index until DIMM level attrs work + FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_REL_POS, dimm, l_dimm_index) ); + + for( auto rank = 0; rank < l_ranks[l_dimm_index]; ++rank ) + { + std::shared_ptr l_efd_data; + + // Get EFD data + l_vpd_info.iv_rank = rank; + l_vpd_info.iv_omi_freq_mhz = l_freq; + std::vector l_vpd_raw (l_vpd_info.iv_size, 0); + FAPI_TRY( fapi2::getVPD(l_ocmb, l_vpd_info, l_vpd_raw.data()) ); + + // Instantiate EFD decoder + FAPI_TRY( mss::efd::factory(l_ocmb, l_vpd_raw, l_vpd_info.iv_rank, l_efd_data) ); + + // Set up SI ATTRS + FAPI_TRY( mss::attr_si_engine::set(l_efd_data) ); + } + + { + std::vector l_raw_spd; + FAPI_TRY(mss::spd::get_raw_data(dimm, l_raw_spd)); + { + // Gets the SPD facade + fapi2::ReturnCode l_rc(fapi2::FAPI2_RC_SUCCESS); + mss::spd::facade l_spd_decoder(dimm, l_raw_spd, l_rc); + + // Checks that the facade was setup correctly + FAPI_TRY( l_rc, "Failed to initialize SPD facade for %s", mss::spd::c_str(dimm) ); + + // Set up generic SPD ATTRS + FAPI_TRY( mss::attr_eff_engine::set(l_spd_decoder) ); + + // Set up explorer SPD ATTRS + FAPI_TRY( mss::attr_eff_engine::set(l_spd_decoder) ); + } + } + }// dimm + +fapi_try_exit: + return fapi2::current_err; } diff --git a/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_eff_config.mk b/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_eff_config.mk index 94114e779..65e376f98 100644 --- a/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_eff_config.mk +++ b/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_eff_config.mk @@ -27,5 +27,5 @@ -include 00p9a_common.mk PROCEDURE=p9a_mss_eff_config -$(eval $(call ADD_MEMORY_INCDIRS,$(PROCEDURE))) +$(eval $(call ADD_P9A_MEMORY_INCDIRS,$(PROCEDURE))) $(call BUILD_PROCEDURE) diff --git a/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.C b/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.C index f0a06de0b..7591689e2 100644 --- a/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.C +++ b/src/import/chips/p9a/procedures/hwp/memory/p9a_mss_freq.C @@ -33,8 +33,11 @@ // *HWP Level: 1 // *HWP Consumed by: FSP:HB -// fapi2 #include +#include +#include +#include +#include /// /// @brief Calculate and save off DIMM frequencies @@ -43,5 +46,27 @@ /// fapi2::ReturnCode p9a_mss_freq( const fapi2::Target& i_target ) { - return fapi2::FAPI2_RC_SUCCESS; + // We will first set pre-eff_config attribes + for(const auto& d : mss::find_targets(i_target)) + { + std::vector l_raw_spd; + FAPI_TRY(mss::spd::get_raw_data(d, l_raw_spd)); + { + // Gets the SPD facade + fapi2::ReturnCode l_rc(fapi2::FAPI2_RC_SUCCESS); + mss::spd::facade l_spd_decoder(d, l_raw_spd, l_rc); + + // Checks that the facade was setup correctly + FAPI_TRY( l_rc, "Failed to initialize SPD facade for %s", mss::spd::c_str(d) ); + + FAPI_TRY( mss::attr_eff_engine::set(l_spd_decoder) ); + } + + // TK - Remove hard-code FREQ -- Should we have enums? Louis problem now + uint64_t HARDCODE_FREQ_LOUIS_REMOVE = 25600; + FAPI_TRY( mss::attr::set_freq(i_target, HARDCODE_FREQ_LOUIS_REMOVE) ); + }// dimm + +fapi_try_exit: + return fapi2::current_err; } diff --git a/src/import/generic/memory/lib/data_engine/data_engine.H b/src/import/generic/memory/lib/data_engine/data_engine.H index 471390306..6a7cbb437 100644 --- a/src/import/generic/memory/lib/data_engine/data_engine.H +++ b/src/import/generic/memory/lib/data_engine/data_engine.H @@ -22,3 +22,220 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ +/// +/// @file pre_data_init.H +/// @brief Class to set preliminary eff_config attributes +/// +// *HWP HWP Owner: Andre Marin +// *HWP FW Owner: Stephen Glancy +// *HWP Team: Memory +// *HWP Level: 2 +// *HWP Consumed by: HB:CI + +#ifndef _MSS_GEN_DATA_ENGINE_H_ +#define _MSS_GEN_DATA_ENGINE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mss +{ + +/// +/// @brief Alias for function pointer to spd_facade timing methods +/// +using spd_facade_fptr = fapi2::ReturnCode (spd::facade::*)(int64_t& o_timing_in_mtb) const; + +/// +/// @brief Algorithm to calculate SPD timings in nCK +/// @tparam ET SPD fields enumeration (e.g. attr_eff_engine_fields) +/// @tparam F SPD field +/// @tparam OT output type +/// @tparam TT defaulted to setTimingTraits +/// @param[in] i_spd the SPD data +/// @param[out] o_timing_in_ps SPD timing value in picoseconds +/// @return FAPI2_RC_SUCCESS iff okay +/// +template < typename ET, + ET F, + typename OT, + typename TT = setTimingTraits > +inline fapi2::ReturnCode calc_spd_time_in_ps(const spd::facade& i_spd, + OT& o_timing_in_ps) +{ + const auto l_dimm = i_spd.get_dimm_target(); + int64_t l_timing_mtb = 0; + int64_t l_timing_ftb = 0; + int64_t l_mtb = 0; + int64_t l_ftb = 0; + + FAPI_TRY( spd::get_timebases(i_spd, l_mtb, l_ftb) ); + + FAPI_TRY( (i_spd.*TT::get_timing_in_mtb)(l_timing_mtb), + "Failed to get % (in MTB) for %s", TT::TIMING_NAME, spd::c_str(l_dimm) ); + FAPI_TRY( (i_spd.*TT::get_timing_in_ftb)(l_timing_ftb), + "Failed to get %s (in FTB) for %s", TT::TIMING_NAME, spd::c_str(l_dimm) ); + + FAPI_DBG("%s medium timebase (ps): %ld, fine timebase (ps): %ld, %s (MTB): %ld, (FTB): %ld", + spd::c_str(l_dimm), l_mtb, l_ftb, TT::TIMING_NAME, l_timing_mtb, l_timing_ftb ); + + o_timing_in_ps = spd::calc_timing_from_timebase(l_timing_mtb, l_mtb, l_timing_ftb, l_ftb); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Algorithm to calculate SPD timings in nCK +/// @tparam ET SPD fields enumeration (e.g. attr_eff_engine_fields) +/// @tparam F SPD field +/// @tparam OT output type +/// @tparam TT defaulted to setTimingTraits +/// @param[in] i_spd the SPD data +/// @param[out] o_timing_in_ps SPD timing value in number of clocks (nCK) +/// @return FAPI2_RC_SUCCESS iff okay +/// +template < typename ET, + ET F, + typename OT, + typename TT = setTimingTraits > +inline fapi2::ReturnCode calc_spd_time_in_nck(const spd::facade& i_spd, + OT& o_timing_in_nck) +{ + const auto l_dimm = i_spd.get_dimm_target(); + + // Calculate the DIMM speed in picoseconds (a.k.a tCK == clock period) + int64_t l_tck_in_ps = 0; + uint64_t l_freq = 0; + FAPI_TRY( attr::get_freq(mss::find_target(l_dimm), l_freq) ); + FAPI_TRY( freq_to_ps(l_freq, l_tck_in_ps), + "Failed to calculate clock period (tCK) for %s", spd::c_str(l_dimm) ); + + { + // Calculate the desired timing in ps + int64_t l_timing_in_ps = 0; + FAPI_TRY( (calc_spd_time_in_ps(i_spd, l_tck_in_ps)) ); + + // Calculate nck + FAPI_TRY( spd::calc_nck(l_timing_in_ps, l_tck_in_ps, spd::INVERSE_DDR4_CORRECTION_FACTOR, o_timing_in_nck), + "Error in calculating %s (nCK) for target %s, with value of %d", + TT::TIMING_NAME, spd::c_str(l_dimm), l_timing_in_ps ); + + FAPI_INF("tCK (ps): %d, %s (ps): %d, %s (nck): %d", + l_tck_in_ps, TT::TIMING_NAME, l_timing_in_ps, TT::TIMING_NAME, o_timing_in_nck); + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Sets preliminary data fields +/// @tparam F pre_data_init_fields +/// @tparam T FAPI2 target type +/// @tparam IT Input data type +/// @tparam TT defaulted to preDataInitTraits +/// @param[in] i_setting value we want to set attr with +/// @return FAPI2_RC_SUCCESS iff okay +/// +template< attr_eff_engine_fields F, + fapi2::TargetType T, + typename IT, + typename TT = mss::attrEngineTraits + > +inline fapi2::ReturnCode set_field(const fapi2::Target& i_target, + const IT i_setting) +{ + FAPI_TRY( (gen::set_field(i_target, i_setting)), + "Failed set_field() for %s", spd::c_str(i_target) ); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Value traits for attrEnumTraits +/// @class attrEnumTraits - attr_si_engine_fields specialization +/// +template < > +struct attrEnumTraits +{ + static constexpr size_t DISPATCHER = ATTR_SI_DISPATCHER; +}; + +/// +/// @brief Value traits for attrEnumTraits +/// @class attrEnumTraits - attr_eff_engine_fields specialization +/// +template < > +struct attrEnumTraits +{ + static constexpr size_t DISPATCHER = ATTR_EFF_DISPATCHER; +}; + +/// +/// @brief Value traits for attrEnumTraits +/// @class attrEnumTraits - attr_eff_engine_fields specialization +/// +template < > +struct attrEnumTraits +{ + static constexpr size_t DISPATCHER = ATTR_PRE_DATA_ENG_DISPATCHER; +}; + +/// +/// @brief attribute signal integrity engine +/// @class attr_si_engine +/// @tparam ET field enumeration type +/// @tparam TT defaulted to attrEnumTraits +/// +template < typename ET, typename TT = attrEnumTraits > +struct attr_si_engine +{ + using attr_eng_t = gen::attr_engine(TT::DISPATCHER)>; + + /// + /// @brief Sets attr_si_engine_fields + /// @tparam[in] IT rank input type + /// @param[in] i_target the DIMM target + /// @param[in] i_efd_data EFD data + /// @param[in] i_rank current rank + /// @return FAPI2_RC_SUCCESS iff ok + /// + static fapi2::ReturnCode set(const std::shared_ptr& i_efd_data) + { + return attr_eng_t::set(i_efd_data); + } +}; + +/// +/// @brief Data structure to set effective config EFF data +/// @class pre_attr_eff_engine +/// @tparam F attr_eff_engine_fields enum +/// +template < typename ET, typename TT = attrEnumTraits > +struct attr_eff_engine +{ + using attr_eng_t = gen::attr_engine(TT::DISPATCHER)>; + + /// + /// @brief Sets attr_si_engine_fields + /// @param[in] i_target the DIMM target + /// @param[in] i_spd_data EFD data + /// @return FAPI2_RC_SUCCESS iff ok + /// + static fapi2::ReturnCode set(const mss::spd::facade& i_spd_data) + { + return attr_eng_t::set(i_spd_data); + } +}; + +}// 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 37fb596b4..4a802bd46 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 @@ -47,12 +47,67 @@ namespace mss /// enum pre_data_init_fields { - DIMM_TYPE, - DRAM_GEN, - HYBRID, - HYBRID_MEDIA, - MRANKS, - DIMM_RANKS_CNFG, + // Template recursive base case + ATTR_PRE_DATA_ENGINE_CASE = 0, + + DIMM_TYPE = 1, + DRAM_GEN = 2, + HYBRID = 3, + HYBRID_MEDIA = 4, + MRANKS = 5, + DIMM_RANKS_CNFG = 6, + + // Dispatcher set to last enum value + ATTR_PRE_DATA_ENG_DISPATCHER = DIMM_RANKS_CNFG, +}; + +/// +/// @brief enum list of SPD based attr fields to set +/// +enum attr_eff_engine_fields +{ + // Template recursive base case + ATTR_EFF_BASE_CASE = 0, + + // Attrs to set + DRAM_WIDTH = 1, + + // Dispatcher set to last enum value + ATTR_EFF_DISPATCHER = DRAM_WIDTH, +}; + +/// +/// @brief enum list of SI attr fields to set +/// +enum attr_si_engine_fields +{ + // Template recursive base case + ATTR_SI_BASE_CASE = 0, + + // Attrs to set + SI_MC_RCV_IMP_DQ_DQS = 1, + SI_MC_DRV_IMP_DQ_DQS_PULL_UP = 2, + SI_MC_DRV_IMP_DQ_DQS_PULL_DOWN = 3, + SI_MC_DRV_SLEW_RATE_DQ_DQS = 4, + SI_MC_DRV_IMP_CMD_ADDR = 5, + SI_MC_DRV_SLEW_RATE_CMD_ADDR = 6, + SI_MC_DRV_IMP_CLK = 7, + SI_MC_DRV_SLEW_RATE_CLK = 8, + SI_MC_RCV_IMP_ALERT_N = 9, + SI_DRAM_RTT_NOM = 10, + SI_DRAM_RTT_WR = 11, + SI_DRAM_RTT_PARK = 12, + SI_DRAM_PREAMBLE = 13, + SI_MC_DRV_EQ_DQ_DQS = 14, + SI_DRAM_DRV_IMP_DQ_DQS = 15, + SI_VREF_DQ_TRAIN_RANGE = 16, + SI_VREF_DQ_TRAIN_VALUE = 17, + SI_ODT_WR = 18, + SI_ODT_RD = 19, + SI_GEARDOWN_MODE = 20, + + // Dispatcher set to last enum value + ATTR_SI_DISPATCHER = SI_GEARDOWN_MODE, }; /// @@ -64,6 +119,33 @@ enum pre_data_init_fields template< proc_type T, pre_data_init_fields TT > class preDataInitTraits; + +/// +/// @brief Forward declartion of traits for attrEngineTraits +/// @class attrEngineTraits +/// @tparam ET enum type +/// @tparam T enum value +/// +template < typename ET, ET T> +struct attrEngineTraits; + +/// +/// @brief Forward declartion of traits for setTimingTraits +/// @class setTimingTraits +/// @tparam ET enum type +/// @tparam T enum value +/// +template < typename ET, ET T > +struct setTimingTraits; + +/// +/// @brief Forward declartion of traits for attr_engine +/// @class attrEnumTraits +/// @tparam ET enum type +/// +template < typename ET > +struct attrEnumTraits; + }// mss #endif diff --git a/src/import/generic/memory/lib/data_engine/data_engine_utils.H b/src/import/generic/memory/lib/data_engine/data_engine_utils.H index e2d5652c0..5436fd5a3 100644 --- a/src/import/generic/memory/lib/data_engine/data_engine_utils.H +++ b/src/import/generic/memory/lib/data_engine/data_engine_utils.H @@ -39,6 +39,8 @@ #include #include #include +#include +#include namespace mss { @@ -67,7 +69,7 @@ struct DataSetterTraits2D < proc_type::NIMBUS, }; /// -/// @brief Helper function for attribute setting +/// @brief Helper function to update a 2D array output /// @tparam P proc_type /// @tparam X size of 1st array index /// @tparam Y size of 2nd array index @@ -85,11 +87,13 @@ template < proc_type P, typename T, typename TT = DataSetterTraits2D > -fapi2::ReturnCode data_setter(const fapi2::Target& i_target, +fapi2::ReturnCode update_data(const fapi2::Target& i_target, const T i_setting, const generic_ffdc_codes i_ffdc_code, T (&o_data)[X][Y]) { + // Currenlty only valid for a DIMM target, for Nimbus, traits enforces this at compile time + // Use case is currently for pre_eff_config which is supported in both Axone and Nimbus const auto l_port_index = mss::index( find_target(i_target) ); const auto l_dimm_index = mss::index(i_target); @@ -170,8 +174,7 @@ fapi_try_exit: template< proc_type P, typename TT, fapi2::TargetType T, - typename IT - > + typename IT > inline fapi2::ReturnCode set_field(const fapi2::Target& i_target, const IT i_setting) { @@ -179,13 +182,334 @@ inline fapi2::ReturnCode set_field(const fapi2::Target& i_target, typename TT::attr_type l_attr_list = {}; FAPI_TRY( TT::get_attr(l_attr_target, l_attr_list) ); - FAPI_TRY( data_setter

(i_target, i_setting, TT::FFDC_CODE, l_attr_list) ); + FAPI_TRY( update_data

(i_target, i_setting, TT::FFDC_CODE, l_attr_list) ); FAPI_TRY( TT::set_attr(l_attr_target, l_attr_list) ); fapi_try_exit: return fapi2::current_err; } +// Controller agnostic functions + +namespace gen +{ + +/// +/// @brief Get the target associated with the SPD facade +/// @param[in] i_data the SPD data +/// return a fapi2 DIMM target +/// +static inline fapi2::Target get_target(const spd::facade& i_data) +{ + return i_data.get_dimm_target(); +} + +/// +/// @brief Get the target associated with the EFD decoder +/// @param[in] i_data the EFD data +/// return a fapi2 DIMM target +/// +static inline fapi2::Target get_target(const std::shared_ptr& i_data) +{ + return i_data->get_ocmb_target(); +} + +/// +/// @brief Helper function to update the structure that holds attr data +/// @tparam X size of 1st array index +/// @tparam Y size of 2nd array index +/// @tparam T Input/output data type +/// @tparam FFDC the FFDC type +/// @param[in] i_efd_data the EFD data +/// @param[in] i_setting array to set +/// @param[in] i_ffdc_code FFDC function code +/// @param[out] o_data attribute data structure to set +/// @return FAPI2_RC_SUCCESS iff okay +/// +template < size_t X, + size_t Y, + typename T, + typename FFDC > +inline fapi2::ReturnCode update_data(const std::shared_ptr& i_efd_data, + const T i_setting, + const FFDC i_ffdc_code, + T (&o_data)[X][Y]) +{ + const auto l_ocmb = i_efd_data->get_ocmb_target(); + + // TK, remove hard-code when VPDinfo struct adds an iv_dimm index + // For explorer we can only have 1 DDIMM (index 0), or up to 2 DIMMs + constexpr size_t l_dimm_index = 0; + const auto l_rank = i_efd_data->get_rank(); + + FAPI_ASSERT( l_dimm_index < X, + fapi2::MSS_OUT_OF_BOUNDS_INDEXING() + .set_INDEX(l_dimm_index) + .set_LIST_SIZE(X) + .set_FUNCTION(i_ffdc_code) + .set_TARGET(l_ocmb), + "Dimm index (%d) was larger than max (%d) on %s", + l_dimm_index, + X, + mss::spd::c_str(l_ocmb) ); + + FAPI_ASSERT( l_rank < Y, + fapi2::MSS_OUT_OF_BOUNDS_INDEXING() + .set_INDEX(l_rank) + .set_LIST_SIZE(X) + .set_FUNCTION(i_ffdc_code) + .set_TARGET(l_ocmb), + "Rank index (%d) was larger than max (%d) on %s", + l_rank, + Y, + mss::spd::c_str(l_ocmb) ); + + FAPI_DBG("Updating data[%d][%d] with %d for %s", l_dimm_index, l_rank, i_setting, spd::c_str(l_ocmb)); + o_data[l_dimm_index][l_rank] = i_setting; + + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Helper function to update the structure that holds attr data +/// @tparam X size of 1st array index +/// @tparam T Input/output data type +/// @tparam FFDC the FFDC type +/// @param[in] i_data the SPD data +/// @param[in] i_target the DIMM target +/// @param[in] i_setting array to set +/// @param[in] i_ffdc_code FFDC function code +/// @param[out] o_data attribute data structure to set +/// @return FAPI2_RC_SUCCESS iff okay +/// +template < size_t X, + typename T, + typename FFDC > +inline fapi2::ReturnCode update_data( const spd::facade& i_spd_data, + const T i_setting, + const FFDC i_ffdc_code, + T (&o_data)[X]) +{ + // TK remove hard-code to DIMM0, use REL_POS attr + const auto l_dimm = i_spd_data.get_dimm_target(); + const size_t l_dimm_index = 0; + + FAPI_ASSERT( l_dimm_index < X, + fapi2::MSS_OUT_OF_BOUNDS_INDEXING() + .set_INDEX(l_dimm_index) + .set_LIST_SIZE(X) + .set_FUNCTION(i_ffdc_code) + .set_TARGET(l_dimm), + "Dimm index (%d) was larger than max (%d) on %s", + l_dimm_index, + X, + mss::spd::c_str(l_dimm) ); + + FAPI_DBG("Updating data[%d] with %d for %s", l_dimm_index, i_setting, spd::c_str(l_dimm)); + o_data[l_dimm_index] = i_setting; + + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Helper function to update the structure that holds attr data +/// @tparam DT the data type +/// @tparam IT Input data type +/// @tparam FFDC type +/// @tparam OT Output data type +/// @param[in] i_data the data (e.g. EFD, SPD) +/// @param[in] i_setting array to set +/// @param[in] i_ffdc_code FFDC function code +/// @param[out] o_data output to set +/// @return FAPI2_RC_SUCCESS iff okay +/// +template < typename DT, + typename IT, + typename FFDC, + typename OT > +inline fapi2::ReturnCode update_data( const DT& i_data, + const IT i_setting, + const FFDC i_ffdc_code, + OT& o_data ) +{ + FAPI_DBG("Updating data with %d for %s", i_setting, spd::c_str(get_target(i_data))); + o_data = i_setting; + return fapi2::FAPI2_RC_SUCCESS; +} + +/// +/// @brief Sets attr data fields +/// @tparam TT data engine class traits (e.g. preDataInitTraits, etc.) +/// @tparam T FAPI2 target type +/// @tparam IT Input data type +/// @param[in] i_target the FAPI target +/// @param[in] i_setting value we want to set attr with +/// @return FAPI2_RC_SUCCESS iff okay +/// +template< typename TT, + fapi2::TargetType T, + typename IT > +inline fapi2::ReturnCode set_field(const fapi2::Target& i_target, + const IT i_setting) +{ + const auto l_attr_target = mss::find_target(i_target); + typename TT::attr_type l_attr_list = {}; + FAPI_TRY( TT::get_attr(l_attr_target, l_attr_list) ); + + FAPI_TRY( update_data(i_target, i_setting, TT::FFDC_CODE, l_attr_list) ); + FAPI_TRY( TT::set_attr(l_attr_target, l_attr_list) ); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Helper function to get the target associated with generic attribute setting +/// @param[in] i_target +/// return a fapi2 MEM_PORT target +/// +static inline fapi2::Target get_attr_target(const fapi2::Target& + i_target) +{ + return mss::find_target(i_target); +} + +/// +/// @brief Helper function to get the target associated with generic attribute setting +/// @param[in] i_target +/// return a fapi2 MEM_PORT target +/// +inline fapi2::Target get_attr_target(const fapi2::Target& + i_target) +{ + // Explorer has only one MEM_PORT per OCMB, so we are looking for the 0th pos relative to the OCMB + // Will need to update to take into account a mem_channel index in VPDinfo if we ever support this. + // Per FW, for the DDIMM case we can't support unique settings per channel because the SPD + // doesn't know about anything outside of the DDIMM itself. + return mss::find_targets(i_target)[0]; +} + +/// +/// @brief Sets attr data fields +/// @tparam TT data engine class traits (e.g. preDataInitTraits, etc.) +/// @tparam DT the data type +/// @tparam IT Input data type +/// @param[in] i_target the FAPI target +/// @param[in] i_setting value we want to set attr with +/// @return FAPI2_RC_SUCCESS iff okay +/// +template< typename TT, + typename DT, + typename IT > +inline fapi2::ReturnCode set_field(const DT& i_data, + const IT i_setting) +{ + // Grab the target associated w/the data (e.g. SPD or EFD) + const auto l_data_target = get_target(i_data); + + // Grab the target associated w/the attribute to set + const auto l_attr_target = get_attr_target(l_data_target); + + // Get the attribute data in its entirety + typename TT::attr_type l_attr_list = {}; + FAPI_TRY( TT::get_attr(l_attr_target, l_attr_list) ); + + // Update the portion of interest (can vary per dimm and/or rank) + FAPI_TRY( update_data(i_data, i_setting, TT::FFDC_CODE, l_attr_list) ); + + // Set the contents back to the attribute + FAPI_TRY( TT::set_attr(l_attr_target, l_attr_list) ); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Template recursive algorithm for setting attrs +/// @class attr_engine +/// @tparam ET enum type - conceptually a list of attrs to set +/// @tparam F enum value - the specific attr value from ET to set +/// @tparam TT defaulted to attrEngineTraits +/// @tparam V defaulted to void (dispatch tag) +/// +template < typename ET, + ET F, + typename TT = mss::attrEngineTraits, + typename V = void > +struct attr_engine +{ + /// + /// @brief Sets attributes fields F in ET + /// @tparam DT the data type + /// @param[in] i_data the data (efd_decoder, spd_facade, etc.) + /// @return FAPI2_RC_SUCCESS iff ok + /// + template < typename DT > + static fapi2::ReturnCode single_set(const DT& i_data) + { + typename TT::attr_integral_type l_value = 0; + FAPI_TRY( TT::get_value_to_set(i_data, l_value) ); + + FAPI_TRY( set_field(i_data, l_value) ); + + fapi_try_exit: + return fapi2::current_err; + } + + /// + /// @brief Sets attributes fields F in ET + /// @tparam DT the data type + /// @param[in] i_data the data (efd_decoder, spd_facade, etc.) + /// @return FAPI2_RC_SUCCESS iff ok + /// + template < typename DT > + static fapi2::ReturnCode set(const DT& i_data) + { + FAPI_TRY( (attr_engine::single_set(i_data)) ); + + // Compiler isn't smart enough to deduce F - 1u (decrementing the enum values by 1) + // Cast needed to help the compiler deduce this value is an ET type + // This does the recursive call to unroll a compile-time looping of a enum list of attrs to set + FAPI_TRY( (attr_engine < ET, static_cast(F - 1u) >::set(i_data)) ); + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Algorithm for setting SI attrs +/// @class attr_engine +/// @tparam ET enum type +/// @tparam F enum value +/// @note partial specialization when F == 0 (base case). Which is a NOP. +/// +template < typename ET, ET F> +struct attr_engine< ET, + F, + mss::attrEngineTraits, + typename std::enable_if<0u == F>::type > +{ + /// + /// @brief Sets attributes fields F in ET + /// @tparam DT the data type + /// @param[in] i_data the data (efd_decoder, spd_facade, etc.) + /// @return FAPI2_RC_SUCCESS iff ok + /// + template < typename DT > + static fapi2::ReturnCode set(const DT& i_data) + { + return fapi2::FAPI2_RC_SUCCESS; + } +}; + +}// gen }//mss #endif diff --git a/src/import/generic/memory/lib/data_engine/p9a/p9a_data_init_traits.H b/src/import/generic/memory/lib/data_engine/p9a/p9a_data_init_traits.H index 66edc77d0..69234151e 100644 --- a/src/import/generic/memory/lib/data_engine/p9a/p9a_data_init_traits.H +++ b/src/import/generic/memory/lib/data_engine/p9a/p9a_data_init_traits.H @@ -22,3 +22,447 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ +/// +/// @file p9a_data_init_traits.H +/// @brief Trait class definitions for Axone pre_data_init +/// +// *HWP HWP Owner: Andre Marin +// *HWP FW Owner: Stephen Glancy +// *HWP Team: Memory +// *HWP Level: 2 +// *HWP Consumed by: HB:CI + +#ifndef _MSS_P9A_PRE_DATA_INIT_TRAITS_H_ +#define _MSS_P9A_PRE_DATA_INIT_TRAITS_H_ + +#include +#include +#include +#include + +namespace mss +{ + +/// +/// @brief Traits for pre_data_engine +/// @class attrEngineTraits +/// @note AXONE, DIMM_TYPE specialization +/// +template<> +struct attrEngineTraits +{ + using attr_type = fapi2::ATTR_MEM_EFF_DIMM_TYPE_Type; + using attr_integral_type = std::remove_all_extents::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DIMM_TYPE_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DIMM_TYPE; + + /// + /// @brief attribute getter + /// @param[in] i_target the MCS target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target& i_target, + attr_type& o_setting) + { + return FAPI_ATTR_GET(fapi2::ATTR_MEM_EFF_DIMM_TYPE, i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the MCS target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target& i_target, + attr_type& i_setting) + { + return FAPI_ATTR_SET(fapi2::ATTR_MEM_EFF_DIMM_TYPE, i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[in] i_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) + { + // ========================================================= + // DDR4 SPD Document Release 4 + // Byte 3 (0x003): Key Byte / Module Type + // ========================================================= + static const std::vector< std::pair > BASE_MODULE_TYPE_MAP = + { + //{key byte, dimm type} + {1, fapi2::ENUM_ATTR_MEM_EFF_DIMM_TYPE_RDIMM}, + {2, fapi2::ENUM_ATTR_MEM_EFF_DIMM_TYPE_UDIMM}, + {10, fapi2::ENUM_ATTR_MEM_EFF_DIMM_TYPE_DDIMM}, + // All others reserved or not supported + }; + + uint8_t l_base_module_type = 0; + FAPI_TRY(i_spd_data.base_module(l_base_module_type)); + FAPI_TRY(lookup_table_check(i_spd_data.get_dimm_target(), BASE_MODULE_TYPE_MAP, SET_ATTR_DIMM_TYPE, l_base_module_type, + o_setting)); + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for pre_data_engine +/// @class attrEngineTraits +/// @note AXONE, DRAM_GEN specialization +/// +template<> +struct attrEngineTraits +{ + using attr_type = fapi2::ATTR_MEM_EFF_DRAM_GEN_Type; + using attr_integral_type = std::remove_all_extents::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DRAM_GEN_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DRAM_GEN; + + /// + /// @brief attribute getter + /// @param[in] i_target the MCS target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target& i_target, + attr_type& o_setting) + { + return FAPI_ATTR_GET(fapi2::ATTR_MEM_EFF_DRAM_GEN, i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the MCS target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target& i_target, + attr_type& i_setting) + { + return FAPI_ATTR_SET(fapi2::ATTR_MEM_EFF_DRAM_GEN, i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[in] i_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) + { + // ========================================================= + // DDR4 SPD Document Release 4 + // Byte 2 (0x002): Key Byte / DRAM Device Type + // ========================================================= + static const std::vector< std::pair > DRAM_GEN_MAP = + { + //{key value, dram gen} + {0x0C, fapi2::ENUM_ATTR_MEM_EFF_DRAM_GEN_DDR4} + // Other key bytes reserved or not supported + }; + + uint8_t l_device_type = 0; + FAPI_TRY(i_spd_data.device_type(l_device_type)); + FAPI_TRY(lookup_table_check(i_spd_data.get_dimm_target(), DRAM_GEN_MAP, SET_ATTR_DRAM_GEN, l_device_type, o_setting)); + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for pre_data_engine +/// @class attrEngineTraits +/// @note AXONE, HYBRID specialization +/// +template<> +struct attrEngineTraits +{ + using attr_type = fapi2::ATTR_MEM_EFF_HYBRID_Type; + using attr_integral_type = std::remove_all_extents::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_HYBRID_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_HYBRID; + + /// + /// @brief attribute getter + /// @param[in] i_target the MCS target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target& i_target, + attr_type& o_setting) + { + return FAPI_ATTR_GET(fapi2::ATTR_MEM_EFF_HYBRID, i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the MCS target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target& i_target, + attr_type& i_setting) + { + return FAPI_ATTR_SET(fapi2::ATTR_MEM_EFF_HYBRID, i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[in] i_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) + { + // ========================================================= + // DDR4 SPD Document Release 4 + // Byte 3 (0x003): Key Byte / Module Type - Hybrid + // ========================================================= + static const std::vector< std::pair > HYBRID_MAP = + { + //{key byte, dimm type} + {0, fapi2::ENUM_ATTR_MEM_EFF_HYBRID_NOT_HYBRID}, + {1, fapi2::ENUM_ATTR_MEM_EFF_HYBRID_IS_HYBRID}, + // All others reserved or not supported + }; + + uint8_t l_spd_hybrid_type = 0; + FAPI_TRY(i_spd_data.hybrid(l_spd_hybrid_type)); + FAPI_TRY(lookup_table_check(i_spd_data.get_dimm_target(), HYBRID_MAP, SET_ATTR_HYBRID, l_spd_hybrid_type, o_setting)); + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for pre_data_engine +/// @class attrEngineTraits +/// @note AXONE, HYBRID_MEDIA specialization +/// +template<> +struct attrEngineTraits +{ + using attr_type = fapi2::ATTR_MEM_EFF_HYBRID_MEMORY_TYPE_Type; + using attr_integral_type = std::remove_all_extents::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_HYBRID_MEMORY_TYPE_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_HYBRID_MEDIA; + + /// + /// @brief attribute getter + /// @param[in] i_target the MCS target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target& i_target, + attr_type& o_setting) + { + return FAPI_ATTR_GET(fapi2::ATTR_MEM_EFF_HYBRID_MEMORY_TYPE, i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the MCS target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target& i_target, + attr_type& i_setting) + { + return FAPI_ATTR_SET(fapi2::ATTR_MEM_EFF_HYBRID_MEMORY_TYPE, i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[in] i_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) + { + // ========================================================= + // DDR4 SPD Document Release 4 + // Byte 3 (0x003): Key Byte / Module Type - Hybrid + // ========================================================= + static const std::vector< std::pair > HYBRID_MEMORY_TYPE_MAP = + { + + //{key byte, dimm type} + {0, fapi2::ENUM_ATTR_MEM_EFF_HYBRID_MEMORY_TYPE_NONE}, + {1, fapi2::ENUM_ATTR_MEM_EFF_HYBRID_MEMORY_TYPE_NVDIMM}, + // All others reserved or not supported + }; + + uint8_t l_spd_hybrid_media = 0; + FAPI_TRY(i_spd_data.hybrid_media(l_spd_hybrid_media)); + FAPI_TRY(lookup_table_check(i_spd_data.get_dimm_target(), HYBRID_MEMORY_TYPE_MAP, SET_ATTR_HYBRID_MEDIA, + l_spd_hybrid_media, o_setting)); + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Gets master ranks from SPD +/// @param[out] o_output num package ranks per DIMM +/// @return FAPI2_RC_SUCCESS iff ok +/// +static fapi2::ReturnCode get_master_ranks(const spd::facade& i_spd_data, + const generic_ffdc_codes i_ffdc, + uint8_t& o_output) +{ + // ========================================================= + // DDR4 SPD Document Release 4 + // Byte 12 (0x00C): Module Organization + // ========================================================= + static const std::vector< std::pair > NUM_PACKAGE_RANKS_MAP = + { + // {key byte, num of package ranks per DIMM (package ranks)} + {0, fapi2::ENUM_ATTR_MEM_EFF_NUM_MASTER_RANKS_PER_DIMM_1R}, + {1, fapi2::ENUM_ATTR_MEM_EFF_NUM_MASTER_RANKS_PER_DIMM_2R}, + {3, fapi2::ENUM_ATTR_MEM_EFF_NUM_MASTER_RANKS_PER_DIMM_4R}, + }; + + const auto l_dimm = i_spd_data.get_dimm_target(); + uint8_t l_master_ranks_spd = 0; + FAPI_TRY(i_spd_data.num_package_ranks_per_dimm(l_master_ranks_spd), + "%s failed to get number of package ranks from SPD", spd::c_str(l_dimm)); + + FAPI_TRY(lookup_table_check(l_dimm, NUM_PACKAGE_RANKS_MAP, i_ffdc, l_master_ranks_spd, + o_output), "%s failed MASTER_RANKS lookup check", spd::c_str(l_dimm)); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Traits for pre_data_engine +/// @class attrEngineTraits +/// @note AXONE, MRANKS specialization +/// +template<> +struct attrEngineTraits +{ + using attr_type = fapi2::ATTR_MEM_EFF_NUM_MASTER_RANKS_PER_DIMM_Type; + using attr_integral_type = std::remove_all_extents::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_NUM_MASTER_RANKS_PER_DIMM_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_MRANKS; + + /// + /// @brief attribute getter + /// @param[in] i_target the MCS target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target& i_target, + attr_type& o_setting) + { + return FAPI_ATTR_GET(fapi2::ATTR_MEM_EFF_NUM_MASTER_RANKS_PER_DIMM, i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the MCS target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target& i_target, + attr_type& i_setting) + { + return FAPI_ATTR_SET(fapi2::ATTR_MEM_EFF_NUM_MASTER_RANKS_PER_DIMM, i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[in] i_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) + { + FAPI_TRY( get_master_ranks(i_spd_data, SET_ATTR_MASTER_RANKS, o_setting) ); + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @brief Traits for pre_data_engine +/// @class attrEngineTraits +/// @note AXONE, DIMM_RANKS_CNFG specialization +/// +template<> +struct attrEngineTraits +{ + using attr_type = fapi2::ATTR_MEM_EFF_DIMM_RANKS_CONFIGED_Type; + using attr_integral_type = std::remove_all_extents::type; + static constexpr fapi2::TargetType TARGET_TYPE = fapi2::ATTR_MEM_EFF_DIMM_RANKS_CONFIGED_TargetType; + static constexpr generic_ffdc_codes FFDC_CODE = SET_DIMM_RANKS_CNFG; + + /// + /// @brief attribute getter + /// @param[in] i_target the MCS target + /// @param[out] o_setting array to populate + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode get_attr(const fapi2::Target& i_target, + attr_type& o_setting) + { + return FAPI_ATTR_GET(fapi2::ATTR_MEM_EFF_DIMM_RANKS_CONFIGED, i_target, o_setting); + } + + /// + /// @brief attribute setter + /// @param[in] i_target the MCS target + /// @param[in] i_setting array to set + /// @return FAPI2_RC_SUCCESS iff okay + /// + static fapi2::ReturnCode set_attr(const fapi2::Target& i_target, + attr_type& i_setting) + { + return FAPI_ATTR_SET(fapi2::ATTR_MEM_EFF_DIMM_RANKS_CONFIGED, i_target, i_setting); + } + + /// + /// @brief Computes setting for attribute + /// @param[in] i_spd_data SPD data + /// @param[in] i_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) + { + // Set configed ranks. Set the bit representing the master rank configured (0 being left most.) So, + // a 4R DIMM would be 0b11110000 (0xF0). This is used by PRD. + fapi2::buffer l_ranks_configed; + + uint8_t l_master_ranks = 0; + FAPI_TRY( get_master_ranks(i_spd_data, SET_ATTR_RANKS_CONFIGED, l_master_ranks) ); + + FAPI_TRY( l_ranks_configed.setBit(0, l_master_ranks), + "%s. Failed to setBit", spd::c_str(i_spd_data.get_dimm_target()) ); + + o_setting = l_ranks_configed; + + fapi_try_exit: + return fapi2::current_err; + } +}; + +}//mss + +#endif diff --git a/src/import/generic/memory/lib/data_engine/pre_data_init.H b/src/import/generic/memory/lib/data_engine/pre_data_init.H index 068e4da4f..b3e4de8ad 100644 --- a/src/import/generic/memory/lib/data_engine/pre_data_init.H +++ b/src/import/generic/memory/lib/data_engine/pre_data_init.H @@ -42,7 +42,6 @@ #include #include #include -#include #include namespace mss diff --git a/src/import/generic/memory/lib/mss_generic_attribute_getters.H b/src/import/generic/memory/lib/mss_generic_attribute_getters.H index bce94f55f..3b01d0c4a 100644 --- a/src/import/generic/memory/lib/mss_generic_attribute_getters.H +++ b/src/import/generic/memory/lib/mss_generic_attribute_getters.H @@ -2348,6 +2348,55 @@ fapi_try_exit: return fapi2::current_err; } +/// +/// @brief ATTR_MEM_EFF_DIMM_RANKS_CONFIGED getter +/// @param[in] const ref to the TARGET_TYPE_DIMM +/// @param[out] uint8_t& reference to store the value +/// @note Generated by gen_accessors.pl generate_mc_port_params +/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK +/// @note Bit wise representation of master ranks in each DIMM that are used for reads and +/// writes. Used by PRD. +/// +inline fapi2::ReturnCode get_dimm_ranks_configed(const fapi2::Target& i_target, + uint8_t& o_value) +{ + uint8_t l_value[2] = {}; + const auto l_port = i_target.getParent(); + + FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_MEM_EFF_DIMM_RANKS_CONFIGED, l_port, l_value) ); + o_value = l_value[mss::index(i_target)]; + return fapi2::current_err; + +fapi_try_exit: + FAPI_ERR("failed getting ATTR_MEM_EFF_DIMM_RANKS_CONFIGED: 0x%lx (target: %s)", + uint64_t(fapi2::current_err), mss::c_str(i_target)); + return fapi2::current_err; +} + +/// +/// @brief ATTR_MEM_EFF_DIMM_RANKS_CONFIGED getter +/// @param[in] const ref to the TARGET_TYPE_MEM_PORT +/// @param[out] uint8_t&[] array reference to store the value +/// @note Generated by gen_accessors.pl generate_mc_port_params +/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK +/// @note Bit wise representation of master ranks in each DIMM that are used for reads and +/// writes. Used by PRD. +/// +inline fapi2::ReturnCode get_dimm_ranks_configed(const fapi2::Target& i_target, + uint8_t (&o_array)[2]) +{ + uint8_t l_value[2] = {}; + + FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_MEM_EFF_DIMM_RANKS_CONFIGED, i_target, l_value) ); + memcpy(o_array, &l_value, 2); + return fapi2::current_err; + +fapi_try_exit: + FAPI_ERR("failed getting ATTR_MEM_EFF_DIMM_RANKS_CONFIGED: 0x%lx (target: %s)", + uint64_t(fapi2::current_err), mss::c_str(i_target)); + return fapi2::current_err; +} + /// /// @brief ATTR_MEM_EFF_DRAM_TREFI getter /// @param[in] const ref to the TARGET_TYPE_MEM_PORT @@ -3864,8 +3913,8 @@ fapi_try_exit: /// @note Generated by gen_accessors.pl generate_mc_port_params /// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK /// @note Array[DIMM][RANK] READ, On Die Termination triggering bitmap. Use bitmap to determine -/// which ODT to fire for the designated rank. The bits in 8 bit field are [Dimm0 ODT0][Dimm0 -/// ODT1][N/A][N/A][Dimm1 ODT0][Dimm1 ODT1][N/A][N/A] +/// which ODT to fire for the designated rank. The bits in 8 bit field are [DIMM0 ODT0][DIMM0 +/// ODT1][DIMM0 ODT2][DIMM0 ODT3][DIMM1 ODT0][DIMM1 ODT1][DIMM1 ODT2][DIMM1 ODT3] /// inline fapi2::ReturnCode get_si_odt_rd(const fapi2::Target& i_target, uint8_t (&o_array)[4]) { @@ -3889,8 +3938,8 @@ fapi_try_exit: /// @note Generated by gen_accessors.pl generate_mc_port_params /// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK /// @note Array[DIMM][RANK] READ, On Die Termination triggering bitmap. Use bitmap to determine -/// which ODT to fire for the designated rank. The bits in 8 bit field are [Dimm0 ODT0][Dimm0 -/// ODT1][N/A][N/A][Dimm1 ODT0][Dimm1 ODT1][N/A][N/A] +/// which ODT to fire for the designated rank. The bits in 8 bit field are [DIMM0 ODT0][DIMM0 +/// ODT1][DIMM0 ODT2][DIMM0 ODT3][DIMM1 ODT0][DIMM1 ODT1][DIMM1 ODT2][DIMM1 ODT3] /// inline fapi2::ReturnCode get_si_odt_rd(const fapi2::Target& i_target, uint8_t (&o_array)[2][4]) @@ -3914,8 +3963,8 @@ fapi_try_exit: /// @note Generated by gen_accessors.pl generate_mc_port_params /// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK /// @note Array[DIMM][RANK] WRITE, On Die Termination triggering bitmap. Use bitmap to determine -/// which ODT to fire for the designated rank. The bits in 8 bit field are [Dimm0 ODT0][Dimm0 -/// ODT1][N/A][N/A][Dimm1 ODT0][Dimm1 ODT1][N/A][N/A] +/// which ODT to fire for the designated rank. The bits in 8 bit field are [DIMM0 ODT0][DIMM0 +/// ODT1][DIMM0 ODT2][DIMM0 ODT3][DIMM1 ODT0][DIMM1 ODT1][DIMM1 ODT2][DIMM1 ODT3] /// inline fapi2::ReturnCode get_si_odt_wr(const fapi2::Target& i_target, uint8_t (&o_array)[4]) { @@ -3939,8 +3988,8 @@ fapi_try_exit: /// @note Generated by gen_accessors.pl generate_mc_port_params /// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK /// @note Array[DIMM][RANK] WRITE, On Die Termination triggering bitmap. Use bitmap to determine -/// which ODT to fire for the designated rank. The bits in 8 bit field are [Dimm0 ODT0][Dimm0 -/// ODT1][N/A][N/A][Dimm1 ODT0][Dimm1 ODT1][N/A][N/A] +/// which ODT to fire for the designated rank. The bits in 8 bit field are [DIMM0 ODT0][DIMM0 +/// ODT1][DIMM0 ODT2][DIMM0 ODT3][DIMM1 ODT0][DIMM1 ODT1][DIMM1 ODT2][DIMM1 ODT3] /// inline fapi2::ReturnCode get_si_odt_wr(const fapi2::Target& i_target, uint8_t (&o_array)[2][4]) diff --git a/src/import/generic/memory/lib/spd/ddimm/ddr4/ddimm_decoder_ddr4.H b/src/import/generic/memory/lib/spd/ddimm/ddr4/ddimm_decoder_ddr4.H index 5e736cc76..2d1816ab3 100644 --- a/src/import/generic/memory/lib/spd/ddimm/ddr4/ddimm_decoder_ddr4.H +++ b/src/import/generic/memory/lib/spd/ddimm/ddr4/ddimm_decoder_ddr4.H @@ -452,7 +452,7 @@ class decoder : public dimm_module_decoder fapi2::buffer l_buffer; right_aligned_insert(l_buffer, l_byte1, l_byte0); o_output = l_buffer; - FAPI_INF("%s. Register Manufacturer ID Code: 0x%04x", + FAPI_INF("%s. Byte enables: 0x%04x", spd::c_str(iv_target), o_output); } @@ -484,7 +484,7 @@ class decoder : public dimm_module_decoder fapi2::buffer l_buffer; right_aligned_insert(l_buffer, l_byte3, l_byte2, l_byte1, l_byte0); o_output = l_buffer; - FAPI_INF("%s. Register Manufacturer ID Code: 0x%04x", + FAPI_INF("%s. Nibble Enables: 0x%04x", spd::c_str(iv_target), o_output); } diff --git a/src/import/generic/memory/lib/spd/ddimm/ddr4/efd_ddr4_custom_microchip_decoder.H b/src/import/generic/memory/lib/spd/ddimm/ddr4/efd_ddr4_custom_microchip_decoder.H index 12a292b57..12acc87ef 100644 --- a/src/import/generic/memory/lib/spd/ddimm/ddr4/efd_ddr4_custom_microchip_decoder.H +++ b/src/import/generic/memory/lib/spd/ddimm/ddr4/efd_ddr4_custom_microchip_decoder.H @@ -68,10 +68,12 @@ class decoder : public b /// @brief ctor /// @param[in] i_target dimm target /// @param[in] i_spd_data vector DIMM SPD data + /// @param[in] i_rank the current rank /// decoder(const fapi2::Target& i_target, - const std::vector& i_spd_data): - base_decoder(i_target, i_spd_data) + const std::vector& i_spd_data, + const size_t i_rank): + base_decoder(i_target, i_spd_data, i_rank) { // Using the emulation value here static_assert( R <= mss::spd::rev::DDIMM_MAX, " R > rev::DDIMM_MAX"); diff --git a/src/import/generic/memory/lib/spd/ddimm/efd_decoder.H b/src/import/generic/memory/lib/spd/ddimm/efd_decoder.H index d3078c171..6ac30ab0f 100644 --- a/src/import/generic/memory/lib/spd/ddimm/efd_decoder.H +++ b/src/import/generic/memory/lib/spd/ddimm/efd_decoder.H @@ -86,6 +86,7 @@ class base_decoder const fapi2::Target iv_target; std::vector iv_data; + size_t iv_rank; public: @@ -98,11 +99,14 @@ class base_decoder /// @brief ctor /// @param[in] i_target DIMM target on which to operate /// @param[in] i_target EFD data + /// @param[in] i_rank the current rank /// base_decoder(const fapi2::Target& i_target, - const std::vector& i_data): + const std::vector& i_data, + const size_t i_rank): iv_target(i_target), - iv_data(i_data) + iv_data(i_data), + iv_rank(i_rank) { } @@ -115,11 +119,20 @@ class base_decoder /// @brief Gets decoder target /// @return fapi2::Target /// - virtual fapi2::Target get_dimm_target() const + virtual fapi2::Target get_ocmb_target() const { return iv_target; } + /// + /// @brief Gets rank tied to this decoder + /// @return size_t + /// + virtual size_t get_rank() const + { + return iv_rank; + } + /// /// @brief Gets decoder SPD data /// @return std::vector diff --git a/src/import/generic/memory/lib/spd/ddimm/efd_factory.H b/src/import/generic/memory/lib/spd/ddimm/efd_factory.H index 6a85c86f8..540bb87b0 100644 --- a/src/import/generic/memory/lib/spd/ddimm/efd_factory.H +++ b/src/import/generic/memory/lib/spd/ddimm/efd_factory.H @@ -48,17 +48,19 @@ namespace efd /// @brief Generates the EFD decoder based upon the EFD type /// @param[in] i_target DIMM target /// @param[in] i_data SPD data +/// @param[in] i_rank the current rank /// @param[out] o_decoder shared pointer to the decoder in question /// @return fapi2::ReturnCode SUCCESS iff the procedure executes successfully /// // TODO:update this for other types of EFD inline fapi2::ReturnCode factory(const fapi2::Target& i_target, const std::vector& i_data, + const size_t i_rank, std::shared_ptr& o_decoder_ptr) { - o_decoder_ptr = - std::make_shared>(i_target, - i_data); + o_decoder_ptr = std::make_shared>(i_target, i_data, i_rank); return fapi2::FAPI2_RC_SUCCESS; } diff --git a/src/import/generic/procedures/xml/attribute_info/generic_memory_eff_attributes.xml b/src/import/generic/procedures/xml/attribute_info/generic_memory_eff_attributes.xml index cec393f11..ae04f2e57 100644 --- a/src/import/generic/procedures/xml/attribute_info/generic_memory_eff_attributes.xml +++ b/src/import/generic/procedures/xml/attribute_info/generic_memory_eff_attributes.xml @@ -64,7 +64,7 @@ uint8 - EMPTY = 0, RDIMM = 1, UDIMM = 2, LRDIMM = 3 + EMPTY = 0, RDIMM = 1, UDIMM = 2, LRDIMM = 3, DDIMM = 4 2 dimm_type @@ -697,6 +697,20 @@ num_master_ranks_per_dimm + + ATTR_MEM_EFF_DIMM_RANKS_CONFIGED + TARGET_TYPE_MEM_PORT + + Bit wise representation of master ranks in each DIMM that are used for reads and writes. + Used by PRD. + + + uint8 + + 2 + dimm_ranks_configed + + ATTR_MEM_EFF_DRAM_TREFI TARGET_TYPE_MEM_PORT diff --git a/src/import/generic/procedures/xml/attribute_info/generic_memory_si_attributes.xml b/src/import/generic/procedures/xml/attribute_info/generic_memory_si_attributes.xml index 819336678..1ec910f04 100644 --- a/src/import/generic/procedures/xml/attribute_info/generic_memory_si_attributes.xml +++ b/src/import/generic/procedures/xml/attribute_info/generic_memory_si_attributes.xml @@ -218,7 +218,7 @@ uint8 - HALF =0, QUARTER=1 + HALF=0, QUARTER=1 2 4 si_geardown_mode @@ -481,7 +481,8 @@ Array[DIMM][RANK] READ, On Die Termination triggering bitmap. Use bitmap to determine which ODT to fire for the designated rank. - The bits in 8 bit field are [Dimm0 ODT0][Dimm0 ODT1][N/A][N/A][Dimm1 ODT0][Dimm1 ODT1][N/A][N/A] + The bits in 8 bit field are + [DIMM0 ODT0][DIMM0 ODT1][DIMM0 ODT2][DIMM0 ODT3][DIMM1 ODT0][DIMM1 ODT1][DIMM1 ODT2][DIMM1 ODT3] uint8 @@ -496,7 +497,8 @@ Array[DIMM][RANK] WRITE, On Die Termination triggering bitmap. Use bitmap to determine which ODT to fire for the designated rank. - The bits in 8 bit field are [Dimm0 ODT0][Dimm0 ODT1][N/A][N/A][Dimm1 ODT0][Dimm1 ODT1][N/A][N/A] + The bits in 8 bit field are + [DIMM0 ODT0][DIMM0 ODT1][DIMM0 ODT2][DIMM0 ODT3][DIMM1 ODT0][DIMM1 ODT1][DIMM1 ODT2][DIMM1 ODT3] uint8 -- cgit v1.2.1