diff options
Diffstat (limited to 'src/import/generic/memory/lib/spd/spd_factory_pattern.H')
-rw-r--r-- | src/import/generic/memory/lib/spd/spd_factory_pattern.H | 484 |
1 files changed, 484 insertions, 0 deletions
diff --git a/src/import/generic/memory/lib/spd/spd_factory_pattern.H b/src/import/generic/memory/lib/spd/spd_factory_pattern.H index c0629c5c9..9d36738d4 100644 --- a/src/import/generic/memory/lib/spd/spd_factory_pattern.H +++ b/src/import/generic/memory/lib/spd/spd_factory_pattern.H @@ -22,3 +22,487 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ +/// +/// @file spd_factory_pattern.H +/// @brief SPD factory pattern declaration +/// + +// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com> +// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 2 +// *HWP Consumed by: HB:FSP + +#ifndef _MSS_SPD_FACTORY_PATTERN_H_ +#define _MSS_SPD_FACTORY_PATTERN_H_ + +#include <fapi2.H> +#include <cstdint> +#include <map> +#include <generic/memory/lib/spd/common/ddr4/spd_decoder_ddr4.H> +#include <generic/memory/lib/spd/rdimm/ddr4/rdimm_decoder_ddr4.H> +#include <generic/memory/lib/spd/lrdimm/ddr4/lrdimm_decoder_ddr4.H> +#include <generic/memory/lib/spd/spd_checker.H> +#include <generic/memory/lib/utils/shared/mss_generic_consts.H> + +namespace mss +{ +/// +/// @class moduleFactoryTraits +/// @brief class that holds module factory traits +/// @tparam T the decoder type we want the factory to generate +/// +template < typename T > +struct moduleFactoryTraits; + +/// +/// @class moduleFactoryTraits - base_cnfg_decoder specialization +/// @brief class that holds module factory traits +/// +template< > +struct moduleFactoryTraits<spd::base_cnfg_decoder> +{ + static constexpr generic_ffdc_codes MODULE_FACTORY_FFDC_CODE = BASE_CFG_FACTORY; +}; + +/// +/// @class moduleFactoryTraits - dimm_module_decoder specialization +/// @brief class that holds module factory traits +/// +template< > +struct moduleFactoryTraits<spd::dimm_module_decoder> +{ + static constexpr generic_ffdc_codes MODULE_FACTORY_FFDC_CODE = DIMM_MODULE_FACTORY; +}; + +namespace spd +{ + +/// +/// @class module_key +/// @brief SPD module key for factory +/// +struct module_key +{ + uint8_t iv_rev; + uint8_t iv_dram_gen; + parameters iv_param; + + /// + /// @brief default ctor + /// + module_key() = default; + + /// + /// @brief constexpr ctor + /// @param[in] i_dram_gen DRAM generation + /// @param[in] i_spd_param DIMM type + /// @param[in] i_rev SPD revision + /// + module_key(const uint8_t i_dram_gen, + const parameters i_spd_param, + const uint8_t i_rev); + + /// + /// @brief default dtor + /// + ~module_key() = default; + + /// + /// @brief less-than operator + /// @param[in] i_rhs the module_key + /// @return true or false + /// + bool operator<(const module_key& i_rhs) const; + +};// module_key + +/// +/// @brief Class that performs revision fallback +/// @class rev_fallback +/// +class rev_fallback +{ + public: + + /// + /// @brief ctor + /// @param[in] i_target the DIMM target + /// @param[in] i_key the module_key + /// + rev_fallback(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + const module_key& i_key); + + /// + /// @brief dtor + /// + ~rev_fallback() = default; + + /// + /// @brief Retrieves highest supported SPD revision + /// @param[out] o_rev SPD revision + /// @return FAPI2_RC_SUCCESS iff okay + /// + fapi2::ReturnCode get_supported_rev(uint8_t& o_rev) const; + + private: + + enum + { + LEN = 4, + ENCODINGS_REV_START = 0, + ADDITIONS_REV_START = 4, + }; + + fapi2::Target<fapi2::TARGET_TYPE_DIMM> iv_target; + module_key iv_key; + uint8_t iv_encoding_level; + uint8_t iv_additions_level; + + // Constants convenient for map indexing + const module_key LRDIMM_DDR4_V1_0; + const module_key LRDIMM_DDR4_V1_1; + const module_key LRDIMM_DDR4_V1_2; + + const module_key RDIMM_DDR4_V1_0; + const module_key RDIMM_DDR4_V1_1; + + const module_key NVDIMM_DDR4_V1_0; + const module_key NVDIMM_DDR4_V1_1; + + std::map<module_key, uint8_t> iv_lrdimm_rev_map; + std::map<module_key, uint8_t> iv_rdimm_rev_map; + std::map<module_key, uint8_t> iv_nvdimm_rev_map; + std::map< parameters, std::map<module_key, uint8_t> > iv_spd_param_map; + + /// + /// @brief Helper function to select the largest SPD revision + /// @param[in] i_map a map of supported SPD revisions for a certain SPD param + /// @param[out] o_rev the SPD Revision + /// @return FAPI2_RC_SUCCESS iff okay + /// + void select_highest_rev( const std::map<module_key, uint8_t>& i_map, + uint8_t& o_rev) const; + + /// + /// @brief Helper function to check non-backward compatible encoding level changes + /// @param[in] i_map Map of supported SPD revisions for a certain SPD param + /// @return FAPI2_RC_SUCCESS iff okay + /// + fapi2::ReturnCode check_encoding_level(const std::map<module_key, uint8_t>& i_map) const; +}; + +/// +/// @class module_factory +/// @tparam T module decoder type (e.g. base_cnfg_decoder, dimm_module_decoder) +/// @tparam TT defaulted to moduleFactoryTraits<T> +/// @brief Factory method for SPD module parameters +/// +template < typename T, typename TT = moduleFactoryTraits<T> > +class module_factory +{ + public: + + /// + /// @brief ctor + /// @param[in] i_target the DIMM target + /// @param[in] i_spd_data SPD data in a vector reference + /// + module_factory(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + const std::vector<uint8_t>& i_spd_data): + iv_target(i_target), + LRDIMM_DDR4_REV_1_0{DDR4, LRDIMM_MODULE, rev::V1_0}, + LRDIMM_DDR4_REV_1_1{DDR4, LRDIMM_MODULE, rev::V1_1}, + LRDIMM_DDR4_REV_1_2{DDR4, LRDIMM_MODULE, rev::V1_2}, + RDIMM_DDR4_REV_1_0{DDR4, RDIMM_MODULE, rev::V1_0}, + RDIMM_DDR4_REV_1_1{DDR4, RDIMM_MODULE, rev::V1_1}, + NVDIMM_DDR4_REV_1_0{DDR4, NVDIMM_MODULE, rev::V1_0}, + NVDIMM_DDR4_REV_1_1{DDR4, NVDIMM_MODULE, rev::V1_1} + { + // Setup pre-defined maps available to search through + init_map_vars(i_spd_data, iv_decoder_map); + } + + /// + /// @brief default dtor + /// + ~module_factory() = default; + + /// + /// @brief creates module_decoder object from key + /// @param[in,out] io_key the module key + /// @param[out] o_decoder_ptr the dimm_module_decoder object ptr + /// @return FAPI2_RC_SUCCESS iff okay + /// + fapi2::ReturnCode make_object(module_key& io_key, + std::shared_ptr<T>& o_decoder_ptr) const + { + auto it = iv_decoder_map.find(io_key); + + // If we found matching key, return that associated decoder + if(it != iv_decoder_map.end()) + { + o_decoder_ptr = it->second; + return fapi2::FAPI2_RC_SUCCESS; + } + + // If we are here that means we didn't find a matching key-value pair. + // So we will dig deeper to evaluate the issue and try to fallback to + // a supported (backward compatible) SPD revision. + FAPI_TRY( try_fallback(io_key, o_decoder_ptr) ); + + fapi_try_exit: + return fapi2::current_err; + } + + private: + + const fapi2::Target<fapi2::TARGET_TYPE_DIMM> iv_target; + + // Indexing member vars for convenient map indexing + const module_key LRDIMM_DDR4_REV_1_0; + const module_key LRDIMM_DDR4_REV_1_1; + const module_key LRDIMM_DDR4_REV_1_2; + const module_key RDIMM_DDR4_REV_1_0; + const module_key RDIMM_DDR4_REV_1_1; + const module_key NVDIMM_DDR4_REV_1_0; + const module_key NVDIMM_DDR4_REV_1_1; + + std::map< module_key, std::shared_ptr<T> > iv_decoder_map; + + /// + /// @brief Helper function to initialize base_cnfg_decoder map + /// @param[out] o_map base_cnfg_decoder map + /// + void init_map_vars(const std::vector<uint8_t>& i_spd_data, + std::map< module_key, std::shared_ptr<base_cnfg_decoder> >& o_map) + { + // + // RDIMMs + // + + // Rev 1.0 + // Life starts out at base revision level + o_map[RDIMM_DDR4_REV_1_0] = std::make_shared< decoder<DDR4, BASE_CNFG, rev::V1_0> >(iv_target, i_spd_data); + + // Rev 1.1 + // Changes to both the general section & rdimm section occured + o_map[RDIMM_DDR4_REV_1_1] = std::make_shared< decoder<DDR4, BASE_CNFG, rev::V1_1> >(iv_target, i_spd_data); + + // + // LRDIMMs + // + + // Rev 1.0 + // Life starts out at base revision level + o_map[LRDIMM_DDR4_REV_1_0] = std::make_shared< decoder<DDR4, BASE_CNFG, rev::V1_0> >(iv_target, i_spd_data); + + // Rev 1.1 + // Changes to both the general section & lrdimm section occured + o_map[LRDIMM_DDR4_REV_1_1] = std::make_shared< decoder<DDR4, BASE_CNFG, rev::V1_1> >(iv_target, i_spd_data); + + // Rev 1.2 + // Changes lrdimm section occured + // General section remained the same + o_map[LRDIMM_DDR4_REV_1_2] = std::make_shared< decoder<DDR4, BASE_CNFG, rev::V1_1> >(iv_target, i_spd_data); + + // + // NVDIMMs + // + + // Rev 1.0 + // NVDIMMs start out life w/the updated general section. + o_map[NVDIMM_DDR4_REV_1_0] = std::make_shared< decoder<DDR4, BASE_CNFG, rev::V1_1> >(iv_target, i_spd_data); + + // Rev 1.1 + // Changes to the NVDIMM module occured, general section remains the same + o_map[NVDIMM_DDR4_REV_1_1] = std::make_shared< decoder<DDR4, BASE_CNFG, rev::V1_1> >(iv_target, i_spd_data); + } + + /// + /// @brief Helper function to initialize dimm_module_decoder map + /// @param[out] o_map dimm_module_decoder map + /// + void init_map_vars(const std::vector<uint8_t>& i_spd_data, + std::map< module_key, std::shared_ptr<dimm_module_decoder> >& o_map) + { + // + // RDIMMs + // + + // Rev 1.0 + // Life starts out at base revision level + o_map[RDIMM_DDR4_REV_1_0] = std::make_shared< decoder<DDR4, RDIMM_MODULE, rev::V1_0> >(iv_target, i_spd_data); + + // Rev 1.1 + // Changes to both the general section & rdimm section occured + o_map[RDIMM_DDR4_REV_1_1] = std::make_shared< decoder<DDR4, RDIMM_MODULE, rev::V1_1> >(iv_target, i_spd_data); + + // + // LRDIMMs + // + + // Rev 1.0 + // Life starts out at base revision level + o_map[LRDIMM_DDR4_REV_1_0] = std::make_shared< decoder<DDR4, LRDIMM_MODULE, rev::V1_0> >(iv_target, i_spd_data); + + // Rev 1.1 + // Changes to both the general section & lrdimm section occured + o_map[LRDIMM_DDR4_REV_1_1] = std::make_shared< decoder<DDR4, LRDIMM_MODULE, rev::V1_1> >(iv_target, i_spd_data); + + // Rev 1.2 + // Changes lrdimm section occured + // General section remained the same + o_map[LRDIMM_DDR4_REV_1_2] = std::make_shared< decoder<DDR4, LRDIMM_MODULE, rev::V1_2> >(iv_target, i_spd_data); + } + + /// + /// @brief Try to fallback to a supported backward compatible decoder + /// @param[in,out] io_key the module key + /// @param[out] o_rev SPD revision we are falling back to + /// @return FAPI2_RC_SUCCESS iff okay + /// + fapi2::ReturnCode find_backward_compatible_rev(module_key& io_key) const + { + const rev_fallback l_rev_fallback(iv_target, io_key); + + // Overwrite io_key.iv_rev with a supported revision + FAPI_TRY(l_rev_fallback.get_supported_rev(io_key.iv_rev)); + + fapi_try_exit: + return fapi2::current_err; + } + + /// + /// @brief Create a decoder with the fallback module_key + /// @param[in] i_key the module key + /// @param[out] o_decoder_ptr decoder ptr + /// @return FAPI2_RC_SUCCESS iff okay + /// + fapi2::ReturnCode create_fallback_decoder(const module_key& i_key, + std::shared_ptr<T>& o_decoder_ptr) const + { + auto it = iv_decoder_map.find(i_key); + + // Sanity check, should never fail unless it's a programming error... + constexpr generic_ffdc_codes FFDC_CODE = TT::MODULE_FACTORY_FFDC_CODE; + + FAPI_ASSERT( it != iv_decoder_map.end(), + fapi2::MSS_FAILED_SPD_REVISION_FALLBACK() + .set_FAILED_REVISION(i_key.iv_rev) + .set_FUNCTION_CODE(FFDC_CODE) + .set_TARGET(iv_target), + "Failed to find a map value for the key (rev 0x%02, param %d, dram gen: %d", + i_key.iv_rev, i_key.iv_param, i_key.iv_dram_gen); + + // Update SPD rev to fallback rev + { + constexpr size_t REV_BYTE = 1; + o_decoder_ptr = it->second; + std::vector<uint8_t> l_spd_data = o_decoder_ptr->get_data(); + l_spd_data[REV_BYTE] = i_key.iv_rev; + o_decoder_ptr->set_data(l_spd_data); + } + + return fapi2::FAPI2_RC_SUCCESS; + + fapi_try_exit: + return fapi2::current_err; + } + + /// + /// @brief Try to fallback to a supported backward compatible decoder + /// @param[in,out] io_key the module key + /// @param[out] o_decoder_ptr the o_decoder_ptr object ptr + /// @return FAPI2_RC_SUCCESS iff okay + /// + fapi2::ReturnCode try_fallback(module_key& io_key, + std::shared_ptr<T>& o_decoder_ptr) const + { + const uint8_t l_dimm_type = io_key.iv_param == RDIMM_MODULE ? RDIMM : LRDIMM; + + // Invalid DRAM gen is a hard fail + FAPI_TRY(check::dram_gen(iv_target, io_key.iv_dram_gen, TT::MODULE_FACTORY_FFDC_CODE)); + + // Invalid DIMM type is a hard fail + FAPI_TRY(check::dimm_type(iv_target, l_dimm_type, TT::MODULE_FACTORY_FFDC_CODE)); + + // We can circumvent SPD revision fails by using backward compatible revisions + FAPI_TRY(find_backward_compatible_rev(io_key)); + + // Let's create a new decoder that we can fall back to + FAPI_TRY(create_fallback_decoder(io_key, o_decoder_ptr)); + + fapi_try_exit: + return fapi2::current_err; + } +}; + +/// +/// @class factories +/// @brief Factory method that creates the right decoder based on SPD data +/// +class factories +{ + public: + + /// + /// @brief ctor + /// @param[in] i_target the DIMM target + /// @param[in] i_spd_data SPD data in a vector reference + /// @param[out] o_rc FAPI2_RC_SUCCESS iff okay + /// + factories(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, + const std::vector<uint8_t>& i_spd_data, + fapi2::ReturnCode& o_rc); + + /// + /// @brief default dtor + /// + ~factories() = default; + + + /// + /// @brief creates base_cnfg_decoder object + /// @param[out] o_decoder_ptr the base_cnfg_decoder object ptr + /// @return FAPI2_RC_SUCCESS iff okay + /// + fapi2::ReturnCode create_decoder( std::shared_ptr<base_cnfg_decoder>& o_decoder_ptr ) const; + + /// + /// @brief creates dimm_module_decoder object + /// @param[out] o_decoder_ptr the dimm_module_decoder object ptr + /// @return FAPI2_RC_SUCCESS iff okay + /// + fapi2::ReturnCode create_decoder( std::shared_ptr<dimm_module_decoder>& o_decoder_ptr ) const; + + private: + + const fapi2::Target<fapi2::TARGET_TYPE_DIMM> iv_target; + std::vector<uint8_t> iv_spd_data; + uint8_t iv_rev; + uint8_t iv_dram_gen; + uint8_t iv_dimm_type; + uint8_t iv_hybrid; + uint8_t iv_hybrid_media; + + /// + /// @brief Helper to select SPD parameter for the dimm module + /// @param[out] o_param SPD parameter + /// @return FAPI2_RC_SUCCESS iff okay + /// + fapi2::ReturnCode dimm_module_select_param(parameters& o_param) const; + + /// + /// @brief Helper to select SPD parameter for the base cfg + /// @param[out] o_param SPD parameter + /// @return FAPI2_RC_SUCCESS iff okay + /// + fapi2::ReturnCode base_cfg_select_param(parameters& o_param) const; + +}; + +}// spd +}// mss + +#endif //_MSS_SPD_FACTORY_PATTERN_H_ |