From 4a69b75341c33bada63ee7d92fda913ebe68fb8d Mon Sep 17 00:00:00 2001 From: Stephen Glancy Date: Thu, 14 Mar 2019 14:42:54 -0400 Subject: 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 Tested-by: Jenkins Server Dev-Ready: STEPHEN GLANCY Tested-by: HWSV CI Reviewed-by: Louis Stermole Tested-by: Hostboot CI Reviewed-by: ANDRE A. MARIN Reviewed-by: Jennifer A. Stofer Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/81322 Reviewed-by: Christian R Geddes Tested-by: Christian R Geddes --- .../lib/workarounds/quad_encode_workarounds.C | 255 +++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 src/import/chips/p9/procedures/hwp/memory/lib/workarounds/quad_encode_workarounds.C (limited to 'src/import/chips/p9/procedures/hwp/memory/lib/workarounds/quad_encode_workarounds.C') 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 +// *HWP HWP Backup: Louis Stermole +// *HWP Team: Memory +// *HWP Level: 3 +// *HWP Consumed by: FSP:HB Memory Lab + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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& 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() || + !i_inst.arr0.getBit < MCBIST_CCS_INST_ARR0_00_DDR_CSN_0_1 + 1 > () || + !i_inst.arr0.getBit() || + !i_inst.arr0.getBit < MCBIST_CCS_INST_ARR0_00_DDR_CSN_2_3 + 1 > (); + + const auto l_mrs_cmd = i_inst.arr0.getBit() && + !i_inst.arr0.getBit() && + !i_inst.arr0.getBit() && + !i_inst.arr0.getBit(); + + const auto l_mrs_ba = !i_inst.arr0.getBit() || + !i_inst.arr0.getBit < MCBIST_CCS_INST_ARR0_00_DDR_BANK_0_1 + 1 > () || + !i_inst.arr0.getBit(); + 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>& 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& 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& i_target, + const uint64_t i_rank) +{ + fapi2::Target 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& 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 -- cgit v1.2.1