summaryrefslogtreecommitdiffstats
path: root/src/import/generic/memory/lib/spd/spd_factory_pattern.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/import/generic/memory/lib/spd/spd_factory_pattern.C')
-rw-r--r--src/import/generic/memory/lib/spd/spd_factory_pattern.C331
1 files changed, 331 insertions, 0 deletions
diff --git a/src/import/generic/memory/lib/spd/spd_factory_pattern.C b/src/import/generic/memory/lib/spd/spd_factory_pattern.C
index bc58ff24f..dceb944fa 100644
--- a/src/import/generic/memory/lib/spd/spd_factory_pattern.C
+++ b/src/import/generic/memory/lib/spd/spd_factory_pattern.C
@@ -22,3 +22,334 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
+///
+/// @file spd_factory_pattern.C
+/// @brief SPD factory pattern implementation
+///
+
+// *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
+
+#include <generic/memory/lib/spd/spd_factory_pattern.H>
+
+namespace mss
+{
+namespace spd
+{
+
+///
+/// @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::module_key(const uint8_t i_dram_gen,
+ const parameters i_spd_param,
+ const uint8_t i_rev):
+ iv_rev(i_rev),
+ iv_dram_gen(i_dram_gen),
+ iv_param(i_spd_param)
+{}
+
+///
+/// @brief less-than operator
+/// @param[in] i_rhs the module_key
+/// @return true or false
+///
+bool module_key::operator<(const module_key& i_rhs) const
+{
+ // Impose weak strict ordering for dram_gen
+ // by dram gen, dimm type, and then revision
+ if(iv_dram_gen != i_rhs.iv_dram_gen)
+ {
+ return iv_dram_gen < i_rhs.iv_dram_gen;
+ }
+
+ // If we are here than iv_param == i_key.iv_param
+ // Impose weak strict ordering for encoding_level
+ if( iv_param != i_rhs.iv_param)
+ {
+ return iv_param < i_rhs.iv_param;
+ }
+
+ // If we are here than iv_encoding_level == i_key.iv_encoding_leve
+ // Impose weak strict ordering for additions_level
+ if( iv_rev != i_rhs.iv_rev)
+ {
+ return iv_rev < i_rhs.iv_rev;
+ }
+
+ return false;
+}
+
+///
+/// @brief ctor
+/// @param[in] i_target the DIMM target
+/// @param[in] i_key the module_key
+///
+rev_fallback::rev_fallback(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ const module_key& i_key):
+ iv_target(i_target),
+ iv_key(i_key),
+ iv_encoding_level(0),
+ iv_additions_level(0),
+ LRDIMM_DDR4_V1_0{DDR4, LRDIMM_MODULE, rev::V1_0},
+ LRDIMM_DDR4_V1_1{DDR4, LRDIMM_MODULE, rev::V1_1},
+ LRDIMM_DDR4_V1_2{DDR4, LRDIMM_MODULE, rev::V1_2},
+ RDIMM_DDR4_V1_0{DDR4, RDIMM_MODULE, rev::V1_0},
+ RDIMM_DDR4_V1_1{DDR4, RDIMM_MODULE, rev::V1_1},
+ NVDIMM_DDR4_V1_0{DDR4, NVDIMM_MODULE, rev::V1_0},
+ NVDIMM_DDR4_V1_1{DDR4, NVDIMM_MODULE, rev::V1_1}
+{
+ // Member variable initialization
+ fapi2::buffer<uint8_t> l_buffer(i_key.iv_rev);
+ l_buffer.extractToRight<ENCODINGS_REV_START, LEN>(iv_encoding_level);
+ l_buffer.extractToRight<ADDITIONS_REV_START, LEN>(iv_additions_level);
+
+ // Setup pre-defined maps available to search through
+ // 3 diff mappings because each map has an independently
+ // managed revision.
+ iv_rdimm_rev_map[RDIMM_DDR4_V1_0] = rev::V1_0;
+ iv_rdimm_rev_map[RDIMM_DDR4_V1_1] = rev::V1_1;
+
+ iv_lrdimm_rev_map[LRDIMM_DDR4_V1_0] = rev::V1_0;
+ iv_lrdimm_rev_map[LRDIMM_DDR4_V1_1] = rev::V1_1;
+ iv_lrdimm_rev_map[LRDIMM_DDR4_V1_2] = rev::V1_2;
+
+ iv_nvdimm_rev_map[NVDIMM_DDR4_V1_0] = rev::V1_1;
+ iv_nvdimm_rev_map[NVDIMM_DDR4_V1_1] = rev::V1_1;
+
+ // Another small map to select the right map based on module
+ iv_spd_param_map[RDIMM_MODULE] = iv_rdimm_rev_map;
+ iv_spd_param_map[LRDIMM_MODULE] = iv_lrdimm_rev_map;
+ iv_spd_param_map[NVDIMM_MODULE] = iv_nvdimm_rev_map;
+}
+
+///
+/// @brief Retrieves highest supported SPD revision
+/// @param[out] o_rev SPD revision
+/// @return FAPI2_RC_SUCCESS iff okay
+///
+fapi2::ReturnCode rev_fallback::get_supported_rev(uint8_t& o_rev) const
+{
+ std::map<module_key, uint8_t> l_map;
+
+ auto it = iv_spd_param_map.find(iv_key.iv_param);
+ FAPI_ASSERT(it != iv_spd_param_map.end(),
+ fapi2::MSS_INVALID_SPD_PARAMETER_RECEIVED()
+ .set_SPD_PARAM(iv_key.iv_param)
+ .set_FUNCTION_CODE(GET_SUPPORTED_REV)
+ .set_TARGET(iv_target),
+ "Invalid SPD parameter received %d for %s",
+ iv_key.iv_param, spd::c_str(iv_target));
+
+ l_map = it->second;
+ FAPI_TRY( check_encoding_level(l_map) );
+
+ // The logic is easier to handle only additions level changes.
+ // This source will need to be updated to handle encodings level changes
+ // (rare occurance that hasn't happened yet...) and will be caught with the conditional above.
+ select_highest_rev(l_map, o_rev);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @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 rev_fallback::select_highest_rev( const std::map<module_key, uint8_t>& i_map,
+ uint8_t& o_rev) const
+{
+ // When encoding revisions are the same and only
+ // addition revisions differ, setting are backward
+ // compatible. This means if we hit a case where
+ // the additions level is not in our existing list of
+ // decoders we can default to the highest decoded revision.
+ // (e.g. If the DRAM is rev 1.3 but we have only decoded up
+ // to rev 1.1, we can safely default to rev 1.1 accepting
+ // that we lose features that may exist in higher revisions).
+ auto it = i_map.end();
+ o_rev = (--it)->second;
+}
+
+///
+/// @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 rev_fallback::check_encoding_level(const std::map<module_key, uint8_t>& i_map) const
+{
+ // A change in encoding revision breaks backward compatability,
+ // (e.g. revision 2.# is not backwards compatible with revision 1.#,
+ // for some integer #).
+ auto it = --(i_map.end());
+ const uint8_t l_highest_possible_rev = it->second;
+ const fapi2::buffer<uint8_t> l_buffer(l_highest_possible_rev);
+
+ uint8_t l_last_valid_encoding_lvl = 0;
+ l_buffer.extractToRight<ENCODINGS_REV_START, LEN>(l_last_valid_encoding_lvl);
+
+ FAPI_INF("Highest valid rev 0x%02x, Highest valid encoding level %d, encoding level received %d for %s",
+ l_highest_possible_rev, l_last_valid_encoding_lvl, iv_encoding_level, spd::c_str(iv_target));
+
+ FAPI_ASSERT( iv_encoding_level <= l_last_valid_encoding_lvl,
+ fapi2::MSS_SPD_REV_ENCODING_LEVEL_NOT_SUPPORTED()
+ .set_ENCODING_LEVEL(iv_encoding_level)
+ .set_TARGET(iv_target),
+ "SPD revision encoding level (%d) is greater than largest decode (%d) for %s",
+ iv_encoding_level, l_last_valid_encoding_lvl, spd::c_str(iv_target));
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @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::factories(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ const std::vector<uint8_t>& i_spd_data,
+ fapi2::ReturnCode& o_rc):
+ iv_target(i_target),
+ iv_spd_data(i_spd_data)
+{
+ FAPI_TRY( (reader<init_fields::REVISION, spd::rev::GEN_SEC_MAX>(i_target, i_spd_data, iv_rev)),
+ "Failed to read REVISION field for %s", spd::c_str(i_target) );
+ FAPI_TRY( (reader<init_fields::BASE_MODULE, spd::rev::GEN_SEC_MAX>(i_target, i_spd_data, iv_dimm_type)),
+ "Failed to read BASE_MODULE field for %s", spd::c_str(i_target) );
+ FAPI_TRY( (reader<init_fields::DEVICE_TYPE, spd::rev::GEN_SEC_MAX>(i_target, i_spd_data, iv_dram_gen)),
+ "Failed to read DEVICE_TYPE field for %s", spd::c_str(i_target) );
+ FAPI_TRY( (reader<init_fields::HYBRID, spd::rev::GEN_SEC_MAX>(i_target, i_spd_data, iv_hybrid)),
+ "Failed to read HYBRID field for %s", spd::c_str(i_target) );
+ FAPI_TRY( (reader<init_fields::HYBRID_MEDIA, spd::rev::GEN_SEC_MAX>(i_target, i_spd_data, iv_hybrid_media)),
+ "Failed to read HYBRID_MEDIA field for %s", spd::c_str(i_target) );
+
+ o_rc = fapi2::FAPI2_RC_SUCCESS;
+ return;
+
+fapi_try_exit:
+ o_rc = fapi2::current_err;
+}
+
+///
+/// @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 factories::create_decoder( std::shared_ptr<base_cnfg_decoder>& o_decoder_ptr ) const
+{
+ parameters l_param = UNINITIALIZED;
+ FAPI_TRY(base_cfg_select_param(l_param));
+
+ {
+ auto l_factory_key = module_key(iv_dram_gen, l_param, iv_rev);
+
+ const module_factory<base_cnfg_decoder> l_decoder(iv_target, iv_spd_data);
+ FAPI_TRY( l_decoder.make_object(l_factory_key, o_decoder_ptr) );
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @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 factories::create_decoder( std::shared_ptr<dimm_module_decoder>& o_decoder_ptr ) const
+{
+ parameters l_param = UNINITIALIZED;
+ FAPI_TRY(dimm_module_select_param(l_param));
+
+ {
+ auto l_factory_key = module_key(iv_dram_gen, l_param, iv_rev);
+
+ const module_factory<dimm_module_decoder> l_decoder(iv_target, iv_spd_data);
+ FAPI_TRY( l_decoder.make_object(l_factory_key, o_decoder_ptr) );
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Helper to select SPD parameter for the dimm module
+/// @param[out] o_param SPD parameter
+/// @return FAPI2_RC_SUCCESS iff okay
+///
+fapi2::ReturnCode factories::dimm_module_select_param(parameters& o_param) const
+{
+ switch(iv_dimm_type)
+ {
+ case RDIMM:
+ o_param = RDIMM_MODULE;
+ break;
+
+ case LRDIMM:
+ o_param = LRDIMM_MODULE;
+ break;
+
+ default:
+ FAPI_ASSERT(false,
+ fapi2::MSS_INVALID_DIMM_TYPE()
+ .set_DIMM_TYPE(iv_dimm_type)
+ .set_FUNCTION(DIMM_MODULE_PARAM_SELECT)
+ .set_DIMM_TARGET(iv_target),
+ "Invalid DIMM type recieved (%d) for %s",
+ iv_dimm_type, spd::c_str(iv_target));
+ break;
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Helper to select SPD parameter for the base cfg
+/// @param[out] o_param SPD parameter
+/// @return FAPI2_RC_SUCCESS iff okay
+///
+fapi2::ReturnCode factories::base_cfg_select_param(parameters& o_param) const
+{
+ if(iv_hybrid == HYBRID && iv_hybrid_media == NVDIMM_HYBRID)
+ {
+ // The general section used for NVDIMMs is different than
+ // those for LRDIMM and RDIMM modules.
+ o_param = NVDIMM_MODULE;
+ return fapi2::FAPI2_RC_SUCCESS;
+ }
+
+ // If we are here let's make sure we are not hybrid, sanity
+ // check to assure we don't have invalid hybrid combination
+ FAPI_ASSERT(iv_hybrid == NOT_HYBRID &&
+ iv_hybrid_media == NOT_HYBRID,
+ fapi2::MSS_INVALID_HYBRID_MODULE().
+ set_HYBRID(iv_hybrid).
+ set_HYBRID_MEDIA(iv_hybrid_media).
+ set_FUNCTION(BASE_CFG_PARAM_SELECT).
+ set_TARGET(iv_target),
+ "Invalid hybrid (%d) or hybrid_media (%d) for %s",
+ iv_hybrid, iv_hybrid_media, spd::c_str(iv_target));
+
+ FAPI_TRY(dimm_module_select_param(o_param));
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+}// spd
+}// mss
OpenPOWER on IntegriCloud