summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory/lib
diff options
context:
space:
mode:
authorStephen Glancy <sglancy@us.ibm.com>2019-03-14 14:42:54 -0400
committerChristian R Geddes <crgeddes@us.ibm.com>2019-07-30 11:38:49 -0500
commit4a69b75341c33bada63ee7d92fda913ebe68fb8d (patch)
treecacde181ece72818e7855037603c5f0816ea24a7 /src/import/chips/p9/procedures/hwp/memory/lib
parent1552e3875f35b41928ffb6c63578c561c8324493 (diff)
downloadtalos-hostboot-4a69b75341c33bada63ee7d92fda913ebe68fb8d.tar.gz
talos-hostboot-4a69b75341c33bada63ee7d92fda913ebe68fb8d.zip
Adds LRDIMM shadow register workaround
Change-Id: Ice8c2e4e420394d3c6970b2f635792d8060c8e37 Original-Change-Id: I8c0ad45871dc51d6e12c94c530e19b3d3a26ab7c Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/73318 Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Dev-Ready: STEPHEN GLANCY <sglancy@us.ibm.com> Tested-by: HWSV CI <hwsv-ci+hostboot@us.ibm.com> Reviewed-by: Louis Stermole <stermole@us.ibm.com> Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com> Reviewed-by: ANDRE A. MARIN <aamarin@us.ibm.com> Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com> Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/81322 Reviewed-by: Christian R Geddes <crgeddes@us.ibm.com> Tested-by: Christian R Geddes <crgeddes@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9/procedures/hwp/memory/lib')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/workarounds/quad_encode_workarounds.C255
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/workarounds/quad_encode_workarounds.H373
2 files changed, 628 insertions, 0 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/quad_encode_workarounds.C b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/quad_encode_workarounds.C
new file mode 100644
index 000000000..b09ab6f70
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/quad_encode_workarounds.C
@@ -0,0 +1,255 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/workarounds/quad_encode_workarounds.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2019 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file quad_encode_workarounds.C
+/// @brief Contains workarounds having to do with quad-encode CS
+///
+// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com>
+// *HWP HWP Backup: Louis Stermole <stermole@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 3
+// *HWP Consumed by: FSP:HB Memory Lab
+
+#include <lib/shared/nimbus_defaults.H>
+#include <fapi2.H>
+#include <p9n2_mc_scom_addresses.H>
+
+#include <generic/memory/lib/utils/c_str.H>
+#include <generic/memory/lib/utils/find.H>
+#include <lib/ccs/ccs.H>
+#include <lib/mss_attribute_accessors.H>
+#include <lib/dimm/ddr4/mrs_load_ddr4.H>
+#include <lib/workarounds/quad_encode_workarounds.H>
+
+namespace mss
+{
+
+namespace workarounds
+{
+
+const std::vector< uint64_t> shadow_regs_traits<0>::REGS =
+{
+ P9N2_MCA_DDRPHY_PC_MR0_RP0_P0,
+ P9N2_MCA_DDRPHY_PC_MR0_RP1_P0,
+ P9N2_MCA_DDRPHY_PC_MR0_RP2_P0,
+ P9N2_MCA_DDRPHY_PC_MR0_RP3_P0,
+};
+const std::vector< uint64_t> shadow_regs_traits<1>::REGS =
+{
+ P9N2_MCA_DDRPHY_PC_MR1_RP0_P0,
+ P9N2_MCA_DDRPHY_PC_MR1_RP1_P0,
+ P9N2_MCA_DDRPHY_PC_MR1_RP2_P0,
+ P9N2_MCA_DDRPHY_PC_MR1_RP3_P0,
+};
+const std::vector< uint64_t> shadow_regs_traits<2>::REGS =
+{
+ P9N2_MCA_DDRPHY_PC_MR2_RP0_P0,
+ P9N2_MCA_DDRPHY_PC_MR2_RP1_P0,
+ P9N2_MCA_DDRPHY_PC_MR2_RP2_P0,
+ P9N2_MCA_DDRPHY_PC_MR2_RP3_P0,
+};
+const std::vector< uint64_t> shadow_regs_traits<3>::REGS =
+{
+ P9N2_MCA_DDRPHY_PC_MR3_RP0_P0,
+ P9N2_MCA_DDRPHY_PC_MR3_RP1_P0,
+ P9N2_MCA_DDRPHY_PC_MR3_RP2_P0,
+ P9N2_MCA_DDRPHY_PC_MR3_RP3_P0,
+};
+const std::vector< uint64_t> shadow_regs_traits<4>::REGS =
+{
+ P9N2_MCA_DDRPHY_PC_MR4_RP0_P0,
+ P9N2_MCA_DDRPHY_PC_MR4_RP1_P0,
+ P9N2_MCA_DDRPHY_PC_MR4_RP2_P0,
+ P9N2_MCA_DDRPHY_PC_MR4_RP3_P0,
+};
+const std::vector< uint64_t> shadow_regs_traits<5>::REGS =
+{
+ P9N2_MCA_DDRPHY_PC_MR5_RP0_P0,
+ P9N2_MCA_DDRPHY_PC_MR5_RP1_P0,
+ P9N2_MCA_DDRPHY_PC_MR5_RP2_P0,
+ P9N2_MCA_DDRPHY_PC_MR5_RP3_P0,
+};
+const std::vector< uint64_t> shadow_regs_traits<6>::REGS =
+{
+ P9N2_MCA_DDRPHY_PC_MR6_RP0_P0,
+ P9N2_MCA_DDRPHY_PC_MR6_RP1_P0,
+ P9N2_MCA_DDRPHY_PC_MR6_RP2_P0,
+ P9N2_MCA_DDRPHY_PC_MR6_RP3_P0,
+};
+
+///
+/// @brief Returns true if an MRS command was run
+/// @param[in] i_inst instruction to check for an MRS command
+/// @return true iff the command contains an MRS command
+///
+bool is_command_mrs(const ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& i_inst)
+{
+ // An MRS command is
+ // 1) at least one chip select active
+ // 2) at ACT HI, RAS/CAS/WEN low
+ // 3) not BA7
+
+ const auto l_cs_low = !i_inst.arr0.getBit<MCBIST_CCS_INST_ARR0_00_DDR_CSN_0_1>() ||
+ !i_inst.arr0.getBit < MCBIST_CCS_INST_ARR0_00_DDR_CSN_0_1 + 1 > () ||
+ !i_inst.arr0.getBit<MCBIST_CCS_INST_ARR0_00_DDR_CSN_2_3>() ||
+ !i_inst.arr0.getBit < MCBIST_CCS_INST_ARR0_00_DDR_CSN_2_3 + 1 > ();
+
+ const auto l_mrs_cmd = i_inst.arr0.getBit<MCBIST_CCS_INST_ARR0_00_DDR_ACTN>() &&
+ !i_inst.arr0.getBit<MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_16>() &&
+ !i_inst.arr0.getBit<MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_15>() &&
+ !i_inst.arr0.getBit<MCBIST_CCS_INST_ARR0_00_DDR_ADDRESS_14>();
+
+ const auto l_mrs_ba = !i_inst.arr0.getBit<MCBIST_CCS_INST_ARR0_00_DDR_BANK_0_1>() ||
+ !i_inst.arr0.getBit < MCBIST_CCS_INST_ARR0_00_DDR_BANK_0_1 + 1 > () ||
+ !i_inst.arr0.getBit<MCBIST_CCS_INST_ARR0_00_DDR_BANK_GROUP_0>();
+ return l_cs_low && l_mrs_cmd && l_mrs_ba;
+}
+///
+/// @brief Returns true if a vector of commands contains an MRS command
+/// @param[in] i_inst instruction to check for an MRS command
+/// @return true iff the command contains an MRS command
+///
+bool contains_command_mrs(const std::vector<ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>>& i_inst)
+{
+ bool l_contains_mrs = false;
+
+ for(const auto& l_inst : i_inst)
+ {
+ l_contains_mrs = is_command_mrs(l_inst);
+
+ if(l_contains_mrs)
+ {
+ FAPI_DBG("0x%016lx is an MRS command. Exiting", uint64_t(l_inst.arr0));
+ break;
+ }
+ }
+
+ return l_contains_mrs;
+}
+
+///
+/// @brief Fixes shadow register corruption over all ranks if needed
+/// @param[in] i_target - the DIMM target on which to operate
+/// @return fapi2::ReturnCode - SUCCESS iff everything executes successfully
+///
+fapi2::ReturnCode fix_shadow_register_corruption( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
+{
+ std::vector< uint64_t > l_ranks;
+ FAPI_TRY(mss::rank::primary_ranks( i_target, l_ranks ));
+
+ for(const auto l_rank : l_ranks)
+ {
+ FAPI_TRY(fix_shadow_register_corruption(i_target, l_rank));
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Fixes shadow register corruption if needed
+/// @param[in] i_target - the DIMM target on which to operate
+/// @param[in] i_rank - the rank on which to operate
+/// @return fapi2::ReturnCode - SUCCESS iff everything executes successfully
+///
+fapi2::ReturnCode fix_shadow_register_corruption( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rank)
+{
+ fapi2::Target<fapi2::TARGET_TYPE_DIMM> l_dimm;
+ const auto l_dimm_rank = mss::index(i_rank);
+ uint64_t l_rp = 0;
+ bool l_fix_needed = false;
+
+ // In this case, the rank is really to get the DIMM in question
+ FAPI_TRY(mss::rank::get_dimm_target_from_rank(i_target, i_rank, l_dimm),
+ "%s failed to get DIMM from rank%u", mss::c_str(i_target), i_rank);
+
+ FAPI_TRY(check_shadow_register_corruption(l_dimm, i_rank, l_fix_needed),
+ "%s failed to check if the fix is needed", mss::c_str(i_target));
+
+ // If the fix isn't needed, exit out
+ if(!l_fix_needed)
+ {
+ FAPI_INF("%s workaround not needed. Skipping", mss::c_str(i_target));
+ return fapi2::FAPI2_RC_SUCCESS;
+ }
+
+ // Shadow registers are on a per-rank pair basis
+ FAPI_TRY(mss::rank::get_pair_from_rank(i_target, i_rank, l_rp),
+ "%s rank%u failed to get RP nominal values", mss::c_str(i_target), i_rank);
+
+ FAPI_TRY(fix_shadow_register_corruption_mr<0>(l_dimm, l_rp, l_dimm_rank),
+ "%s failed to fix shadow regs on MR0", mss::c_str(i_target));
+ FAPI_TRY(fix_shadow_register_corruption_mr<1>(l_dimm, l_rp, l_dimm_rank),
+ "%s failed to fix shadow regs on MR1", mss::c_str(i_target));
+ FAPI_TRY(fix_shadow_register_corruption_mr<2>(l_dimm, l_rp, l_dimm_rank),
+ "%s failed to fix shadow regs on MR2", mss::c_str(i_target));
+ FAPI_TRY(fix_shadow_register_corruption_mr<3>(l_dimm, l_rp, l_dimm_rank),
+ "%s failed to fix shadow regs on MR3", mss::c_str(i_target));
+ FAPI_TRY(fix_shadow_register_corruption_mr<4>(l_dimm, l_rp, l_dimm_rank),
+ "%s failed to fix shadow regs on MR4", mss::c_str(i_target));
+ FAPI_TRY(fix_shadow_register_corruption_mr<5>(l_dimm, l_rp, l_dimm_rank),
+ "%s failed to fix shadow regs on MR5", mss::c_str(i_target));
+ FAPI_TRY(fix_shadow_register_corruption_mr<6>(l_dimm, l_rp, l_dimm_rank),
+ "%s failed to fix shadow regs on MR6", mss::c_str(i_target));
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @param[in] i_target - the DIMM target on which to operate
+/// @param[in] i_rank - the rank on which to operate
+/// @param[out] o_fix_needed - true iff the shadow register's could be corrupted (aka are we a 4R DIMM?)
+/// @return fapi2::ReturnCode - SUCCESS iff everything executes successfully
+///
+
+fapi2::ReturnCode check_shadow_register_corruption( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ const uint64_t i_rank,
+ bool& o_fix_needed)
+{
+ // Number of master ranks for this DIMM - if we have 4, we need the workaround
+ // Also, always run the workaround if we have an LRDIMM
+ constexpr uint8_t RANKS_FOR_FIX_NEEDED = 4;
+ uint8_t l_master_ranks = 0;
+ uint8_t l_dimm_type = 0;
+ o_fix_needed = false;
+
+ FAPI_TRY(mss::eff_num_master_ranks_per_dimm(i_target, l_master_ranks), "%s failed to get master ranks",
+ mss::c_str(i_target));
+ FAPI_TRY(mss::eff_dimm_type(i_target, l_dimm_type), "%s failed to get dimm_type",
+ mss::c_str(i_target));
+ o_fix_needed = (l_master_ranks == RANKS_FOR_FIX_NEEDED) ||
+ (l_dimm_type == fapi2::ENUM_ATTR_EFF_DIMM_TYPE_LRDIMM);
+ FAPI_INF("%s workaround %s needed. num master ranks %u dimm type %u", mss::c_str(i_target), o_fix_needed ? "is" : "not",
+ l_master_ranks, l_dimm_type);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+} // ns workarounds
+} // ns mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/quad_encode_workarounds.H b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/quad_encode_workarounds.H
new file mode 100644
index 000000000..cb062e9ac
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/workarounds/quad_encode_workarounds.H
@@ -0,0 +1,373 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/workarounds/quad_encode_workarounds.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2019 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file quad_encode_workaround.H
+/// @brief Contains workarounds having to do with quad-encode CS
+///
+// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com>
+// *HWP HWP Backup: Louis Stermole <stermole@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 3
+// *HWP Consumed by: FSP:HB Memory Lab
+
+#ifndef _QUAD_ENCODE_WORKAROUND_H_
+#define _QUAD_ENCODE_WORKAROUND_H_
+
+#include <fapi2.H>
+#include <p9_mc_scom_addresses.H>
+
+#include <lib/shared/mss_const.H>
+#include <generic/memory/lib/utils/c_str.H>
+#include <generic/memory/lib/utils/find.H>
+#include <lib/ccs/ccs.H>
+#include <lib/dimm/rank.H>
+#include <lib/dimm/ddr4/mrs_load_ddr4.H>
+#include <p9_mc_scom_addresses_fld.H>
+
+namespace mss
+{
+
+namespace workarounds
+{
+
+static constexpr uint64_t MAX_MR = 6;
+
+///
+/// @brief Fixes shadow register corruption over all ranks if needed
+/// @param[in] i_target - the DIMM target on which to operate
+/// @return fapi2::ReturnCode - SUCCESS iff everything executes successfully
+///
+fapi2::ReturnCode fix_shadow_register_corruption( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target);
+
+///
+/// @brief Fixes shadow register corruption if needed
+/// @param[in] i_target - the DIMM target on which to operate
+/// @param[in] i_rank - the rank on which to operate
+/// @return fapi2::ReturnCode - SUCCESS iff everything executes successfully
+///
+fapi2::ReturnCode fix_shadow_register_corruption( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_rank);
+
+///
+/// @param[in] i_target - the DIMM target on which to operate
+/// @param[in] i_rank - the rank on which to operate
+/// @param[out] o_fix_needed - true iff the shadow register's could be corrupted (aka are we a 4R DIMM?)
+/// @return fapi2::ReturnCode - SUCCESS iff everything executes successfully
+///
+
+fapi2::ReturnCode check_shadow_register_corruption( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ const uint64_t i_rank,
+ bool& o_fix_needed);
+
+///
+/// @brief Returns true if an MRS command was run
+/// @param[in] i_inst instruction to check for an MRS command
+/// @return true iff the command contains an MRS command
+///
+bool is_command_mrs(const ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& i_inst);
+
+///
+/// @brief Returns true if a vector of commands contains an MRS command
+/// @param[in] i_inst instruction to check for an MRS command
+/// @return true iff the command contains an MRS command
+///
+bool contains_command_mrs(const std::vector<ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>>& i_inst);
+
+///
+/// @brief Converts the CCS instructions to the shadow register configuration
+/// @param[in] i_inst CCS instruction to convert
+/// @return the register value for the shadow register
+///
+inline fapi2::buffer<uint64_t> convert_to_shadow_reg(const ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& i_inst)
+{
+ fapi2::buffer<uint64_t> l_arr0(i_inst.arr0);
+ mss::reverse(l_arr0);
+ constexpr uint64_t SHADOW_REG_START = 50;
+ l_arr0.clearBit<0, SHADOW_REG_START>();
+ return l_arr0;
+}
+
+///
+/// @class shadow_regs_traits
+/// @brief a collection of traits associated with each shadow register
+/// @tparam MR the MR number for which to fix the shadow regs
+///
+template< uint64_t MR >
+class shadow_regs_traits;
+
+///
+/// @class shadow_regs_traits
+/// @brief a collection of traits associated with each shadow register - specialization for MR0
+///
+template<>
+class shadow_regs_traits<0>
+{
+ public:
+
+ static const std::vector<uint64_t> REGS;
+
+ ///
+ /// @brief Configure the ARR0 of the CCS isntruction for mrs00
+ /// @param[in] i_target a fapi2::Target<fapi2::TARGET_TYPE_DIMM>
+ /// @param[in,out] io_inst the instruction to fixup
+ /// @param[in] i_rank ths rank in question
+ /// @return FAPI2_RC_SUCCESS iff OK
+ ///
+ static inline fapi2::ReturnCode mrs_gen(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& io_inst,
+ const uint64_t i_rank)
+ {
+ constexpr uint8_t LR_2666_MARGIN_ADJUST = 2;
+
+ // So, why is MRS0 being reset differently compared to the other mode register sets?
+ // For LRDIMM, at 2666, we're running at the edge of the PHY's capabilities to account for the read delay
+ // This means, we've started taking some fails related to not being able to wait long enough for the data to come back
+ // A handy workaround for this is to increase our CAS latency within the PHY itself by changing the value of the mode register
+ // This tricks the PHY's snooping capabilities to think that the data is coming back a bit later
+ // This allows the gate delay and RLO to account for the increased delay correctly
+ // Note: we need the DRAM to send the data back at the same time, but fake the PHY into thinking that it's coming later
+
+ uint8_t l_dimm_type = 0;
+ uint64_t l_freq = 0;
+
+ // Check to make sure our ctor worked ok
+ mss::ddr4::mrs00_data l_data( i_target, fapi2::current_err );
+ FAPI_TRY( fapi2::current_err, "%s Unable to construct MRS00 data from attributes", mss::c_str(i_target) );
+ FAPI_TRY( mss::eff_dimm_type(i_target, l_dimm_type));
+ FAPI_TRY( mss::freq(mss::find_target<fapi2::TARGET_TYPE_MCBIST>(i_target), l_freq));
+
+ // Apply the CAS latency offset if we have an LRDIMM at 2666
+ l_data.iv_cas_latency += ((l_dimm_type == fapi2::ENUM_ATTR_EFF_DIMM_TYPE_LRDIMM) &&
+ (l_freq == fapi2::ENUM_ATTR_MSS_FREQ_MT2666)) ?
+ LR_2666_MARGIN_ADJUST : 0;
+ FAPI_TRY( mss::ddr4::mrs00(i_target, l_data, io_inst, i_rank) );
+ fapi_try_exit:
+ return fapi2::current_err;
+ };
+};
+
+///
+/// @class shadow_regs_traits
+/// @brief a collection of traits associated with each shadow register - specialization for MR1
+///
+template<>
+class shadow_regs_traits<1>
+{
+ public:
+
+ static const std::vector<uint64_t> REGS;
+
+ ///
+ /// @brief Configure the ARR0 of the CCS isntruction for mrs00
+ /// @param[in] i_target a fapi2::Target<fapi2::TARGET_TYPE_DIMM>
+ /// @param[in,out] io_inst the instruction to fixup
+ /// @param[in] i_rank ths rank in question
+ /// @return FAPI2_RC_SUCCESS iff OK
+ ///
+ static inline fapi2::ReturnCode mrs_gen(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& io_inst,
+ const uint64_t i_rank)
+ {
+ return mss::ddr4::mrs01(i_target, io_inst, i_rank);
+ };
+};
+
+///
+/// @class shadow_regs_traits
+/// @brief a collection of traits associated with each shadow register - specialization for MR2
+///
+template<>
+class shadow_regs_traits<2>
+{
+ public:
+
+ static const std::vector<uint64_t> REGS;
+
+ ///
+ /// @brief Configure the ARR0 of the CCS isntruction for mrs00
+ /// @param[in] i_target a fapi2::Target<fapi2::TARGET_TYPE_DIMM>
+ /// @param[in,out] io_inst the instruction to fixup
+ /// @param[in] i_rank ths rank in question
+ /// @return FAPI2_RC_SUCCESS iff OK
+ ///
+ static inline fapi2::ReturnCode mrs_gen(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& io_inst,
+ const uint64_t i_rank)
+ {
+ return mss::ddr4::mrs02(i_target, io_inst, i_rank);
+ };
+};
+
+///
+/// @class shadow_regs_traits
+/// @brief a collection of traits associated with each shadow register - specialization for MR3
+///
+template<>
+class shadow_regs_traits<3>
+{
+ public:
+
+ static const std::vector<uint64_t> REGS;
+
+ ///
+ /// @brief Configure the ARR0 of the CCS isntruction for mrs00
+ /// @param[in] i_target a fapi2::Target<fapi2::TARGET_TYPE_DIMM>
+ /// @param[in,out] io_inst the instruction to fixup
+ /// @param[in] i_rank ths rank in question
+ /// @return FAPI2_RC_SUCCESS iff OK
+ ///
+ static inline fapi2::ReturnCode mrs_gen(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& io_inst,
+ const uint64_t i_rank)
+ {
+ return mss::ddr4::mrs03(i_target, io_inst, i_rank);
+ };
+};
+
+///
+/// @class shadow_regs_traits
+/// @brief a collection of traits associated with each shadow register - specialization for MR4
+///
+template<>
+class shadow_regs_traits<4>
+{
+ public:
+
+ static const std::vector<uint64_t> REGS;
+
+ ///
+ /// @brief Configure the ARR0 of the CCS isntruction for mrs00
+ /// @param[in] i_target a fapi2::Target<fapi2::TARGET_TYPE_DIMM>
+ /// @param[in,out] io_inst the instruction to fixup
+ /// @param[in] i_rank ths rank in question
+ /// @return FAPI2_RC_SUCCESS iff OK
+ ///
+ static inline fapi2::ReturnCode mrs_gen(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& io_inst,
+ const uint64_t i_rank)
+ {
+ return mss::ddr4::mrs04(i_target, io_inst, i_rank);
+ };
+};
+
+///
+/// @class shadow_regs_traits
+/// @brief a collection of traits associated with each shadow register - specialization for MR5
+///
+template<>
+class shadow_regs_traits<5>
+{
+ public:
+
+ static const std::vector<uint64_t> REGS;
+
+ ///
+ /// @brief Configure the ARR0 of the CCS isntruction for mrs00
+ /// @param[in] i_target a fapi2::Target<fapi2::TARGET_TYPE_DIMM>
+ /// @param[in,out] io_inst the instruction to fixup
+ /// @param[in] i_rank ths rank in question
+ /// @return FAPI2_RC_SUCCESS iff OK
+ ///
+ static inline fapi2::ReturnCode mrs_gen(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& io_inst,
+ const uint64_t i_rank)
+ {
+ return mss::ddr4::mrs05(i_target, io_inst, i_rank);
+ };
+};
+
+///
+/// @class shadow_regs_traits
+/// @brief a collection of traits associated with each shadow register - specialization for MR6
+///
+template<>
+class shadow_regs_traits<6>
+{
+ public:
+
+ static const std::vector<uint64_t> REGS;
+
+ ///
+ /// @brief Configure the ARR0 of the CCS isntruction for mrs00
+ /// @param[in] i_target a fapi2::Target<fapi2::TARGET_TYPE_DIMM>
+ /// @param[in,out] io_inst the instruction to fixup
+ /// @param[in] i_rank ths rank in question
+ /// @return FAPI2_RC_SUCCESS iff OK
+ ///
+ static inline fapi2::ReturnCode mrs_gen(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& io_inst,
+ const uint64_t i_rank)
+ {
+ return mss::ddr4::mrs06(i_target, io_inst, i_rank);
+ };
+};
+
+
+///
+/// @brief Fixes shadow register corruption on the associated MR
+/// @tparam MR the MR number for which to fix the shadow regs
+/// @tparam traits associated with this shadow register
+/// @param[in] i_target - the DIMM target on which to operate
+/// @param[in] i_rp - the rank pair on which to operate
+/// @param[in] i_rank - the rank on which to operate
+/// @return fapi2::ReturnCode - SUCCESS iff everything executes successfully
+///
+template< uint64_t MR, typename TT = shadow_regs_traits<MR> >
+fapi2::ReturnCode fix_shadow_register_corruption_mr( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ const uint64_t i_rp,
+ const uint64_t i_rank)
+{
+ static_assert( MR <= MAX_MR, "MR instance out of range");
+
+ ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST> l_inst;
+ const auto& l_mca = mss::find_target<fapi2::TARGET_TYPE_MCA>(i_target);
+
+ // Converts this to DIMM rank. just. in. case.
+ const auto l_dimm_rank = mss::index(i_rank);
+
+ FAPI_ASSERT( i_rp < MAX_RANK_PAIRS,
+ fapi2::MSS_INVALID_RANK_PAIR()
+ .set_RANK_PAIR(i_rp)
+ .set_FUNCTION(mss::ffdc_function_codes::FIX_SHADOW_REGISTER)
+ .set_MCA_TARGET(l_mca),
+ "%s invalid RP %u. Max is %u",
+ mss::c_str(l_mca), i_rp, MAX_RANK_PAIRS);
+
+ FAPI_TRY(TT::mrs_gen(i_target, l_inst, l_dimm_rank), "%s failed to get MRS%u nominal values", mss::c_str(i_target), MR);
+
+ // Issues the scom to the shadow regiser
+ FAPI_TRY(mss::putScom(l_mca, TT::REGS[i_rp], convert_to_shadow_reg(l_inst)),
+ "%s rank%u failed to set the shadow register", mss::c_str(i_target), l_dimm_rank);
+
+ return fapi2::FAPI2_RC_SUCCESS;
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+} // ns workarounds
+} // ns mss
+
+#endif
OpenPOWER on IntegriCloud