diff options
19 files changed, 2627 insertions, 199 deletions
diff --git a/src/import/chips/p9/common/include/p9_mc_scom_addresses_fld_fixes.H b/src/import/chips/p9/common/include/p9_mc_scom_addresses_fld_fixes.H index 1021dd8fb..6e633719e 100644 --- a/src/import/chips/p9/common/include/p9_mc_scom_addresses_fld_fixes.H +++ b/src/import/chips/p9/common/include/p9_mc_scom_addresses_fld_fixes.H @@ -52,4 +52,7 @@ REG64_FLD( MCA_DDRPHY_WC_RTT_WL_SWAP_ENABLE_P0 , 48 , SH_UN REG64_FLD( MCA_DDRPHY_WC_RTT_WR_CTL_SWAP_ENABLE_P0 , 49 , SH_UNT_MCA , SH_ACS_SCOM_RW , 0 ); +REG64_FLD( MCBIST_MCBCFGQ_CFG_MCBIST_CFG_FORCE_PAUSE_AFTER_RANK , 34 , SH_UNT_MCA , SH_ACS_SCOM_RW , + 0 ); + #endif diff --git a/src/import/chips/p9/procedures/hwp/memory/lab/sdk/example/C/mss_lab_sfwrite.C b/src/import/chips/p9/procedures/hwp/memory/lab/sdk/example/C/mss_lab_sfwrite.C new file mode 100644 index 000000000..69f6d3763 --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/memory/lab/sdk/example/C/mss_lab_sfwrite.C @@ -0,0 +1,124 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: chips/p9/procedures/hwp/memory/lab/sdk/example/C/mss_lab_sfwrite.C $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* EKB Project */ +/* */ +/* COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +/// +/// @file mss_lab_sfwrite.C +/// @brief Memdiags super-fast write +/// +// *HWP HWP Owner: Marc Gollub <gollub@us.ibm.com> +// *HWP FW Owner: Brian Silver <bsiler@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 3 +// *HWP Consumed by: Memory + +#include <mss_lab_tools.H> + +#include <lib/utils/poll.H> +#include <lib/mcbist/address.H> +#include <lib/mcbist/memdiags.H> +#include <lib/mcbist/mcbist.H> + +/// +/// @brief display procedure usage +/// +void help() +{ + // Note: Use ecmdOutput for usage information so it is always printed to the console. + // Otherwise, always use mss::lab::log or mss::lab::logf + ecmdOutput("mss_lab_sfwrite.exe - Example of building a lab tool to do super-fast write\n"); + ecmdOutput("mss_lab_sfwrite.exe [options] [cronus options]\n"); + ecmdOutput("\n"); + ecmdOutput(" Options:\n"); + ecmdOutput(" --help/-h Shows this help message\n"); + ecmdOutput(" --cronus-target Provide the Cronus target to begin operations on.\n"); + ecmdOutput("\n"); + ecmdOutput(" Cronus Options:\n"); + ecmdOutput(" These are cronus specific command line instructions that are passed\n"); + ecmdOutput(" into cronus\n"); + return; +} + +/// +/// @brief main test function +/// +int main(int i_argc, char* i_argv[]) +{ + // vars, handles, etc + fapi2::ReturnCode rc; + char cronus_target[32] = "p9n.mcbist:k0:n0:s0:p00:c0"; + char* l_target; + + // Memory Lab Tools initialization + mss::lab::tool_init tool_init(rc, i_argc, i_argv); + mss::lab::is_ok(rc, "Failed to initialize lab tool"); + + // command line handling + if (ecmdParseOption(&i_argc, &i_argv, "-h")) + { + help(); + return 0; + } + + if ((l_target = ecmdParseOptionWithArgs(&i_argc, &i_argv, "--cronus-target=")) != nullptr) + { + strcpy(cronus_target, l_target); + } + + // get ecmd target + auto ecmd_target = std::make_shared<ecmdChipTarget>(); + rc = mss::lab::get_ecmd_target(cronus_target, ecmd_target); + mss::lab::is_ok(rc, "Failed to get ecmd target"); + + // get fapi2 target + fapi2::Target<fapi2::TARGET_TYPE_MCBIST> fapi2_mcbist_target; + rc = mss::lab::get_fapi2_target(ecmd_target, fapi2_mcbist_target); + mss::lab::is_ok(rc, "Failed to get mcbist from ecmd target"); + + // retrieve the Cronus string representing the fapi2 target + mss::logf(mss::DEBUG, "MCBIST C_str: %s", mss::c_str(fapi2_mcbist_target)); + + rc = memdiags::sf_init(fapi2_mcbist_target, mss::mcbist::PATTERN_5); + mss::lab::is_ok(rc, "memdiags::sf_init failed"); + + // Just for giggles, poll here looking for the FIR bit ... + { + // Poll for the fir bit. We expect this to be set ... + fapi2::buffer<uint64_t> l_status; + + // A small vector of addresses to poll during the polling loop + static const std::vector<mss::poll_probe<fapi2::TARGET_TYPE_MCBIST>> l_probes = + { + {fapi2_mcbist_target, "mcbist current address", MCBIST_MCBMCATQ}, + }; + + mss::poll_parameters l_poll_parameters; + bool l_poll_results = mss::poll(fapi2_mcbist_target, MCBIST_MCBISTFIRQ, l_poll_parameters, + [&l_status](const size_t poll_remaining, const fapi2::buffer<uint64_t>& stat_reg) -> bool + { + FAPI_DBG("mcbist firq 0x%llx, remaining: %d", stat_reg, poll_remaining); + l_status = stat_reg; + return l_status.getBit<MCBIST_MCBISTFIRQ_MCBIST_PROGRAM_COMPLETE>() == true; + }, + l_probes); + + mss::lab::is_ok(l_poll_results == true, "memdiags::sf_write timedout"); + } + + mss::log(mss::DEBUG, "Finished"); +} diff --git a/src/import/chips/p9/procedures/hwp/memory/lab/sdk/example/C/mss_lab_sfwrite.mk b/src/import/chips/p9/procedures/hwp/memory/lab/sdk/example/C/mss_lab_sfwrite.mk new file mode 100644 index 000000000..92e763c8b --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/memory/lab/sdk/example/C/mss_lab_sfwrite.mk @@ -0,0 +1,25 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: chips/p9/procedures/hwp/memory/lab/sdk/example/C/mss_lab_sfwrite.mk $ +# +# IBM CONFIDENTIAL +# +# EKB Project +# +# COPYRIGHT 2016 +# [+] International Business Machines Corp. +# +# +# The source code for this program is not published or otherwise +# divested of its trade secrets, irrespective of what has been +# deposited with the U.S. Copyright Office. +# +# IBM_PROLOG_END_TAG + +# +# Example Makefile to build MSS Lab Tools C++ tests +# + +TOOL=mss_lab_sfwrite +$(call BUILD_LAB_TOOL) diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/address.H b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/address.H index 68d72328f..ff9cd9f24 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/address.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/address.H @@ -116,7 +116,7 @@ class address /// @return right-aligned uint64_t representing the value /// template< const field& F > - inline uint64_t get_field() + inline uint64_t get_field() const { uint64_t l_value = 0; iv_address.extractToRight<F.first, F.second>(l_value); @@ -207,7 +207,7 @@ class address /// @brief Get the port value for an address /// @return right-aligned uint64_t representing the value /// - inline uint64_t get_port() + inline uint64_t get_port() const { return get_field<PORT>(); } @@ -227,7 +227,7 @@ class address /// @brief Get the DIMM value for an address /// @return right-aligned uint64_t representing the vaule /// - inline uint64_t get_dimm() + inline uint64_t get_dimm() const { return (get_field<DIMM>() == true ? 1 : 0); } @@ -246,7 +246,7 @@ class address /// @brief Get the master rank value for an address /// @return right-aligned uint64_t representing the value /// - inline uint64_t get_master_rank() + inline uint64_t get_master_rank() const { return get_field<MRANK>(); } @@ -265,7 +265,7 @@ class address /// @brief Get the slave rank value for an address /// @return right-aligned uint64_t representing the value /// - inline uint64_t get_slave_rank() + inline uint64_t get_slave_rank() const { return get_field<SRANK>(); } @@ -285,7 +285,7 @@ class address /// @brief Get the row value for an address /// @return right-aligned uint64_t representing the value /// - inline uint64_t get_row() + inline uint64_t get_row() const { return get_field<ROW>(); } @@ -305,7 +305,7 @@ class address /// @brief Get the column value for an address /// @return right-aligned uint64_t representing the value /// - inline uint64_t get_column() + inline uint64_t get_column() const { return get_field<COL>(); } @@ -325,7 +325,7 @@ class address /// @brief Get the bank value for an address /// @return right-aligned uint64_t representing the value /// - inline uint64_t get_bank() + inline uint64_t get_bank() const { return get_field<BANK>(); } @@ -344,7 +344,7 @@ class address /// @brief Get the bank group value for an address /// @return right-aligned uint64_t representing the value /// - inline uint64_t get_bank_group() + inline uint64_t get_bank_group() const { return get_field<BANK_GROUP>(); } diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.C b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.C index 5eaabc21e..2527bc7e8 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.C +++ b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.C @@ -65,7 +65,7 @@ fapi2::ReturnCode load_mcbmr( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target, // Leave if there are no subtests. if (0 == i_program.iv_subtests.size()) { - FAPI_DBG("no subtests, noting to do"); + FAPI_INF("no subtests, nothing to do"); return fapi2::current_err; } @@ -132,52 +132,28 @@ fapi_try_exit: } /// -/// @brief Execute the mcbist program +/// @brief Poll the mcbist engine and check for errors +/// @tparam T the fapi2::TargetType - derived +/// @tparam TT the mcbistTraits associated with T - derived /// @param[in] i_target the target to effect -/// @param[in] i_program, the mcbist program to execute +/// @param[in] i_program, the mcbist program which is executing /// @return fapi2::ReturnCode, FAPI2_RC_SUCCESS iff OK /// -template<> -fapi2::ReturnCode execute( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target, - const program<TARGET_TYPE_MCBIST>& i_program ) +template< fapi2::TargetType T, typename TT = mcbistTraits<T> > +fapi2::ReturnCode poll( const fapi2::Target<T>& i_target, const program<T>& i_program ) { - typedef mcbistTraits<TARGET_TYPE_MCBIST> TT; + fapi2::buffer<uint64_t> l_status; static const uint64_t l_done = fapi2::buffer<uint64_t>().setBit<TT::MCBIST_DONE>(); static const uint64_t l_fail = fapi2::buffer<uint64_t>().setBit<TT::MCBIST_FAIL>(); static const uint64_t l_in_progress = fapi2::buffer<uint64_t>().setBit<TT::MCBIST_IN_PROGRESS>(); - fapi2::buffer<uint64_t> l_status; - // A small vector of addresses to poll during the polling loop static const std::vector<mss::poll_probe<fapi2::TARGET_TYPE_MCBIST>> l_probes = { {i_target, "mcbist current address", MCBIST_MCBMCATQ}, }; - // Slam the subtests in to the mcbist registers - FAPI_TRY( load_mcbmr(i_target, i_program) ); - - // Slam the parameters in to the mcbist parameter register - FAPI_TRY( load_mcbparm(i_target, i_program) ); - - // Slam the address generator config - FAPI_TRY( load_addr_gen(i_target, i_program) ); - - // Slam the configured address maps down - FAPI_TRY( load_mcbamr( i_target, i_program) ); - - // Slam the config register down - FAPI_TRY( load_config( i_target, i_program) ); - - // Slam the control register down - FAPI_TRY( load_control( i_target, i_program) ); - - // Start the engine, and then poll for completion - // Note: We need to have a bit in the program for 'async' mode where an attention - // bit is set and we can fire-and-forget BRS - FAPI_TRY(start_stop(i_target, mss::START)); - mss::poll(i_target, TT::STATQ_REG, i_program.iv_poll, [&l_status](const size_t poll_remaining, const fapi2::buffer<uint64_t>& stat_reg) -> bool { @@ -221,6 +197,71 @@ fapi_try_exit: return fapi2::current_err; } +/// +/// @brief Execute the mcbist program +/// @param[in] i_target the target to effect +/// @param[in] i_program, the mcbist program to execute +/// @return fapi2::ReturnCode, FAPI2_RC_SUCCESS iff OK +/// +template<> +fapi2::ReturnCode execute( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target, + const program<TARGET_TYPE_MCBIST>& i_program ) +{ + typedef mcbistTraits<TARGET_TYPE_MCBIST> TT; + + fapi2::buffer<uint64_t> l_status; + bool l_poll_result = false; + poll_parameters l_poll_parameters; + + FAPI_TRY( i_program.clear_errors(i_target) ); + + // Slam the subtests in to the mcbist registers + FAPI_TRY( load_mcbmr(i_target, i_program) ); + + // Slam the parameters in to the mcbist parameter register + FAPI_TRY( load_mcbparm(i_target, i_program) ); + + // Slam the address generator config + FAPI_TRY( load_addr_gen(i_target, i_program) ); + + // Slam the configured address maps down + FAPI_TRY( load_mcbamr( i_target, i_program) ); + + // Slam the config register down + FAPI_TRY( load_config( i_target, i_program) ); + + // Slam the control register down + FAPI_TRY( load_control( i_target, i_program) ); + + // Start the engine, and then poll for completion + FAPI_TRY(start_stop(i_target, mss::START)); + + // Verify that the in-progress bit has been set, so we know we started + // Don't use the program's poll as it could be a very long time. Use the default poll. + l_poll_result = mss::poll(i_target, TT::STATQ_REG, l_poll_parameters, + [&l_status](const size_t poll_remaining, const fapi2::buffer<uint64_t>& stat_reg) -> bool + { + FAPI_DBG("looking for mcbist start, mcbist statq 0x%llx, remaining: %d", stat_reg, poll_remaining); + l_status = stat_reg; + // We're done polling when either we see we're in progress or we see we're done. + return (l_status.getBit<TT::MCBIST_IN_PROGRESS>() == true) || (l_status.getBit<TT::MCBIST_DONE>() == true); + }); + + // So we've either run/are running or we timed out waiting for the start. + FAPI_ASSERT( l_poll_result == true, + fapi2::MSS_MEMDIAGS_MCBIST_FAILED_TO_START().set_TARGET(i_target), + "The MCBIST engine failed to start its program" ); + + // If the user asked for async mode, we can leave. Otherwise, poll and check for errors + if (!i_program.iv_async) + { + return mcbist::poll(i_target, i_program); + } + +fapi_try_exit: + return fapi2::current_err; +} + } // namespace // Note: outside of the mcbist namespace diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.H b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.H index 45c9d7ca2..ca5b75cfc 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.H @@ -22,7 +22,7 @@ /// @brief Run and manage the MCBIST engine /// // *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com> -// *HWP HWP Backup: Craig Hamilton <cchamilt@us.ibm.com> +// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com> // *HWP Team: Memory // *HWP Level: 2 // *HWP Consumed by: HB:FSP @@ -38,6 +38,8 @@ #include <lib/utils/poll.H> #include <lib/shared/mss_const.H> #include <lib/utils/bit_count.H> +#include <lib/mcbist/patterns.H> +#include <lib/mcbist/settings.H> namespace mss { @@ -72,29 +74,36 @@ class mcbistTraits<fapi2::TARGET_TYPE_MCBIST> { public: /// MCBIST "memory registers" - config for subtests. - static const uint64_t MCBMR0_REG = MCBIST_MCBMR0Q; - static const uint64_t CFGQ_REG = MCBIST_MCBCFGQ; - static const uint64_t CNTLQ_REG = MCBIST_MCB_CNTLQ; - static const uint64_t STATQ_REG = MCBIST_MCB_CNTLSTATQ; - static const uint64_t MCBSTATQ_REG = MCBIST_MCBSTATQ; - static const uint64_t MCBPARMQ_REG = MCBIST_MCBPARMQ; - static const uint64_t MCBAGRAQ_REG = MCBIST_MCBAGRAQ; - static const uint64_t SRERR_REG = MCBIST_MBSEC1Q; - - static const uint64_t MCBAMR0A0Q_REG = MCBIST_MCBAMR0A0Q; - static const uint64_t MCBAMR1A0Q_REG = MCBIST_MCBAMR1A0Q; - static const uint64_t MCBAMR2A0Q_REG = MCBIST_MCBAMR2A0Q; - static const uint64_t MCBAMR3A0Q_REG = MCBIST_MCBAMR3A0Q; - - static const uint64_t START_ADDRESS_0 = MCBIST_MCBSA0Q; - static const uint64_t START_ADDRESS_1 = MCBIST_MCBSA1Q; - static const uint64_t START_ADDRESS_2 = MCBIST_MCBSA2Q; - static const uint64_t START_ADDRESS_3 = MCBIST_MCBSA3Q; - - static const uint64_t END_ADDRESS_0 = MCBIST_MCBEA0Q; - static const uint64_t END_ADDRESS_1 = MCBIST_MCBEA1Q; - static const uint64_t END_ADDRESS_2 = MCBIST_MCBEA2Q; - static const uint64_t END_ADDRESS_3 = MCBIST_MCBEA3Q; + static constexpr uint64_t MCBMR0_REG = MCBIST_MCBMR0Q; + static constexpr uint64_t CFGQ_REG = MCBIST_MCBCFGQ; + static constexpr uint64_t CNTLQ_REG = MCBIST_MCB_CNTLQ; + static constexpr uint64_t STATQ_REG = MCBIST_MCB_CNTLSTATQ; + static constexpr uint64_t MCBSTATQ_REG = MCBIST_MCBSTATQ; + static constexpr uint64_t MCBPARMQ_REG = MCBIST_MCBPARMQ; + static constexpr uint64_t MCBAGRAQ_REG = MCBIST_MCBAGRAQ; + static constexpr uint64_t SRERR_REG = MCBIST_MBSEC1Q; + static constexpr uint64_t THRESHOLD_REG = MCBIST_MBSTRQ; + static constexpr uint64_t FIRQ_REG = MCBIST_MCBISTFIRQ; + + static constexpr uint64_t MCBAMR0A0Q_REG = MCBIST_MCBAMR0A0Q; + static constexpr uint64_t MCBAMR1A0Q_REG = MCBIST_MCBAMR1A0Q; + static constexpr uint64_t MCBAMR2A0Q_REG = MCBIST_MCBAMR2A0Q; + static constexpr uint64_t MCBAMR3A0Q_REG = MCBIST_MCBAMR3A0Q; + + // All of the pattern registers are calculated off of this base + static constexpr uint64_t PATTERN0_REG = MCBIST_MCBFD0Q; + + static constexpr uint64_t START_ADDRESS_0 = MCBIST_MCBSA0Q; + static constexpr uint64_t START_ADDRESS_1 = MCBIST_MCBSA1Q; + static constexpr uint64_t START_ADDRESS_2 = MCBIST_MCBSA2Q; + static constexpr uint64_t START_ADDRESS_3 = MCBIST_MCBSA3Q; + + static constexpr uint64_t END_ADDRESS_0 = MCBIST_MCBEA0Q; + static constexpr uint64_t END_ADDRESS_1 = MCBIST_MCBEA1Q; + static constexpr uint64_t END_ADDRESS_2 = MCBIST_MCBEA2Q; + static constexpr uint64_t END_ADDRESS_3 = MCBIST_MCBEA3Q; + + static constexpr uint64_t PATTERN_COUNT = 4; // Sometimes we want to access the start/end address registers based off // of an index, like master rank. This allows us to do that. @@ -177,6 +186,7 @@ class mcbistTraits<fapi2::TARGET_TYPE_MCBIST> MCBIST_CFG_FORCE_PAUSE_AFTER_SUBTEST = MCBIST_MCBCFGQ_MCBIST_CFG_FORCE_PAUSE_AFTER_SUBTEST, CFG_ENABLE_SPEC_ATTN = MCBIST_MCBCFGQ_CFG_ENABLE_SPEC_ATTN, CFG_ENABLE_HOST_ATTN = MCBIST_MCBCFGQ_CFG_ENABLE_HOST_ATTN, + MCBIST_CFG_PAUSE_AFTER_RANK = MCBIST_MCBCFGQ_CFG_MCBIST_CFG_FORCE_PAUSE_AFTER_RANK, LOGGED_ERROR_ON_PORT_INDICATOR = MCBIST_MCBSTATQ_MCBIST_LOGGED_ERROR_ON_PORT_INDICATOR, LOGGED_ERROR_ON_PORT_INDICATOR_LEN = MCBIST_MCBSTATQ_MCBIST_LOGGED_ERROR_ON_PORT_INDICATOR_LEN, @@ -421,6 +431,19 @@ inline subtest_t<T> read_subtest() } /// +/// @brief Return an init subtest - configured simply +/// @tparam T the fapi2::TargetType - derived +/// @tparam TT the mcbistTraits associated with T - derived +/// @return mss::mcbist::subtest_t +/// @note Configures for start/end address select bit as address config register 0 +/// +template< fapi2::TargetType T, typename TT = mcbistTraits<T> > +inline subtest_t<T> init_subtest() +{ + return write_subtest<T>(); +} + +/// /// @brief A class representing a series of MCBIST subtests, and the /// MCBIST engine parameters associated with running the subtests /// @tparam T fapi2::TargetType representing the fapi2 target which @@ -477,7 +500,8 @@ class program iv_addr_map2(0), iv_addr_map3(0), iv_config(0), - iv_control(0) + iv_control(0), + iv_async(false) { // Enable the maintenance mode addressing change_maint_address_mode(mss::ON); @@ -502,6 +526,22 @@ class program } /// + /// @brief Change MCBIST Stop conditions + /// @param[in] i_stops the stop conditions + /// @return FAPI2_RC_SUCCSS iff ok + /// @note if the user askes for stop-on-error we stop after the operation on the failed address has completed + /// + inline void change_stops( const stop_conditions i_stops ) + { + if (i_stops != DONT_CHANGE) + { + iv_config.insertFromRight<TT::CFG_PAUSE_ON_ERROR_MODE, TT::CFG_PAUSE_ON_ERROR_MODE_LEN>(i_stops); + } + + FAPI_INF("load MCBIST stops: 0x%016lx (0x%016lx)", i_stops, iv_config); + } + + /// /// @brief Change the mcbist min command gap /// @param[in] i_gap minimum number of cycles between commands when cfg_en_randcmd_gap is a 0 (disabled) /// @note Assumes data is right-aligned @@ -730,44 +770,30 @@ class program } /// + /// @brief Enable or disable async mode + /// @param[in] i_program the program in question + /// @param[in] i_mode mss::ON to enable, programs will run async + /// @return void + /// + inline void change_async( const bool i_mode ) + { + iv_async = i_mode; + return; + } + + /// /// @brief Select the port(s) to be used by the MCBIST /// @param[in] i_ports uint64_t representing the ports. Multiple bits set imply broadcast /// i_ports is a right-aligned uint64_t, of which only the right-most 4 bits are used. The register /// field is defined such that the left-most bit in the field represents port 0, the right most /// bit in the field represents port 3. So, to run on port 0, i_ports should be 0b1000. 0b0001 /// (or 0x1) is port 3 - not port 0 - /// @param[in] i_wait_time representing the sync wait time for broadcast operations (optional) /// @return void - /// @note If multiple bits are set, the MCBIST will be configured for broadcast mode. - /// This implies all subtests are individual reads/writes. Uses i_wait parameter. - /// @note i_wait is the number of 1024 2:1 cycle timebases to wait starting up MCBIST for SRQ's to get - /// synchornized for broadcast mode (ranges 0-127). /// - inline void select_ports( const uint64_t i_ports, const uint64_t i_wait = 0) + inline void select_ports( const uint64_t i_ports ) { - fapi2::buffer<uint64_t> l_data; - fapi2::buffer<uint64_t> l_ports; - - if (0 == i_ports) - { - FAPI_DBG("no ports selected for mcbist"); - return; - } - - if (1 != mss::bit_count(i_ports)) - { - // We're in broadcast mode, so setup the broadcast inforamtion registers - iv_config.setBit<TT::SYNC_EN>(); - iv_config.insertFromRight<TT::SYNC_WAIT, TT::SYNC_WAIT_LEN>(i_wait); - FAPI_INF("mcbist select ports seeing broadcast requested: ports 0x%x, config 0x%016lx", - i_ports, iv_config); - - - // Should we check for maint mode and set the MCBAGRAQ_CFG_MAINT_BROADCAST_MODE_EN? BRS - } - iv_control.insertFromRight<TT::PORT_SEL, TT::PORT_SEL_LEN>(i_ports); - FAPI_DBG("mcbist select ports: iv_control 0x%016lx (ports: 0x%x)", iv_control, i_ports); + FAPI_INF("mcbist select ports: iv_control 0x%016lx (ports: 0x%x)", iv_control, i_ports); return; } @@ -822,6 +848,23 @@ class program return fapi2::current_err; } + /// + /// @brief Clear mcbist errors + /// @param[in] i_target fapi2::Target<T> of the MCBIST + /// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok + /// + inline fapi2::ReturnCode clear_errors( const fapi2::Target<T> i_target ) const + { + // TK: Clear the more detailed errors checked above + FAPI_INF("Clear MCBIST error state"); + FAPI_TRY( mss::putScom(i_target, TT::MCBSTATQ_REG, 0) ); + FAPI_TRY( mss::putScom(i_target, TT::SRERR_REG, 0) ); + FAPI_TRY( mss::putScom(i_target, TT::FIRQ_REG, 0) ); + + fapi_try_exit: + return fapi2::current_err; + } + // Vector of subtests. Note the MCBIST subtests are spread across // 8 registers - 4 subtests fit in one 64b register @@ -855,6 +898,9 @@ class program // Control register fapi2::buffer<uint64_t> iv_control; + + // True iff we want to run in asynchronous mode + bool iv_async; }; /// @@ -868,7 +914,7 @@ class program template< fapi2::TargetType T, typename TT = mcbistTraits<T> > inline fapi2::ReturnCode load_config( const fapi2::Target<T>& i_target, const mcbist::program<T>& i_program ) { - FAPI_DBG("loading MCBIST Config 0x%016lx", i_program.iv_config); + FAPI_INF("loading MCBIST Config 0x%016lx", i_program.iv_config); return mss::putScom(i_target, TT::CFGQ_REG, i_program.iv_config); } @@ -884,7 +930,7 @@ inline fapi2::ReturnCode load_config( const fapi2::Target<T>& i_target, const mc template< fapi2::TargetType T, typename TT = mcbistTraits<T> > inline fapi2::ReturnCode load_control( const fapi2::Target<T>& i_target, const mcbist::program<T>& i_program ) { - FAPI_DBG("loading MCBIST Control 0x%016lx", i_program.iv_control); + FAPI_INF("loading MCBIST Control 0x%016lx", i_program.iv_control); return mss::putScom(i_target, TT::CNTLQ_REG, i_program.iv_control); } @@ -900,7 +946,7 @@ inline fapi2::ReturnCode load_control( const fapi2::Target<T>& i_target, const m template< fapi2::TargetType T, typename TT = mcbistTraits<T> > inline fapi2::ReturnCode load_addr_gen( const fapi2::Target<T>& i_target, const mcbist::program<T>& i_program ) { - FAPI_DBG("loading MCBIST Address Generation 0x%016lx", i_program.iv_addr_gen); + FAPI_INF("loading MCBIST Address Generation 0x%016lx", i_program.iv_addr_gen); return mss::putScom(i_target, TT::MCBAGRAQ_REG, i_program.iv_addr_gen); } @@ -920,7 +966,7 @@ template< fapi2::TargetType T, typename TT = mcbistTraits<T> > inline fapi2::ReturnCode config_address_range( const fapi2::Target<T>& i_target, const uint64_t i_start, const uint64_t i_end, const uint64_t i_index ) { - FAPI_DBG("config MCBIST address range %d start: 0x%016lx (0x%016lx), end/len 0x%016lx (0x%016lx)", + FAPI_INF("config MCBIST address range %d start: 0x%016lx (0x%016lx), end/len 0x%016lx (0x%016lx)", i_index, i_start, (i_start << 26), i_end, (i_end << 26)); FAPI_TRY( mss::putScom(i_target, TT::address_pairs[i_index].first, i_start << 26) ); FAPI_TRY( mss::putScom(i_target, TT::address_pairs[i_index].second, i_end << 26) ); @@ -1027,6 +1073,26 @@ fapi_try_exit: } /// +/// @brief Return whether or not the MCBIST engine has an operation in progress +/// @tparam T the fapi2::TargetType - derived +/// @param[in] i_target the target to effect +/// @param[out] i_in_progress - false if no operation is in progress +/// @return FAPI2_RC_SUCCESS if getScom succeeded +/// +template< fapi2::TargetType T, typename TT = mcbistTraits<T> > +inline fapi2::ReturnCode in_progress( const fapi2::Target<T>& i_target, bool o_in_progress ) +{ + fapi2::buffer<uint64_t> l_buf; + + FAPI_TRY(mss::getScom(i_target, TT::STATQ_REG, l_buf)); + o_in_progress = l_buf.getBit<TT::MCBIST_IN_PROGRESS>(); + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + return fapi2::current_err; +} + +/// /// @brief Execute the mcbist program /// @tparam T the fapi2::TargetType - derived /// @param[in] i_target the target to effect @@ -1060,16 +1126,16 @@ template< fapi2::TargetType T, typename TT = mcbistTraits<T> > fapi2::ReturnCode load_mcbamr( const fapi2::Target<T>& i_target, const mcbist::program<T>& i_program ) { // Vector? Can decide when we fully understand the methods to twiddle the maps themselves. BRS - FAPI_DBG("load MCBIST address map register 0: 0x%016lx", i_program.iv_addr_map0); + FAPI_INF("load MCBIST address map register 0: 0x%016lx", i_program.iv_addr_map0); FAPI_TRY( mss::putScom(i_target, TT::MCBAMR0A0Q_REG, i_program.iv_addr_map0) ); - FAPI_DBG("load MCBIST address map register 1: 0x%016lx", i_program.iv_addr_map1); + FAPI_INF("load MCBIST address map register 1: 0x%016lx", i_program.iv_addr_map1); FAPI_TRY( mss::putScom(i_target, TT::MCBAMR1A0Q_REG, i_program.iv_addr_map1) ); - FAPI_DBG("load MCBIST address map register 2: 0x%016lx", i_program.iv_addr_map2); + FAPI_INF("load MCBIST address map register 2: 0x%016lx", i_program.iv_addr_map2); FAPI_TRY( mss::putScom(i_target, TT::MCBAMR1A0Q_REG, i_program.iv_addr_map2) ); - FAPI_DBG("load MCBIST address map register 3: 0x%016lx", i_program.iv_addr_map3); + FAPI_INF("load MCBIST address map register 3: 0x%016lx", i_program.iv_addr_map3); FAPI_TRY( mss::putScom(i_target, TT::MCBAMR1A0Q_REG, i_program.iv_addr_map3) ); fapi_try_exit: @@ -1088,10 +1154,100 @@ fapi_try_exit: template< fapi2::TargetType T, typename TT = mcbistTraits<T> > inline fapi2::ReturnCode load_mcbparm( const fapi2::Target<T>& i_target, const mcbist::program<T>& i_program ) { - FAPI_DBG("load MCBIST parameter register: 0x%016lx", i_program.iv_parameters); + FAPI_INF("load MCBIST parameter register: 0x%016lx", i_program.iv_parameters); return mss::putScom(i_target, TT::MCBPARMQ_REG, i_program.iv_parameters); } +/// +/// @brief Load MCBIST pattern given a pattern +/// @tparam T, the fapi2::TargetType - derived +/// @tparam TT, the mcbistTraits associated with T - derived +/// @param[in] i_target the target to effect +/// @param[in] i_pattern an mcbist::patterns +/// @param[in] i_invert whether to invert the pattern or not +/// @return FAPI2_RC_SUCCSS iff ok +/// +template< fapi2::TargetType T, typename TT = mcbistTraits<T> > +inline fapi2::ReturnCode load_pattern( const fapi2::Target<T>& i_target, const pattern& i_pattern, const bool i_invert ) +{ + uint64_t l_address = TT::PATTERN0_REG; + + // Sanity check the pattern as the user can pass in anything they like + FAPI_ASSERT( i_pattern.size() == TT::PATTERN_COUNT, + fapi2::MSS_MEMDIAGS_INVALID_PATTERN_SIZE().set_SIZE(i_pattern.size()).set_TARGET(i_target), + "Attempting to load a pattern which is not %d elements (%d)", TT::PATTERN_COUNT, i_pattern.size() ); + + // Loop over the cache lines in the pattern. We write one half of the cache line + // to the even register and half to the odd. + for (const auto& l_cache_line : i_pattern) + { + fapi2::buffer<uint64_t> l_value_first = i_invert ? ~l_cache_line.first : l_cache_line.first; + fapi2::buffer<uint64_t> l_value_second = i_invert ? ~l_cache_line.second : l_cache_line.second; + FAPI_INF("Loading cache line pattern 0x%016lx 0x%016lx", l_value_first, l_value_second); + FAPI_TRY( mss::putScom(i_target, l_address, l_value_first) ); + FAPI_TRY( mss::putScom(i_target, ++l_address, l_value_second) ); + ++l_address; + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Load MCBIST pattern given an index +/// @tparam T, the fapi2::TargetType - derived +/// @tparam TT, the mcbistTraits associated with T - derived +/// @param[in] i_target the target to effect +/// @param[in] i_index an index representing the pattern you'd like +/// @return FAPI2_RC_SUCCSS iff ok +/// +template< fapi2::TargetType T, typename TT = mcbistTraits<T> > +inline fapi2::ReturnCode load_pattern( const fapi2::Target<T>& i_target, uint64_t i_index ) +{ + if (NO_PATTERN != i_index) + { + bool l_invert = false; + + FAPI_INF("%s load MCBIST pattern index %d", mss::c_str(i_target), i_index); + + // Sanity check the pattern since they're just numbers. + FAPI_ASSERT( i_index <= mcbist::LAST_PATTERN, + fapi2::MSS_MEMDIAGS_INVALID_PATTERN_INDEX().set_INDEX(i_index).set_TARGET(i_target), + "Attempting to load a pattern which does not exist %d", i_index ); + + // The indexes are split in to even and odd where the odd indexes don't really exist. + // They're just indicating that we want to grab the even index and invert it. So calculate + // the proper vector index and acknowledge the inversion if necessary. + if ((i_index % 2) != 0) + { + l_invert = true; + i_index -= 1; + } + + return load_pattern(i_target, patterns[i_index / 2], l_invert); + } + + return fapi2::FAPI2_RC_SUCCESS; + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Load MCBIST Threshold Register +/// @tparam T, the fapi2::TargetType - derived +/// @tparam TT, the mcbistTraits associated with T - derived +/// @param[in] i_target the target to effect +/// @param[in] i_thresholds the thresholds +/// @return FAPI2_RC_SUCCSS iff ok +/// +template< fapi2::TargetType T, typename TT = mcbistTraits<T> > +inline fapi2::ReturnCode load_thresholds( const fapi2::Target<T>& i_target, const uint64_t i_thresholds ) +{ + FAPI_INF("load MCBIST threshold register: 0x%016lx", i_thresholds ); + return mss::putScom(i_target, TT::THRESHOLD_REG, i_thresholds); +} + } // namespace } // namespace diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/memdiags.C b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/memdiags.C new file mode 100644 index 000000000..4318e111c --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/memdiags.C @@ -0,0 +1,359 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: chips/p9/procedures/hwp/memory/lib/mcbist/memdiags.C $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* EKB Project */ +/* */ +/* COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +/// +/// @file memdiags.C +/// @brief Run and manage the MEMDIAGS engine +/// +// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com> +// *HWP HWP Backup: Marc Gollub <gollub@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 2 +// *HWP Consumed by: FSP:HB + +#include <fapi2.H> + +#include <p9_mc_scom_addresses.H> +#include <p9_mc_scom_addresses_fld.H> + +#include <lib/mcbist/memdiags.H> +#include <lib/mcbist/mcbist.H> +#include <lib/mcbist/address.H> +#include <lib/mcbist/settings.H> +#include <lib/mcbist/sim.H> + +using fapi2::TARGET_TYPE_MCBIST; +using fapi2::TARGET_TYPE_MCA; +using fapi2::TARGET_TYPE_DIMM; +using fapi2::TARGET_TYPE_SYSTEM; +using fapi2::FAPI2_RC_SUCCESS; + +namespace memdiags +{ + +/// +/// @brief Stop the current command +/// @param[in] i_target the target +/// @return FAPI2_RC_SUCCESS iff ok +/// +template<> +fapi2::ReturnCode stop( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target ) +{ + FAPI_INF("Stopping any mcbist operations which are in progress"); + + // TODO RTC:153951 Add masking of FIR when stopping + return mss::mcbist::start_stop(i_target, mss::STOP); +} + +/// +/// @brief memdiags::base initializer +/// @return FAPI2_RC_SUCCESS iff everything ok +/// @note specialized for Nimbus as the port select mechanism is different +/// +template<> +fapi2::ReturnCode memdiags::base<TARGET_TYPE_MCBIST>::init() +{ + FAPI_INF("memdiags base init"); + + // Check the state of the MCBIST engine to make sure its OK that we proceed. + // Force stop the engine (per spec, as opposed to waiting our turn) + FAPI_TRY( memdiags::stop(iv_target) ); + + // Zero out cmd timebase - mcbist::program constructor does that for us. + // Load pattern + FAPI_TRY( mss::mcbist::load_pattern(iv_target, iv_const.iv_pattern) ); + + // Load stop conditions + iv_program.change_stops(iv_const.iv_stop); + + // Load thresholds + FAPI_TRY( mss::mcbist::load_thresholds(iv_target, iv_const.iv_thresholds) ); + + // A superfast operation which has an end address of 0 means 'to the end' + if (iv_const.iv_end_address == 0) + { + iv_const.iv_start_address.get_range<memdiags::address::DIMM>(iv_const.iv_end_address); + } + + // Enable maint addressing mode - enabled by default in the mcbist::program ctor + // Configure the address range + FAPI_TRY( mss::mcbist::config_address_range0(iv_target, iv_const.iv_start_address, iv_const.iv_end_address) ); + + // Apparently the MCBIST engine needs the ports selected even tho the ports are specified + // in the subtest. We can just select them all, and it adjusts when it executes the subtest + iv_program.select_ports(0b1111); + + // Kick it off, don't wait for a result + iv_program.change_async(mss::ON); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Super Fast Base initializer +/// @note Uses broadcast mode if possible +/// @return FAPI2_RC_SUCCESS iff everything ok +/// +template<> +fapi2::ReturnCode memdiags::sf_operation<TARGET_TYPE_MCBIST>::init() +{ + FAPI_INF("superfast init"); + + // Initialize the base class + FAPI_TRY( base::init() ); + + // Deterimine which ports are functional and whether we can broadcast to them + // TK on the broadcast BRS + // Disable braodcast mode - disabled by default + // For each functional port, setup 2 INIT subtests, one per DIMM select + for (const auto& p : mss::find_targets<TARGET_TYPE_MCA>(iv_target)) + { + // Run in ECC mode, 64B writes (superfast mode) + for (const auto& d : mss::find_targets<TARGET_TYPE_DIMM>(p)) + { + // Don't destroy the subtest passed in, copy it + mss::mcbist::subtest_t<TARGET_TYPE_MCBIST> l_subtest = iv_subtest; + + l_subtest.enable_port(mss::relative_pos<TARGET_TYPE_MCBIST>(p)); + l_subtest.enable_dimm(mss::index(d)); + iv_program.iv_subtests.push_back(l_subtest); + FAPI_INF("adding superfast subtest for %s (dimm %d)", mss::c_str(d), mss::index(d)); + } + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Super Fast Read (End of Port) initializer +/// @note Uses broadcast mode if possible +/// @return FAPI2_RC_SUCCESS iff everything ok +/// +template<> +fapi2::ReturnCode memdiags::sf_read_operation<TARGET_TYPE_MCBIST>::end_of_port_init() +{ + FAPI_INF("superfast read (end of port) init"); + + const uint64_t l_relative_port_number = iv_const.iv_start_address.get_port(); + const uint64_t l_dimm_number = iv_const.iv_start_address.get_dimm(); + + // Initialize the base class + FAPI_TRY( base::init() ); + + // Make sure the specificed port is functional + FAPI_ASSERT( mss::is_functional<TARGET_TYPE_MCA>(iv_target, l_relative_port_number), + fapi2::MSS_MEMDIAGS_PORT_NOT_FUNCTIONAL() + .set_RELATIVE_PORT_POSITION(l_relative_port_number) + .set_ADDRESS( uint64_t(iv_const.iv_start_address) ) + .set_TARGET(iv_target), + "Port with relative postion %d is not functional", l_relative_port_number ); + + // The address should have the port and DIMM noted in it. All we need to do is calculate the + // remainder of the address + iv_const.iv_start_address.get_range<memdiags::address::DIMM>(iv_const.iv_end_address); + + // No broadcast mode for this one + // Push on a read subtest + { + mss::mcbist::subtest_t<TARGET_TYPE_MCBIST> l_subtest = iv_subtest; + + l_subtest.enable_port(l_relative_port_number); + l_subtest.enable_dimm(l_dimm_number); + iv_program.iv_subtests.push_back(l_subtest); + FAPI_INF("adding superfast read remainder of port %d, DIMM %d", l_relative_port_number, l_dimm_number); + } + + return FAPI2_RC_SUCCESS; + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Super Fast Read Init - used to init all memory behind a target with a given pattern +/// @note Uses broadcast mode if possible +/// @param[in] i_target the target behind which all memory should be initialized +/// @param[in] i_pattern an index representing a pattern to use to initize memory (defaults to 0) +/// @return FAPI2_RC_SUCCESS iff everything ok +/// @note The function is asynchronous, and the caller should be looking for a done attention +/// +template<> +fapi2::ReturnCode sf_init( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target, + const uint64_t i_pattern ) +{ + FAPI_INF("superfast init start"); + + // If we're running in the simulator, we want to only touch the addresses which training touched + uint8_t is_sim = 0; + FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<TARGET_TYPE_SYSTEM>(), is_sim) ); + + if (is_sim) + { + // Use some sort of pattern in sim in case the verification folks need to look for something + // TK. Need a verification pattern. This is a not-good pattern for verification ... We don't really + // have a good pattern for verification defined. + FAPI_INF("running mss sim init in place of sf_init"); + return mss::mcbist::sim::sf_init(i_target, i_pattern); + } + else + { + fapi2::ReturnCode l_rc; + sf_init_operation<TARGET_TYPE_MCBIST> l_init_op(i_target, i_pattern, l_rc); + + FAPI_ASSERT( l_rc == FAPI2_RC_SUCCESS, + fapi2::MSS_MEMDIAGS_SUPERFAST_INIT_FAILED_TO_INIT().set_TARGET(i_target), + "Unable to initialize the MCBIST engine for a sf read %s", mss::c_str(i_target) ); + + return l_init_op.execute(); + } + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Super Fast Read All - used to run superfast read on all memory behind the target +/// @note Uses broadcast mode if possible +/// @param[in] i_target the target behind which all memory should be read +/// @param[in] i_stop stop conditions +/// @param[in] i_thresholds thresholds +/// @return FAPI2_RC_SUCCESS iff everything ok +/// @note The function is asynchronous, and the caller should be looking for a done attention +/// +template<> +fapi2::ReturnCode sf_read( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target, + const memdiags::stop_conditions i_stop, + const memdiags::thresholds& i_thresholds ) +{ + FAPI_INF("superfast read start"); + + fapi2::ReturnCode l_rc; + sf_read_operation<TARGET_TYPE_MCBIST> l_read_op(i_target, i_stop, i_thresholds, l_rc); + + FAPI_ASSERT( l_rc == FAPI2_RC_SUCCESS, + fapi2::MSS_MEMDIAGS_SUPERFAST_READ_FAILED_TO_INIT().set_TARGET(i_target), + "Unable to initialize the MCBIST engine for a sf read %s", mss::c_str(i_target) ); + + return l_read_op.execute(); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Super Fast Read to End of Port - used to run superfast read on all memory behind the target +/// @param[in] i_target the target behind which all memory should be read +/// @param[in] i_stop stop conditions +/// @param[in] i_thresholds thresholds +/// @param[in] i_address mcbist::address representing the port, dimm, rank +/// @return FAPI2_RC_SUCCESS iff everything ok +/// @note The function is asynchronous, and the caller should be looking for a done attention +/// +template<> +fapi2::ReturnCode sf_read( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target, + const memdiags::stop_conditions i_stop, + const memdiags::thresholds& i_thresholds, + const memdiags::address& i_address ) +{ + FAPI_INF("superfast read - end of port"); + + fapi2::ReturnCode l_rc; + sf_read_operation<TARGET_TYPE_MCBIST> l_read_op(i_target, i_stop, i_thresholds, i_address, l_rc); + + FAPI_ASSERT( l_rc == FAPI2_RC_SUCCESS, + fapi2::MSS_MEMDIAGS_SUPERFAST_READ_FAILED_TO_INIT().set_TARGET(i_target), + "Unable to initialize the MCBIST engine for a sf read %s", mss::c_str(i_target) ); + + return l_read_op.execute(); + +fapi_try_exit: + return fapi2::current_err; +} + +/// +/// @brief Scrub - scrub all memory behind the target +/// @param[in] i_target the target behind which all memory should be scrubbed +/// @param[in] i_stop stop conditions +/// @param[in] i_thresholds thresholds +/// @param[in] i_speed the speed to scrub +/// @param[in] i_address mcbist::address representing the port, dimm, rank +/// @param[in] i_end whether to end, and where (default = continuous scrub) +/// @return FAPI2_RC_SUCCESS iff everything ok +/// @note The function is asynchronous, and the caller should be looking for a done attention +/// +template<> +fapi2::ReturnCode scrub( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target, + const memdiags::stop_conditions i_stop, + const memdiags::thresholds& i_thresholds, + const memdiags::speed i_speed, + const memdiags::address& i_address, + const memdiags::end_boundary i_end ) +{ + // TK implementation (because Glancy couldn't figure that out <grin>) + FAPI_INF("scrub"); + return FAPI2_RC_SUCCESS; +} + +/// +/// @brief Continue current command on next address +/// The current commaand has paused on an error, so we can record the address of the error +/// and finish the current master or slave rank. +/// @param[in] i_target the target +/// @param[in] i_end whether to end, and where (default = don't stop at end of rank) +/// @param[in] i_stop stop conditions (default - 0 meaning 'don't change conditions') +/// @param[in] i_speed the speed to scrub (default - NO_CHANGE meaning leave speed untouched) +/// @return FAPI2_RC_SUCCESS iff ok +/// +template<> +fapi2::ReturnCode continue_cmd( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target, + const memdiags::end_boundary i_end, + const memdiags::stop_conditions i_stop, + const memdiags::speed i_speed ) +{ + // TK implementation (because Glancy couldn't figure that out <grin>) + FAPI_INF("continue_cmd"); + return FAPI2_RC_SUCCESS; +} + +/// +/// @brief Continue current command on next address - change thresholds +/// The current commaand has paused on an error, so we can record the address of the error +/// and finish the current master or slave rank. +/// @param[in] i_target the target +/// @param[in] i_thresholds new thresholds +/// @param[in] i_end whether to end, and where (default = don't stop at end of rank) +/// @param[in] i_stop stop conditions (default - 0 meaning 'don't change conditions') +/// @param[in] i_speed the speed to scrub (default - NO_CHANGE meaning leave speed untouched) +/// @return FAPI2_RC_SUCCESS iff ok +/// +template<> +fapi2::ReturnCode continue_cmd( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target, + const memdiags::thresholds& i_thresholds, + const memdiags::end_boundary i_end, + const memdiags::stop_conditions i_stop, + const memdiags::speed i_speed ) +{ + // TK implementation (because Glancy couldn't figure that out <grin>) + FAPI_INF("continue_cmd - change thresholds"); + return FAPI2_RC_SUCCESS; +} + +} diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/memdiags.H b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/memdiags.H new file mode 100644 index 000000000..92d01e3a4 --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/memdiags.H @@ -0,0 +1,354 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: chips/p9/procedures/hwp/memory/lib/mcbist/memdiags.H $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* EKB Project */ +/* */ +/* COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +/// +/// @file memdiags.H +/// @brief API for memory diagnostics +/// +// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com> +// *HWP HWP Backup: Marc Gollub <gollub@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 1 +// *HWP Consumed by: HB:FSP +// + +#ifndef _MSS_MEMDIAGS_H_ +#define _MSS_MEMDIAGS_H_ + +#include <fapi2.H> +#include <lib/mcbist/mcbist.H> +#include <lib/mcbist/address.H> +#include <lib/mcbist/patterns.H> +#include <lib/mcbist/settings.H> + +namespace memdiags +{ + +// Map some of the mcbist namespace here to make it easier for users of memdiags +// This is an intentional using statement in a header which is typically +// disallowed - I am intentionally pulling these into this namespace for all callers. +using mss::mcbist::thresholds; +using mss::mcbist::constraints; +using mss::mcbist::speed; +using mss::mcbist::end_boundary; +using mss::mcbist::stop_conditions; +using mss::mcbist::address; +using mss::mcbist::cache_line; +using mss::mcbist::pattern; +using mss::mcbist::patterns; + +using mss::mcbist::PATTERN_ZEROS; +using mss::mcbist::PATTERN_0; +using mss::mcbist::PATTERN_ONES; +using mss::mcbist::PATTERN_1; +using mss::mcbist::PATTERN_2; +using mss::mcbist::PATTERN_3; +using mss::mcbist::PATTERN_4; +using mss::mcbist::PATTERN_5; +using mss::mcbist::PATTERN_6; +using mss::mcbist::PATTERN_7; +using mss::mcbist::PATTERN_8; +using mss::mcbist::PATTERN_RANDOM; +using mss::mcbist::LAST_PATTERN; +using mss::mcbist::NO_PATTERN; + +/// +/// @class Base class for memdiags operations +/// @tparam T fapi2::TargetType of the MCBIST engine +/// +template< fapi2::TargetType T > +class base +{ + public: + /// + /// @brief memdiags::base constructor + /// @param[in] i_target the target of the mcbist engine + /// @param[in] i_const mss::constraint structure + /// + base( const fapi2::Target<T>& i_target, + const memdiags::constraints i_const ): + iv_target(i_target), + iv_const(i_const) + { + } + + base() = delete; + + /// + /// @brief memdiags::base initializer + /// @return FAPI2_RC_SUCCESS iff everything ok + /// @note specialized for Nimbus as the port select mechanism is different + // Needed because of the scom operations done in the initialization. There + // is no good way to handle these errors in a constructor + /// + fapi2::ReturnCode init(); + + /// + /// @brief Execute the memdiags operation + /// @return FAPI2_RC_SUCCESS iff ok + /// + inline fapi2::ReturnCode execute() + { + return mss::mcbist::execute(iv_target, iv_program); + } + + /// + /// @brief memdiags::base destructor + /// + virtual ~base() = default; + + protected: + fapi2::Target<T> iv_target; + constraints iv_const; + mss::mcbist::program<T> iv_program; +}; + +/// +/// @class Base class for memdiags super-fast operations +/// @tparam T fapi2::TargetType of the MCBIST engine +/// +template< fapi2::TargetType T > +class sf_operation : public base<T> +{ + public: + /// + /// @brief memdiags::sf_operation constructor + /// @param[in] i_target the target of the mcbist engine + /// @param[in] i_const mss::constraint structure + /// @param[in] i_subtest the appropriate subtest for this operation + /// + sf_operation( const fapi2::Target<T>& i_target, + const memdiags::constraints i_const, + const mss::mcbist::subtest_t<T> i_subtest ): + base<T>(i_target, i_const), + iv_subtest(i_subtest) + { + } + + sf_operation() = delete; + + /// + /// @brief memdiags::sf_operation initializer + /// @return FAPI2_RC_SUCCESS iff everything ok + // Needed because of the scom operations done in the initialization. There + // is no good way to handle these errors in a constructor + /// + fapi2::ReturnCode init(); + + /// + /// @brief memdiags::sf_operation destructor + /// + virtual ~sf_operation() = default; + + protected: + mss::mcbist::subtest_t<T> iv_subtest; +}; + +/// +/// @class Base class for memdiags' super-fast init +/// @tparam T fapi2::TargetType of the MCBIST engine +/// +template< fapi2::TargetType T > +struct sf_init_operation : public sf_operation<T> +{ + + /// + /// @brief memdiags::sf_init_operation constructor + /// @param[in] i_target the target of the mcbist engine + /// @param[in] i_pattern an index representing a pattern to use to initize memory + /// @param[out] o_rc the fapi2::ReturnCode of the intialization process + /// + sf_init_operation( const fapi2::Target<T>& i_target, + const uint64_t i_pattern, + fapi2::ReturnCode& o_rc ): + sf_operation<T>(i_target, constraints(i_pattern), mss::mcbist::init_subtest<T>()) + { + o_rc = sf_operation<T>::init(); + } + + sf_init_operation() = delete; +}; + +/// +/// @class Base class for memdiags' super-fast read +/// @tparam T fapi2::TargetType of the MCBIST engine +/// +template< fapi2::TargetType T > +struct sf_read_operation : public sf_operation<T> +{ + + /// + /// @brief memdiags::sf_read_operation constructor + /// @param[in] i_target the target of the mcbist engine + /// @param[in] i_stop stop conditions + /// @param[in] i_thresholds thresholds + /// @param[out] o_rc the fapi2::ReturnCode of the intialization process + /// + sf_read_operation( const fapi2::Target<T>& i_target, + const memdiags::stop_conditions i_stop, + const memdiags::thresholds& i_thresholds, + fapi2::ReturnCode& o_rc ): + sf_operation<T>(i_target, constraints(i_stop, i_thresholds), mss::mcbist::read_subtest<T>()) + { + o_rc = sf_operation<T>::init(); + } + + /// + /// @brief memdiags::sf_read_operation constructor - given starting address + /// @param[in] i_target the target of the mcbist engine + /// @param[in] i_stop stop conditions + /// @param[in] i_thresholds thresholds + /// @param[in] i_address start address of read operation + /// @note the address indicates this operation is performed on one port, one dimm until the end + /// @param[out] o_rc the fapi2::ReturnCode of the intialization process + /// + sf_read_operation( const fapi2::Target<T>& i_target, + const memdiags::stop_conditions i_stop, + const memdiags::thresholds& i_thresholds, + const memdiags::address& i_start_address, + fapi2::ReturnCode& o_rc ): + sf_operation<T>(i_target, constraints(i_stop, i_thresholds, i_start_address), mss::mcbist::read_subtest<T>()) + { + o_rc = sf_read_operation<T>::end_of_port_init(); + } + + sf_read_operation() = delete; + + /// + /// @brief memdiags::sf_read_operation end-of-port initializer + /// @return FAPI2_RC_SUCCESS iff everything ok + // Needed because of the scom operations done in the initialization. There + // is no good way to handle these errors in a constructor + /// + fapi2::ReturnCode end_of_port_init(); +}; + +/// +/// @brief Super Fast Init - used to init all memory behind a target with a given pattern +/// @note Uses broadcast mode if possible +/// @tparam T the fapi2::TargetType of the target +/// @param[in] i_target the target behind which all memory should be initialized +/// @param[in] i_pattern an index representing a pattern to use to init memory (defaults to 0) +/// @return FAPI2_RC_SUCCESS iff everything ok +/// @note The function is asynchronous, and the caller should be looking for a done attention +/// +template< fapi2::TargetType T > +fapi2::ReturnCode sf_init( const fapi2::Target<T>& i_target, + const uint64_t i_pattern = PATTERN_0 ); + +/// +/// @brief Super Fast Read All - used to run superfast read on all memory behind the target +/// @note Uses broadcast mode if possible +/// @param[in] i_target the target behind which all memory should be read +/// @param[in] i_stop stop conditions +/// @param[in] i_thresholds thresholds +/// @return FAPI2_RC_SUCCESS iff everything ok +/// @note The function is asynchronous, and the caller should be looking for a done attention +/// +template< fapi2::TargetType T > +fapi2::ReturnCode sf_read( const fapi2::Target<T>& i_target, + const stop_conditions i_stop, + const thresholds& i_thresholds ); + +/// +/// @brief Super Fast Read to End of Port - used to run superfast read on all memory behind the target +/// @tparam T the fapi2::TargetType of the target +/// @param[in] i_target the target behind which all memory should be read +/// @param[in] i_stop stop conditions +/// @param[in] i_thresholds thresholds +/// @param[in] i_address mcbist::address representing the address from which to start. +/// @return FAPI2_RC_SUCCESS iff everything ok +/// @note The function is asynchronous, and the caller should be looking for a done attention +/// @note The address is often the port, dimm, rank but this is not enforced in the API. +/// +template< fapi2::TargetType T > +fapi2::ReturnCode sf_read( const fapi2::Target<T>& i_target, + const stop_conditions i_stop, + const thresholds& i_thresholds, + const address& i_address ); + +/// +/// @brief Scrub - scrub all memory behind the target +/// @param[in] i_target the target behind which all memory should be scrubbed +/// @param[in] i_stop stop conditions +/// @param[in] i_thresholds thresholds +/// @param[in] i_speed the speed to scrub +/// @param[in] i_address mcbist::address representing the address from which to start. +/// @param[in] i_end whether to end, and where (default = continuous scrub) +/// @return FAPI2_RC_SUCCESS iff everything ok +/// @note The function is asynchronous, and the caller should be looking for a done attention +/// @note The address is often the port, dimm, rank but this is not enforced in the API. +/// +template< fapi2::TargetType T > +fapi2::ReturnCode scrub( const fapi2::Target<T>& i_target, + const stop_conditions i_stop, + const thresholds& i_thresholds, + const speed i_speed, + const address& i_address, + const end_boundary i_end = end_boundary::NEVER ); + +/// +/// @brief Continue current command on next address +/// The current commaand has paused on an error, so we can record the address of the error +/// and finish the current master or slave rank. +/// @tparam T the fapi2::TargetType of the target +/// @param[in] i_target the target +/// @param[in] i_end whether to end, and where (default = don't stop at end of rank) +/// @param[in] i_stop stop conditions (default - 0 meaning 'don't change conditions') +/// @param[in] i_speed the speed to scrub (default - NO_CHANGE meaning leave speed untouched) +/// @return FAPI2_RC_SUCCESS iff ok +/// +template< fapi2::TargetType T > +fapi2::ReturnCode continue_cmd( const fapi2::Target<T>& i_target, + const end_boundary i_end = end_boundary::DONT_STOP, + const stop_conditions i_stop = stop_conditions::DONT_CHANGE, + const speed i_speed = speed::SAME_SPEED ); + +/// +/// @brief Continue current command on next address - change thresholds +/// The current commaand has paused on an error, so we can record the address of the error +/// and finish the current master or slave rank. +/// @tparam T the fapi2::TargetType of the target +/// @param[in] i_target the target +/// @param[in] i_thresholds new thresholds +/// @param[in] i_end whether to end, and where (default = don't stop at end of rank) +/// @param[in] i_stop stop conditions (default - 0 meaning 'don't change conditions') +/// @param[in] i_speed the speed to scrub (default - NO_CHANGE meaning leave speed untouched) +/// @return FAPI2_RC_SUCCESS iff ok +/// +template< fapi2::TargetType T > +fapi2::ReturnCode continue_cmd( const fapi2::Target<T>& i_target, + const thresholds& i_thresholds, + const end_boundary i_end = end_boundary::DONT_STOP, + const stop_conditions i_stop = stop_conditions::DONT_CHANGE, + const speed i_speed = speed::SAME_SPEED ); + +/// +/// @brief Stop the current command +/// @tparam T the fapi2::TargetType of the target +/// @param[in] i_target the target +/// @return FAPI2_RC_SUCCESS iff ok +/// +template< fapi2::TargetType T > +fapi2::ReturnCode stop( const fapi2::Target<T>& i_target ); + +} // namespace + +#endif + diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/patterns.C b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/patterns.C new file mode 100644 index 000000000..c9eb2d3ba --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/patterns.C @@ -0,0 +1,82 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: chips/p9/procedures/hwp/memory/lib/mcbist/patterns.C $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* EKB Project */ +/* */ +/* COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +/// +/// @file patterns.C +/// @brief Static definition of MCBIST patterns +/// +// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com> +// *HWP HWP Backup: Marc Gollub <gollub@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 2 +// *HWP Consumed by: FSP:HB + +#include <fapi2.H> +#include <vector> +#include <lib/mcbist/patterns.H> + +namespace mss +{ + +namespace mcbist +{ + +/// Vector of cache lines, seaprated in to two 64B chunks +// TK Real patterns from Marc representing the proper bits for ECC checking +const std::vector< pattern > patterns = +{ + // Pattern index 0 (Pattern 1 is this inverted) + { {0x0000000000000000, 0x0000000000000000}, + {0x0000000000000000, 0x0000000000000000}, + {0x0000000000000000, 0x0000000000000000}, + {0x0000000000000000, 0x0000000000000000}, + }, + + // Pattern index 2 (Pattern 3 is this inverted) + { {0x5555555555555555, 0x5555555555555555}, + {0xAAAAAAAAAAAAAAAA, 0xAAAAAAAAAAAAAAAA}, + {0x5555555555555555, 0x5555555555555555}, + {0xAAAAAAAAAAAAAAAA, 0xAAAAAAAAAAAAAAAA}, + }, + + // Pattern index 4 (Pattern 5 is this inverted) + { {0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, + {0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, + {0x0000000000000000, 0x0000000000000000}, + {0x0000000000000000, 0x0000000000000000}, + }, + + // Pattern index 6 (Pattern 7 is this inverted) + { {0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, + {0x0000000000000000, 0x0000000000000000}, + {0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, + {0x0000000000000000, 0x0000000000000000}, + }, + + // Pattern index 8 Random Seed + { {0x1234567887654321, 0x8765432112345678}, + {0x1234567887654321, 0x8765432112345678}, + {0x1234567887654321, 0x8765432112345678}, + {0x1234567887654321, 0x8765432112345678}, + }, +}; + +} + +} diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/patterns.H b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/patterns.H new file mode 100644 index 000000000..818885967 --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/patterns.H @@ -0,0 +1,70 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: chips/p9/procedures/hwp/memory/lib/mcbist/patterns.H $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* EKB Project */ +/* */ +/* COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +/// +/// @file patterns.H +/// @brief Static definition of MCBIST patterns +/// +// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com> +// *HWP HWP Backup: Marc Gollub <gollub@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 2 +// *HWP Consumed by: FSP:HB + +#ifndef _MSS_MCBIST_PATTERNS_ +#define _MSS_MCBIST_PATTERNS_ + +#include <vector> + +namespace mss +{ +namespace mcbist +{ + +/// Memory diagnostic Pattern indexes. +// Why not an enum? I want to do math on them to generate a proper index in to a vector of +// patterns and enums really don't like that. +// Couple of extra symbols in here to keep things easy if desired +constexpr uint64_t PATTERN_ZEROS = 0; +constexpr uint64_t PATTERN_0 = PATTERN_ZEROS; +constexpr uint64_t PATTERN_ONES = 1; +constexpr uint64_t PATTERN_1 = PATTERN_ONES; +constexpr uint64_t PATTERN_2 = 2; +constexpr uint64_t PATTERN_3 = 3; +constexpr uint64_t PATTERN_4 = 4; +constexpr uint64_t PATTERN_5 = 5; +constexpr uint64_t PATTERN_6 = 6; +constexpr uint64_t PATTERN_7 = 7; +constexpr uint64_t PATTERN_8 = 8; +constexpr uint64_t PATTERN_RANDOM = PATTERN_8; +constexpr uint64_t LAST_PATTERN = PATTERN_8; + +// Don't mess with the patterns +constexpr uint64_t NO_PATTERN = LAST_PATTERN + 1; + +/// Vector of cache lines, seaprated in to two 64B chunks +typedef std::pair<uint64_t, uint64_t> cache_line; +typedef std::vector< cache_line > pattern; +extern const std::vector< pattern > patterns; + +} + +} +#endif + diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/settings.H b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/settings.H new file mode 100644 index 000000000..d9e564c62 --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/settings.H @@ -0,0 +1,475 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: chips/p9/procedures/hwp/memory/lib/mcbist/settings.H $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* EKB Project */ +/* */ +/* COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +/// +/// @file settings.H +/// @brief MCBIST settings, like stop conditions, thresholds, etc +/// +// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com> +// *HWP HWP Backup: Marc Gollub <gollub@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 2 +// *HWP Consumed by: HB:FSP + +#ifndef _MSS_MCBIST_SETTINGS_H_ +#define _MSS_MCBIST_SETTINGS_H_ + +#include <fapi2.H> + +#include <p9_mc_scom_addresses.H> +#include <p9_mc_scom_addresses_fld.H> + +#include <lib/mcbist/address.H> + +namespace mss +{ + +namespace mcbist +{ + +/// Stop conditions for MCBIST programs +enum stop_conditions +{ + NO_STOP_ON_ERROR = 0b00, + STOP_AFTER_ADDRESS = 0b01, + STOP_AFTER_RANK = 0b10, + STOP_AFTER_SUBTEST = 0b11, + + /// Don't change the stop conditions when continuing + DONT_CHANGE = 0xFF, +}; + +/// Boundary conditions for operations - when to stopmc +enum end_boundary +{ + NONE = 0, + CONTINUOUS = NONE, + NEVER = NONE, + DONT_STOP = NONE, + MASTER_RANK = 1, + MRANK = MASTER_RANK, + SLAVE_RANK = 2, + SRANK = SLAVE_RANK, +}; + +/// Speeds for performing MCBIST operations +enum speed +{ + /// As fast as possible, often the default + LUDICROUS = 0, + + /// Background scrubbing speed. + BG_SCRUB = 1, + + /// Used to indicate to the continue current command to not change the speed of the commands + SAME_SPEED = 4, +}; + +/// +/// @class Memory diagnostic subsystem error thresholds +/// @note Matches Nimbus MBSTRQ, but might be changed later for Centaur, or mapped. +/// +class thresholds +{ + public: + // Many of the config fields share a disable bit pattern, so we define it here + static constexpr uint64_t DISABLE = 0b1111; + + /// + /// @brief Thresholds class ctor + /// + thresholds(): + iv_value(0) + { } + + /// + /// @brief Thresholds class dtor + /// + ~thresholds() = default; + + /// + /// @brief uint64_t conversion + /// + inline operator uint64_t() const + { + return uint64_t(iv_value); + } + + /// @brief set_thresh_mag_nce_int + /// @param[in] i_value the value of the field + /// NCE intermittent error threshold magnitude to trigger for triggering pause. If + /// 1111, then pause will never be triggered (disabled). Else, then MCBIST will + /// pause if it takes sees 2^[this value] number of errors of this type. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_thresh_mag_nce_int( const uint64_t i_value ) + { + iv_value.insertFromRight<MCBIST_MBSTRQ_CFG_THRESH_MAG_NCE_INT, MCBIST_MBSTRQ_CFG_THRESH_MAG_NCE_INT_LEN>(i_value); + return *this; + } + + /// @brief set_thresh_mag_nce_soft + /// @param[in] i_value the value of the field + /// NCE soft error threshold magnitude to trigger for triggering pause. If 1111, + /// then pause will never be triggered (disabled). Else, then MCBIST will pause if it + /// takes sees 2^[this value] number of errors of this type. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_thresh_mag_nce_soft( const uint64_t i_value ) + { + iv_value.insertFromRight<MCBIST_MBSTRQ_CFG_THRESH_MAG_NCE_SOFT, MCBIST_MBSTRQ_CFG_THRESH_MAG_NCE_SOFT_LEN>(i_value); + return *this; + } + + /// @brief set_thresh_mag_nce_hard + /// @param[in] i_value the value of the field + /// NCE hard error threshold magnitude to trigger for triggering pause. If 1111, + /// then pause will never be triggered (disabled). Else, then MCBIST will pause if it + /// takes sees 2^[this value] number of errors of this type. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_thresh_mag_nce_hard( const uint64_t i_value ) + { + iv_value.insertFromRight<MCBIST_MBSTRQ_CFG_THRESH_MAG_NCE_HARD, MCBIST_MBSTRQ_CFG_THRESH_MAG_NCE_HARD_LEN>(i_value); + return *this; + } + + /// @brief set_thresh_mag_rce + /// @param[in] i_value the value of the field + /// RCE error threshold magnitude to trigger for triggering pause. If 1111, then + /// pause will never be triggered (disabled). Else, then MCBIST will pause if it takes + /// sees 2^[this value] number of errors of this type. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_thresh_mag_rce( const uint64_t i_value ) + { + iv_value.insertFromRight<MCBIST_MBSTRQ_CFG_THRESH_MAG_RCE, MCBIST_MBSTRQ_CFG_THRESH_MAG_RCE_LEN>(i_value); + return *this; + } + + /// @brief set_thresh_mag_ice + /// @param[in] i_value the value of the field + /// ICE (IMPE) error threshold magnitude to trigger for triggering pause. If 1111, + /// then pause will never be triggered (disabled). Else, then MCBIST will pause if + /// it takes sees 2^[this value] number of errors of this type. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_thresh_mag_ice( const uint64_t i_value ) + { + iv_value.insertFromRight<MCBIST_MBSTRQ_CFG_THRESH_MAG_ICE, MCBIST_MBSTRQ_CFG_THRESH_MAG_ICE_LEN>(i_value); + return *this; + } + + /// @brief set_thresh_mag_mce_int + /// @param[in] i_value the value of the field + /// MCE intermittent error threshold magnitude to trigger for triggering pause. If + /// 1111, then pause will never be triggered (disabled). Else, then MCBIST will + /// pause if it takes sees 2^[this value] number of errors of this type. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_thresh_mag_mce_int( const uint64_t i_value ) + { + iv_value.insertFromRight<MCBIST_MBSTRQ_CFG_THRESH_MAG_MCE_INT, MCBIST_MBSTRQ_CFG_THRESH_MAG_MCE_INT_LEN>(i_value); + return *this; + } + + /// @brief set_thresh_mag_mce_soft + /// @param[in] i_value the value of the field + /// MCE soft error threshold magnitude to trigger for triggering pause. If 1111, + /// then pause will never be triggered (disabled). Else, then MCBIST will pause if it + /// takes sees 2^[this value] number of errors of this type. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_thresh_mag_mce_soft( const uint64_t i_value ) + { + iv_value.insertFromRight<MCBIST_MBSTRQ_CFG_THRESH_MAG_MCE_SOFT, MCBIST_MBSTRQ_CFG_THRESH_MAG_MCE_SOFT_LEN>(i_value); + return *this; + } + + /// @brief set_thresh_mag_mce_hard + /// @param[in] i_value the value of the field + /// MCE hard error threshold magnitude to trigger for triggering pause. If 1111, + /// then pause will never be triggered (disabled). Else, then MCBIST will pause if it + /// takes sees 2^[this value] number of errors of this type. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_thresh_mag_mce_hard( const uint64_t i_value ) + { + iv_value.insertFromRight<MCBIST_MBSTRQ_CFG_THRESH_MAG_MCE_HARD, MCBIST_MBSTRQ_CFG_THRESH_MAG_MCE_HARD_LEN>(i_value); + return *this; + } + + /// @brief set_pause_on_sce + /// @param[in] i_value the value of the field + /// Enable pause on SCE error. When enabled, MCBIST will pause at the boundary + /// configured if this error is seen. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_pause_on_sce( const uint64_t i_value ) + { + iv_value.writeBit<MCBIST_MBSTRQ_CFG_PAUSE_ON_SCE>(i_value); + return *this; + } + + /// @brief set_pause_on_mce + /// @param[in] i_value the value of the field + /// Enable pause on MCE error. When enabled, MCBIST will pause at the boundary + /// configured if this error is seen. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_pause_on_mce( const uint64_t i_value ) + { + iv_value.writeBit<MCBIST_MBSTRQ_CFG_PAUSE_ON_MCE>(i_value); + return *this; + } + + /// @brief set_pause_on_mpe + /// @param[in] i_value the value of the field + /// Enable pause on MPE error. When enabled, MCBIST will pause at the boundary + /// configured if this error is seen. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_pause_on_mpe( const uint64_t i_value ) + { + iv_value.writeBit<MCBIST_MBSTRQ_CFG_PAUSE_ON_MPE>(i_value); + return *this; + } + + /// @brief set_pause_on_ue + /// @param[in] i_value the value of the field + /// Enable pause on UE error. When enabled, MCBIST will pause at the boundary + /// configured if this error is seen. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_pause_on_ue( const uint64_t i_value ) + { + iv_value.writeBit<MCBIST_MBSTRQ_CFG_PAUSE_ON_UE>(i_value); + return *this; + } + + /// @brief set_pause_on_sue + /// @param[in] i_value the value of the field + /// Enable pause on SUE error. When enabled, MCBIST will pause at the boundary + /// configured if this error is seen. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_pause_on_sue( const uint64_t i_value ) + { + iv_value.writeBit<MCBIST_MBSTRQ_CFG_PAUSE_ON_SUE>(i_value); + return *this; + } + + /// @brief set_pause_on_aue + /// @param[in] i_value the value of the field + /// Enable pause on AUE error. When enabled, MCBIST will pause at the boundary + /// configured if this error is seen. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_pause_on_aue( const uint64_t i_value ) + { + iv_value.writeBit<MCBIST_MBSTRQ_CFG_PAUSE_ON_AUE>(i_value); + return *this; + } + + /// @brief set_pause_on_rcd + /// @param[in] i_value the value of the field + /// Enable pause on RCD error. When enabled, MCBIST will pause at the boundary + /// configured if this error is seen. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_pause_on_rcd( const uint64_t i_value ) + { + iv_value.writeBit<MCBIST_MBSTRQ_CFG_PAUSE_ON_RCD>(i_value); + return *this; + } + + // Reserved. 39:52 + + /// @brief set_symbol_counter_mode + /// @param[in] i_value the value of the field + /// Selects which mode to use symbol counter latches: Mode 0) MAINT 8-bit error + /// counters for of 72 symbols Mode 1) MCBIST 4-bit error counters for 18 nibbles x 8 + /// ranks (port agnostic) Mode 2) MCBIST 4-bit error counters for 18 nibbles x 4 + /// ports (rank agnostic) and 1-bit error rank map for 18 nibbles x 4 ports + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_symbol_counter_mode( const uint64_t i_value ) + { + iv_value.insertFromRight<MCBIST_MBSTRQ_CFG_SYMBOL_COUNTER_MODE, MCBIST_MBSTRQ_CFG_SYMBOL_COUNTER_MODE_LEN>(i_value); + return *this; + } + + /// @brief set_nce_soft_symbol_count_enable + /// @param[in] i_value the value of the field + /// Enables soft NCEs to trigger per symbol NCE error counting Only applies to + /// scrub where we have different types of NCE. Non scrub counts all NCE. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_nce_soft_symbol_count_enable( const uint64_t i_value ) + { + iv_value.writeBit<MCBIST_MBSTRQ_CFG_NCE_SOFT_SYMBOL_COUNT_ENABLE>(i_value); + return *this; + } + + /// @brief set_nce_inter_symbol_count_enable + /// @param[in] i_value the value of the field + /// Enables intermittent NCEs to trigger per symbol NCE error counting Only applies + /// to scrub where we have different types of NCE. Non scrub counts all NCE. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_nce_inter_symbol_count_enable( const uint64_t i_value ) + { + iv_value.writeBit<MCBIST_MBSTRQ_CFG_NCE_INTER_SYMBOL_COUNT_ENABLE>(i_value); + return *this; + } + + /// @brief set_nce_hard_symbol_count_enable + /// @param[in] i_value the value of the field + /// Enables hard NCEs to trigger per symbol NCE error counting Only applies to + /// scrub where we have different types of NCE. Non scrub counts all NCE. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_nce_hard_symbol_count_enable( const uint64_t i_value ) + { + iv_value.writeBit<MCBIST_MBSTRQ_CFG_NCE_HARD_SYMBOL_COUNT_ENABLE>(i_value); + return *this; + } + + /// @brief set_pause_mcb_error + /// @param[in] i_value the value of the field + /// Enable pause when MCBIST error is logged. When enabled, MCBIST will pause at + /// the boundary configured if this error is seen. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_pause_mcb_error( const uint64_t i_value ) + { + iv_value.writeBit<MCBIST_MBSTRQ_CFG_PAUSE_MCB_ERROR>(i_value); + return *this; + } + + /// @brief set_pause_mcb_log_full + /// @param[in] i_value the value of the field + /// Enable pause when MCBIST log is full. When enabled, MCBIST will pause at the + /// boundary configured if this error is seen. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_pause_mcb_log_full( const uint64_t i_value ) + { + iv_value.writeBit<MCBIST_MBSTRQ_CFG_PAUSE_MCB_LOG_FULL>(i_value); + return *this; + } + + /// @brief set_maint_rce_with_ce + /// @param[in] i_value the value of the field + /// cfg_maint_rce_with_ce - not implemented. Need to investigate if needed for nimbus. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_maint_rce_with_ce( const uint64_t i_value ) + { + iv_value.writeBit<MCBIST_MBSTRQ_CFG_MAINT_RCE_WITH_CE>(i_value); + return *this; + } + + /// @brief set_mce_soft_symbol_count_enable + /// @param[in] i_value the value of the field + /// Enables soft MCEs to trigger per symbol MCE error counting Only applies to + /// scrub where we have different types of MCE. Non scrub counts all MCE. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_mce_soft_symbol_count_enable( const uint64_t i_value ) + { + iv_value.writeBit<MCBIST_MBSTRQ_CFG_MCE_SOFT_SYMBOL_COUNT_ENABLE>(i_value); + return *this; + } + + /// @brief set_mce_inter_symbol_count_enable + /// @param[in] i_value the value of the field + /// Enables intermittent MCEs to trigger per symbol MCE error counting Only applies + /// to scrub where we have different types of MCE. Non scrub counts all MCE. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_mce_inter_symbol_count_enable( const uint64_t i_value ) + { + iv_value.writeBit<MCBIST_MBSTRQ_CFG_MCE_INTER_SYMBOL_COUNT_ENABLE>(i_value); + return *this; + } + + /// @brief set_mce_hard_symbol_count_enable + /// @param[in] i_value the value of the field + /// Enables hard MCEs to trigger per symbol MCE error counting Only applies to + /// scrub where we have different types of MCE. Non scrub counts all MCE. + /// @return fapi2::buffer<uint64_t>& this->iv_value useful for method chaining + inline thresholds& set_mce_hard_symbol_count_enable( const uint64_t i_value ) + { + iv_value.writeBit<MCBIST_MBSTRQ_CFG_MCE_HARD_SYMBOL_COUNT_ENABLE>(iv_value); + return *this; + } + + private: + fapi2::buffer<uint64_t> iv_value; +}; + +/// +/// @class memdiags operational constraints +/// +struct constraints +{ + /// + /// @brief constraints constructor + /// + constraints(): + iv_stop(NO_STOP_ON_ERROR), + iv_thresholds(), + iv_pattern(NO_PATTERN), + iv_end_boundary(NONE), + iv_start_address(0), + iv_end_address(0) + { + } + + /// + /// @brief constraints constructor + /// @param[in] i_pattern a pattern to set + /// + constraints( const uint64_t i_pattern): + constraints() + { + iv_pattern = i_pattern; + FAPI_INF("setting up constraints with pattern %d", i_pattern); + } + + /// + /// @brief constraints constructor + /// @param[in] i_stop stop conditions + /// @param[in] i_thresholds thresholds + /// + constraints( const stop_conditions i_stop, + const thresholds& i_thresholds ): + constraints() + { + iv_stop = i_stop; + iv_thresholds = i_thresholds; + FAPI_INF("setting up constraints with stop %d and thresholds 0x%x", i_stop, uint64_t(i_thresholds)); + } + + /// + /// @brief constraints constructor + /// @param[in] i_stop stop conditions + /// @param[in] i_thresholds thresholds + /// @param[in] i_start_address address to start from + /// + constraints( const stop_conditions i_stop, + const thresholds& i_thresholds, + const address& i_start_address ): + constraints(i_stop, i_thresholds) + { + iv_start_address = i_start_address; + FAPI_INF("setting up constraints with stop %d and thresholds 0x%x start address", + i_stop, uint64_t(i_thresholds), uint64_t(i_start_address)); + } + + stop_conditions iv_stop; + thresholds iv_thresholds; + uint64_t iv_pattern; + end_boundary iv_end_boundary; + mcbist::address iv_start_address; + mcbist::address iv_end_address; +}; + + +} // namespace +} // namespace +#endif + diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/sim.C b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/sim.C new file mode 100644 index 000000000..029072fe9 --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/sim.C @@ -0,0 +1,160 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: chips/p9/procedures/hwp/memory/lib/mcbist/sim.C $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* EKB Project */ +/* */ +/* COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +/// +/// @file mcbist/sim.C +/// @brief MCBIST/memdiags functions for when we're in simulation mode +/// +// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com> +// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 2 +// *HWP Consumed by: FSP:HB + +#include <fapi2.H> + +#include <lib/dimm/rank.H> +#include <lib/mcbist/address.H> +#include <lib/mcbist/mcbist.H> +#include <lib/mcbist/patterns.H> +#include <lib/mcbist/sim.H> + +using fapi2::TARGET_TYPE_MCBIST; +using fapi2::TARGET_TYPE_MCA; +using fapi2::TARGET_TYPE_SYSTEM; +using fapi2::FAPI2_RC_SUCCESS; + +namespace mss +{ + +namespace mcbist +{ + +namespace sim +{ + +/// +/// @brief Perform a sim version of initializing memory +/// @param[in] i_target MCBIST +/// @param[in] i_pattern an index representing a pattern to use to initize memory (defaults to 0) +/// @return FAPI2_RC_SUCCESS iff ok +/// +template<> +fapi2::ReturnCode sf_init( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target, + const uint64_t i_pattern ) +{ + FAPI_INF("Start sim init"); + + // If we're running in the simulator, we want to only touch the addresses which training touched + + for (const auto& p : i_target.getChildren<TARGET_TYPE_MCA>()) + { + std::vector<uint64_t> l_pr; + mss::mcbist::program<TARGET_TYPE_MCBIST> l_program; + + mss::mcbist::address l_start; + mss::mcbist::address l_end; + + size_t l_rank_address_pair = 0; + + // In sim we know a few things ... + // Get the primary ranks for this port. We know there can only be 4, and we know we only trained the primary + // ranks. Therefore, we only need to clean up the primary ranks. And because there's 4 max, we can do it + // all using the 4 address range registers of tne MCBIST (broadcast currently not considered.) + // So we can write 0's to those to get their ECC fixed up. + FAPI_TRY( mss::primary_ranks(p, l_pr) ); + fapi2::Assert( l_pr.size() <= mss::MAX_RANK_PER_DIMM ); + + for (auto r = l_pr.begin(); r != l_pr.end(); ++l_rank_address_pair, ++r) + { + FAPI_INF("sim init %s, rank %d", mss::c_str(p), *r); + + // Setup l_start to represent this rank, and then make the end address from that. + l_start.set_master_rank(*r); + + l_start.get_range<mss::mcbist::address::COL>(l_end); + // Set C3 bit to get an entire cache line + l_end.set_field<mss::mcbist::address::COL>(0b1000000); + + // By default we're in maint address mode, not address counting mode. So we give it a start and end, and ignore + // anything invalid - that's what maint address mode is all about + mss::mcbist::config_address_range(i_target, l_start, l_end, l_rank_address_pair); + + // Write + { + // Run in ECC mode, 64B writes (superfast mode) + + mss::mcbist::subtest_t<TARGET_TYPE_MCBIST> l_fw_subtest = + mss::mcbist::write_subtest<TARGET_TYPE_MCBIST>(); + + l_fw_subtest.enable_port(mss::relative_pos<TARGET_TYPE_MCBIST>(p)); + l_fw_subtest.change_addr_sel(l_rank_address_pair); + l_fw_subtest.enable_dimm(mss::get_dimm_from_rank(*r)); + l_program.iv_subtests.push_back(l_fw_subtest); + FAPI_DBG("adding superfast write for %s rank %d (dimm %d)", mss::c_str(p), *r, mss::get_dimm_from_rank(*r)); + } + + // Read - we do a read here as verification can use this as a tool as we do the write and then the read. + // If we failed to write properly the read would thow ECC errors. Just a write (which the real hardware would + // do) doesn't catch that. This takes longer, but it's not terribly long in any event. + { + // Run in ECC mode, 64B writes (superfast mode) + mss::mcbist::subtest_t<TARGET_TYPE_MCBIST> l_fr_subtest = + mss::mcbist::read_subtest<TARGET_TYPE_MCBIST>(); + + l_fr_subtest.enable_port(mss::relative_pos<TARGET_TYPE_MCBIST>(p)); + l_fr_subtest.change_addr_sel(l_rank_address_pair); + l_fr_subtest.enable_dimm(mss::get_dimm_from_rank(*r)); + l_program.iv_subtests.push_back(l_fr_subtest); + FAPI_DBG("adding superfast read for %s rank %d (dimm %d)", mss::c_str(p), *r, mss::get_dimm_from_rank(*r)); + } + } + + // Write pattern + FAPI_TRY( mss::mcbist::load_pattern(i_target, i_pattern) ); + + // Setup the sim polling based on a heuristic <cough>guess</cough> + // Looks like ~400ck per address for a write/read program on the sim-dimm, and add a long number of polls + // On real hardware wait 100ms and then start polling for another 5s + l_program.iv_poll.iv_initial_sim_delay = mss::cycles_to_simcycles(((l_end - l_start) * l_pr.size()) * 800); + l_program.iv_poll.iv_initial_delay = 100 * mss::DELAY_1MS; + l_program.iv_poll.iv_sim_delay = 100000; + l_program.iv_poll.iv_delay = 10 * mss::DELAY_1MS; + l_program.iv_poll.iv_poll_count = 500; + + // Just one port for now. Per Shelton we need to set this in maint address mode + // even tho we specify the port/dimm in the subtest. + fapi2::buffer<uint8_t> l_port; + l_port.setBit(mss::relative_pos<TARGET_TYPE_MCBIST>(p)); + l_program.select_ports(l_port >> 4); + + // Kick it off, wait for a result + FAPI_TRY( mss::mcbist::execute(i_target, l_program) ); + } + +fapi_try_exit: + FAPI_INF("End sim init"); + return fapi2::current_err; +} + +} // namespace sim + +} // namespace mcbist + +} // namespace mss diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/sim.H b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/sim.H new file mode 100644 index 000000000..e0b6af46b --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/sim.H @@ -0,0 +1,58 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: chips/p9/procedures/hwp/memory/lib/mcbist/sim.H $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* EKB Project */ +/* */ +/* COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +/// +/// @file mcbist/sim.H +/// @brief MCBIST/memdiags functions for when we're in simulation mode +/// +// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com> +// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 2 +// *HWP Consumed by: FSP:HB + +#ifndef _MSS_MCBIST_SIM_H_ +#define _MSS_MCBIST_SIM_H_ + +#include <fapi2.H> + +namespace mss +{ + +namespace mcbist +{ + +namespace sim +{ + +/// +/// @brief Perform a sim version of initializing memory +/// @param T a fapi2::TargetType +/// @param[in] i_target +/// @param[in] i_pattern an index representing a pattern to use to initize memory (defaults to 0) +/// @return FAPI2_RC_SUCCESS iff ok +/// +template< fapi2::TargetType T > +fapi2::ReturnCode sf_init( const fapi2::Target<T>& i_target, const uint64_t i_pattern ); + +} // ns sim +} // ns mcbist +} // ns mss +#endif + diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/find.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/find.H index 1a81db863..77aa4fcc5 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/utils/find.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/find.H @@ -34,6 +34,8 @@ #include <map> #include <vector> +#include <lib/utils/pos.H> + namespace mss { @@ -163,6 +165,30 @@ inline std::vector< fapi2::Target<fapi2::TARGET_TYPE_MCS> > find_targets( const } /// +/// @brief find all the MCA connected to an MCBIST +/// @param[in] i_target a fapi2::Target MCBIST +/// @return a vector of fapi2::TARGET_TYPE_MCA +/// +template<> +inline std::vector< fapi2::Target<fapi2::TARGET_TYPE_MCA> > find_targets( const + fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target ) +{ + return i_target.getChildren<fapi2::TARGET_TYPE_MCA>(); +} + +/// +/// @brief find all the DIMM connected to an MCA +/// @param[in] i_target a fapi2::Target MCA +/// @return a vector of fapi2::TARGET_TYPE_DIMM +/// +template<> +inline std::vector< fapi2::Target<fapi2::TARGET_TYPE_DIMM> > find_targets( const + fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target ) +{ + return i_target.getChildren<fapi2::TARGET_TYPE_DIMM>(); +} + +/// /// @brief find the MCS given a DIMM /// @param[in] i_target the fapi2 target DIMM /// @return a MCS target. @@ -221,6 +247,30 @@ bool find_value_from_key(const std::vector<std::pair<T, OT> >& i_vector_of_pairs }// find_value_from_key +/// +/// @brief Determine if a thing is functional +/// @tparam P, the type of the parent which holds the things of interest +/// @tparam I, the type of the item we want to check for +/// @param[in] i_target the parent containing the thing we're looking for +/// @param[in] i_rel_pos the relative position of the item of interest. +/// @return bool true iff the thing at i_rel_pos is noted as functional +/// +template< fapi2::TargetType I, fapi2::TargetType P > +bool is_functional( const fapi2::Target<P>& i_target, const uint64_t i_rel_pos ) +{ + // Not sure of a good way to do this ... we get all the functional + // children of the parent and look for our relative position ... + for (const auto& i : i_target.template getChildren<I>(fapi2::TARGET_STATE_FUNCTIONAL)) + { + if (mss::template relative_pos<P>(i) == i_rel_pos) + { + return true; + } + } + + return false; +} + }// mss #endif diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/scom.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/scom.H index a63d20d95..9a3491320 100644 --- a/src/import/chips/p9/procedures/hwp/memory/lib/utils/scom.H +++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/scom.H @@ -31,7 +31,7 @@ #define _MSS_SCOM_H_ #include <fapi2.H> -#include <utils/c_str.H> +#include <lib/utils/c_str.H> // // Wrapping scom operations: We wrap fapi2::get/putScom for two reasons. The diff --git a/src/import/chips/p9/procedures/hwp/memory/p9_mss_memdiag.C b/src/import/chips/p9/procedures/hwp/memory/p9_mss_memdiag.C index 57bc8010c..a89ed4186 100644 --- a/src/import/chips/p9/procedures/hwp/memory/p9_mss_memdiag.C +++ b/src/import/chips/p9/procedures/hwp/memory/p9_mss_memdiag.C @@ -30,6 +30,11 @@ #include <fapi2.H> #include <p9_mss_memdiag.H> +#include <lib/utils/poll.H> +#include <lib/mcbist/address.H> +#include <lib/mcbist/memdiags.H> +#include <lib/mcbist/mcbist.H> + using fapi2::TARGET_TYPE_MCBIST; extern "C" @@ -42,7 +47,38 @@ extern "C" fapi2::ReturnCode p9_mss_memdiag( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target ) { FAPI_INF("Start memdiag"); + + FAPI_TRY( memdiags::sf_init(i_target, mss::mcbist::PATTERN_0) ); + + // TODO RTC:153951 + // Remove the polling when the attention bits are hooked up + { + // Poll for the fir bit. We expect this to be set ... + fapi2::buffer<uint64_t> l_status; + + // A small vector of addresses to poll during the polling loop + static const std::vector<mss::poll_probe<fapi2::TARGET_TYPE_MCBIST>> l_probes = + { + {i_target, "mcbist current address", MCBIST_MCBMCATQ}, + }; + + mss::poll_parameters l_poll_parameters; + bool l_poll_results = mss::poll(i_target, MCBIST_MCBISTFIRQ, l_poll_parameters, + [&l_status](const size_t poll_remaining, const fapi2::buffer<uint64_t>& stat_reg) -> bool + { + FAPI_DBG("mcbist firq 0x%llx, remaining: %d", stat_reg, poll_remaining); + l_status = stat_reg; + return l_status.getBit<MCBIST_MCBISTFIRQ_MCBIST_PROGRAM_COMPLETE>() == true; + }, + l_probes); + + FAPI_ASSERT( l_poll_results == true, + fapi2::MSS_MEMDIAGS_SUPERFAST_INIT_FAILED_TO_INIT().set_TARGET(i_target), + "p9_mss_memdiags timedout %s", mss::c_str(i_target) ); + } + + fapi_try_exit: FAPI_INF("End memdiag"); - return fapi2::FAPI2_RC_SUCCESS; + return fapi2::current_err; } } diff --git a/src/import/chips/p9/procedures/hwp/memory/p9_mss_scrub.C b/src/import/chips/p9/procedures/hwp/memory/p9_mss_scrub.C index 9dadf7e05..18d3e74dc 100644 --- a/src/import/chips/p9/procedures/hwp/memory/p9_mss_scrub.C +++ b/src/import/chips/p9/procedures/hwp/memory/p9_mss_scrub.C @@ -33,7 +33,9 @@ #include <lib/dimm/rank.H> #include <lib/mcbist/address.H> #include <lib/mcbist/mcbist.H> -#include <lib/dimm/kind.H> +#include <lib/mcbist/patterns.H> +#include <lib/mcbist/memdiags.H> +#include <lib/mcbist/sim.H> using fapi2::TARGET_TYPE_MCBIST; using fapi2::TARGET_TYPE_MCA; @@ -53,102 +55,19 @@ fapi2::ReturnCode p9_mss_scrub( const fapi2::Target<TARGET_TYPE_MCBIST>& i_targe uint8_t is_sim = 0; FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<TARGET_TYPE_SYSTEM>(), is_sim) ); - for (const auto& p : i_target.getChildren<TARGET_TYPE_MCA>()) + if (is_sim) { - std::vector<uint64_t> l_pr; - mss::mcbist::program<TARGET_TYPE_MCBIST> l_program; - - mss::mcbist::address l_start; - mss::mcbist::address l_end; - - size_t l_rank_address_pair = 0; - - // In sim we know a few things ... - // Get the primary ranks for this port. We know there can only be 4, and we know we only trained the primary - // ranks. Therefore, we only need to clean up the primary ranks. And because there's 4 max, we can do it - // all using the 4 address range registers of tne MCBIST (broadcast currently not considered.) - // So we can write 0's to those to get their ECC fixed up. - FAPI_TRY( mss::primary_ranks(p, l_pr) ); - fapi2::Assert( l_pr.size() <= mss::MAX_RANK_PER_DIMM); - - for (auto r = l_pr.begin(); r != l_pr.end(); ++l_rank_address_pair, ++r) - { - // Setup l_start to represent this rank, and then make the end address from that. - l_start.set_master_rank(*r); - - // l_end starts like as the max as we want to scrub the entire thing. If we're in sim, - // we'll wratchet that back. - l_start.get_range<mss::mcbist::address::MRANK>(l_end); - - if (is_sim) - { - l_start.get_range<mss::mcbist::address::COL>(l_end); - // Set C3 bit to get an entire cache line - l_end.set_field<mss::mcbist::address::COL>(0b1000000); - } - - // By default we're in maint address mode, not address counting mode. So we give it a start and end, and ignore - // anything invalid - that's what maint address mode is all about - mss::mcbist::config_address_range(i_target, l_start, l_end, l_rank_address_pair); - - // Write - { - // Run in ECC mode, 64B writes (superfast mode) - - mss::mcbist::subtest_t<TARGET_TYPE_MCBIST> l_fw_subtest = - mss::mcbist::write_subtest<TARGET_TYPE_MCBIST>(); - - l_fw_subtest.enable_port(mss::relative_pos<TARGET_TYPE_MCBIST>(p)); - l_fw_subtest.change_addr_sel(l_rank_address_pair); - l_fw_subtest.enable_dimm(mss::get_dimm_from_rank(*r)); - l_program.iv_subtests.push_back(l_fw_subtest); - FAPI_DBG("adding superfast write for %s rank %d (dimm %d)", mss::c_str(p), *r, mss::get_dimm_from_rank(*r)); - } - - // Read - { - // Run in ECC mode, 64B writes (superfast mode) - mss::mcbist::subtest_t<TARGET_TYPE_MCBIST> l_fr_subtest = - mss::mcbist::read_subtest<TARGET_TYPE_MCBIST>(); - - l_fr_subtest.enable_port(mss::relative_pos<TARGET_TYPE_MCBIST>(p)); - l_fr_subtest.change_addr_sel(l_rank_address_pair); - l_fr_subtest.enable_dimm(mss::get_dimm_from_rank(*r)); - l_program.iv_subtests.push_back(l_fr_subtest); - FAPI_DBG("adding superfast read for %s rank %d (dimm %d)", mss::c_str(p), *r, mss::get_dimm_from_rank(*r)); - } - } - - // Write pattern - FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD0Q, 0x1234567890ABCDEF) ); - FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD1Q, 0x1234567890ABCDEF) ); - FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD2Q, 0x1234567890ABCDEF) ); - FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD3Q, 0x1234567890ABCDEF) ); - FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD4Q, 0x1234567890ABCDEF) ); - FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD5Q, 0x1234567890ABCDEF) ); - FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD6Q, 0x1234567890ABCDEF) ); - FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD7Q, 0x1234567890ABCDEF) ); - - // Setup the sim polling based on a heuristic <cough>guess</cough> - // Looks like ~400ck per address for a write/read program on the sim-dimm, and add a long number of polls - // On real hardware wait 100ms and then start polling for another 5s - l_program.iv_poll.iv_initial_sim_delay = mss::cycles_to_simcycles(((l_end - l_start) * l_pr.size()) * 800); - l_program.iv_poll.iv_initial_delay = 100 * mss::DELAY_1MS; - l_program.iv_poll.iv_sim_delay = 100000; - l_program.iv_poll.iv_delay = 10 * mss::DELAY_1MS; - l_program.iv_poll.iv_poll_count = 500; - - // Just one port for now. Per Shelton we need to set this in maint address mode - // even tho we specify the port/dimm in the subtest. - fapi2::buffer<uint8_t> l_port; - l_port.setBit(mss::relative_pos<TARGET_TYPE_MCBIST>(p)); - l_program.select_ports(l_port >> 4); - - // Kick it off, wait for a result - FAPI_TRY( mss::mcbist::execute(i_target, l_program) ); + // Use some sort of pattern in sim in case the verification folks need to look for something + // TK. Need a verification pattern. This is a not-good pattern for verification ... We don't really + // have a good pattern for verification defined. + FAPI_INF("running mss sim init in place of scrub"); + return mss::mcbist::sim::sf_init(i_target, mss::mcbist::PATTERN_2); } + // TK do we want these to be arguments to the wrapper? + return memdiags::scrub(i_target, mss::mcbist::stop_conditions::NO_STOP_ON_ERROR, mss::mcbist::thresholds(), + mss::mcbist::speed::LUDICROUS, mss::mcbist::address()); + fapi_try_exit: - FAPI_INF("End mss scrub"); return fapi2::current_err; } diff --git a/src/import/chips/p9/procedures/hwp/memory/tests/mss_memdiags_ut.C b/src/import/chips/p9/procedures/hwp/memory/tests/mss_memdiags_ut.C new file mode 100644 index 000000000..a5a167a78 --- /dev/null +++ b/src/import/chips/p9/procedures/hwp/memory/tests/mss_memdiags_ut.C @@ -0,0 +1,455 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: chips/p9/procedures/hwp/memory/tests/mss_memdiags_ut.C $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* EKB Project */ +/* */ +/* COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +/// +/// @file mss_memdiags_ut.C +/// @brief Unit tests for memory MEMDIAGS functions +/// +// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com> +// *HWP FW Owner: Marc Gollub <gollub@us.ibm.com> +// *HWP Team: Memory +// *HWP Level: 4 +// *HWP Consumed by: CI +//#pragma once + +#include <cstdarg> + +#include <mss.H> +#include <catch.hpp> + +#include <lib/mcbist/mcbist.H> +#include <lib/mcbist/memdiags.H> +#include <lib/mcbist/address.H> +#include <lib/mcbist/settings.H> + +#include <lib/utils/poll.H> +#include <tests/target_fixture.H> + +using fapi2::FAPI2_RC_SUCCESS; +using fapi2::TARGET_TYPE_MCBIST; +using fapi2::TARGET_TYPE_MCA; +using fapi2::TARGET_TYPE_MCS; + +namespace mss +{ +namespace test +{ + +/** + * @brief Test Case for memdiags + * @note mcbist_target_test_fixture is the fixture to use with this test case + */ +TEST_CASE_METHOD(mss::test::mcbist_target_test_fixture, "memdiags", "[memdiags]") +{ + // Don't count the invalid maint address - we know we're setting that. + fapi2::buffer<uint64_t> l_fir_mask; + l_fir_mask.setBit<MCBIST_MCBISTFIRQ_INVALID_MAINT_ADDRESS>().invert(); + + // Loops over MCBIST targets that were defined in the associated config + for_each_target([l_fir_mask](const fapi2::Target<TARGET_TYPE_MCBIST>& i_target) + { + SECTION("Test thresholds structure") + { + mss::mcbist::thresholds l_t; + REQUIRE( 0 == l_t ); + + { + l_t.set_thresh_mag_nce_int( mss::mcbist::thresholds::DISABLE ); + REQUIRE( 0xf000000000000000 == l_t ); + } + + { + l_t.set_thresh_mag_nce_soft( mss::mcbist::thresholds::DISABLE ); + REQUIRE( 0xff00000000000000 == l_t ); + } + + { + l_t.set_thresh_mag_nce_hard( mss::mcbist::thresholds::DISABLE ); + REQUIRE( 0xfff0000000000000 == l_t ); + } + + { + l_t.set_thresh_mag_rce( mss::mcbist::thresholds::DISABLE ); + REQUIRE( 0xffff000000000000 == l_t ); + } + + // Little method chaining check + { + l_t.set_thresh_mag_ice( mss::mcbist::thresholds::DISABLE ) + .set_thresh_mag_mce_int( mss::mcbist::thresholds::DISABLE ); + REQUIRE( 0xffffff0000000000 == l_t ); + } + + { + l_t.set_thresh_mag_mce_soft( mss::mcbist::thresholds::DISABLE ); + REQUIRE( 0xfffffff000000000 == l_t ); + } + + { + l_t.set_thresh_mag_mce_hard( mss::mcbist::thresholds::DISABLE ); + REQUIRE( 0xffffffff00000000 == l_t ); + } + + { + l_t.set_pause_on_sce( mss::ON ); + REQUIRE( 0xffffffff80000000 == l_t ); + } + + { + l_t.set_pause_on_mce( mss::ON ); + REQUIRE( 0xffffffffc0000000 == l_t ); + } + + { + l_t.set_pause_on_mpe( mss::ON ); + REQUIRE( 0xffffffffe0000000 == l_t ); + } + + { + l_t.set_pause_on_ue( mss::ON ); + REQUIRE( 0xfffffffff0000000 == l_t ); + } + + { + l_t.set_pause_on_sue( mss::ON ); + REQUIRE( 0xfffffffff8000000 == l_t ); + } + + { + l_t.set_pause_on_aue( mss::ON ); + REQUIRE( 0xfffffffffc000000 == l_t ); + } + + { + l_t.set_pause_on_rcd( mss::ON ); + REQUIRE( 0xfffffffffe000000 == l_t ); + } + + { + l_t.set_symbol_counter_mode( mss::mcbist::thresholds::DISABLE ); + REQUIRE( 0xfffffffffe000600 == l_t ); + } + + { + l_t.set_nce_hard_symbol_count_enable( mss::ON ); + REQUIRE( 0xfffffffffe000640 == l_t ); + } + + { + l_t.set_pause_mcb_error( mss::ON ); + REQUIRE( 0xfffffffffe000660 == l_t ); + } + + { + l_t.set_pause_mcb_log_full( mss::ON ); + REQUIRE( 0xfffffffffe000670 == l_t ); + } + + { + l_t.set_maint_rce_with_ce( mss::ON ); + REQUIRE( 0xfffffffffe000678 == l_t ); + } + + { + l_t.set_mce_soft_symbol_count_enable( mss::ON ); + REQUIRE( 0xfffffffffe00067c == l_t ); + } + + { + l_t.set_mce_inter_symbol_count_enable( mss::ON ); + REQUIRE( 0xfffffffffe00067e == l_t ); + } + + { + l_t.set_mce_hard_symbol_count_enable( mss::ON ); + REQUIRE( 0xfffffffffe00067f == l_t ); + } + } + + // Note that the testing of the memdiags operations leverages the helper directly + // is it is more flexible allowing better control over simulation environments. + SECTION("Test sf_init") + { + // Loading of patterns is tested in the mcbist unit test. + + mss::mcbist::constraints l_const(memdiags::PATTERN_5); + + // The addresses here are calculated so that we get a few iterations + // of polling on an AWAN, but not so much that we run the risk of timing out + mss::mcbist::address().get_range<mss::mcbist::address::COL>(l_const.iv_end_address); + l_const.iv_end_address.set_column(0b111111); + memdiags::sf_operation<TARGET_TYPE_MCBIST> l_bob(i_target, l_const, mss::mcbist::init_subtest<TARGET_TYPE_MCBIST>()); + REQUIRE_FALSE( l_bob.init() ); + REQUIRE_FALSE( l_bob.execute() ); + + // Check the things we default to so that we have a canary in case the defaults change + // Zero out cmd timebase - mcbist::program constructor does that for us. + { + fapi2::buffer<uint64_t> l_read; + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBPARMQ, l_read) ); + REQUIRE( 0 == l_read ); + } + + // Load stop conditions - default state - already 0's from mcbist::program's ctor. + { + fapi2::buffer<uint64_t> l_read; + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBCFGQ, l_read) ); + REQUIRE( 0x0000000000000080 == l_read ); + } + + // Load thresholds - default state (expecting 0's) + { + fapi2::buffer<uint64_t> l_read; + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MBSTRQ, l_read) ); + REQUIRE( 0x0 == l_read ); + } + + // Enable maint addressing mode - enabled by default in the mcbist::program ctor + { + fapi2::buffer<uint64_t> l_read; + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBAGRAQ, l_read) ); + REQUIRE( 0x0020000000000000 == l_read ); + } + + // Check the address registers + { + fapi2::buffer<uint64_t> l_read; + + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBSA0Q, l_read) ); + REQUIRE(l_read == 0x0); + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBEA0Q, l_read) ); + REQUIRE(l_read == 0x0000001ffc000000); + } + + // Poll for the fir bit. We expect this to be set ... + fapi2::buffer<uint64_t> l_status; + + // A small vector of addresses to poll during the polling loop + static const std::vector<mss::poll_probe<fapi2::TARGET_TYPE_MCBIST>> l_probes = + { + {i_target, "mcbist current address", MCBIST_MCBMCATQ}, + }; + + poll_parameters l_poll_parameters; + bool l_poll_results = mss::poll(i_target, MCBIST_MCBISTFIRQ, l_poll_parameters, + [&l_status](const size_t poll_remaining, const fapi2::buffer<uint64_t>& stat_reg) -> bool + { + FAPI_DBG("mcbist firq 0x%llx, remaining: %d", stat_reg, poll_remaining); + l_status = stat_reg; + return l_status.getBit<MCBIST_MCBISTFIRQ_MCBIST_PROGRAM_COMPLETE>() == true; + }, + l_probes); + + REQUIRE( l_poll_results == true ); + + // Check for errors + { + fapi2::buffer<uint64_t> l_read; + + REQUIRE( 0x20000000000000 == (l_status & l_fir_mask) ); + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBSTATQ, l_read) ); + REQUIRE(l_read == 0); + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MBSEC1Q, l_read) ); + REQUIRE(l_read == 0); + } + + } + + + SECTION("Test sf_read") + { + // Loading of patterns is tested in the mcbist unit test. + + mss::mcbist::constraints l_const(memdiags::stop_conditions::NO_STOP_ON_ERROR, memdiags::thresholds()); + + // The addresses here are calculated so that we get a few iterations + // of polling on an AWAN, but not so much that we run the risk of timing out + mss::mcbist::address().get_range<mss::mcbist::address::COL>(l_const.iv_end_address); + l_const.iv_end_address.set_column(0b111111); + memdiags::sf_operation<TARGET_TYPE_MCBIST> l_bob(i_target, l_const, mss::mcbist::read_subtest<TARGET_TYPE_MCBIST>()); + REQUIRE_FALSE( l_bob.init() ); + REQUIRE_FALSE( l_bob.execute() ); + + // Check the things we default to so that we have a canary in case the defaults change + // Zero out cmd timebase - mcbist::program constructor does that for us. + { + fapi2::buffer<uint64_t> l_read; + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBPARMQ, l_read) ); + REQUIRE( 0 == l_read ); + } + + // Load stop conditions - default state - already 0's from mcbist::program's ctor. + { + fapi2::buffer<uint64_t> l_read; + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBCFGQ, l_read) ); + REQUIRE( 0x0000000000000080 == l_read ); + } + + // Load thresholds - default state (expecting 0's) + { + fapi2::buffer<uint64_t> l_read; + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MBSTRQ, l_read) ); + REQUIRE( 0x0 == l_read ); + } + + // Enable maint addressing mode - enabled by default in the mcbist::program ctor + { + fapi2::buffer<uint64_t> l_read; + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBAGRAQ, l_read) ); + REQUIRE( 0x0020000000000000 == l_read ); + } + + // Check the address registers + { + fapi2::buffer<uint64_t> l_read; + + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBSA0Q, l_read) ); + REQUIRE(l_read == 0x0); + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBEA0Q, l_read) ); + REQUIRE(l_read == 0x0000001ffc000000); + } + + // Poll for the fir bit. We expect this to be set ... + fapi2::buffer<uint64_t> l_status; + + // A small vector of addresses to poll during the polling loop + static const std::vector<mss::poll_probe<fapi2::TARGET_TYPE_MCBIST>> l_probes = + { + {i_target, "mcbist current address", MCBIST_MCBMCATQ}, + }; + + poll_parameters l_poll_parameters; + bool l_poll_results = mss::poll(i_target, MCBIST_MCBISTFIRQ, l_poll_parameters, + [&l_status](const size_t poll_remaining, const fapi2::buffer<uint64_t>& stat_reg) -> bool + { + FAPI_DBG("mcbist firq 0x%llx, remaining: %d", stat_reg, poll_remaining); + l_status = stat_reg; + return l_status.getBit<MCBIST_MCBISTFIRQ_MCBIST_PROGRAM_COMPLETE>() == true; + }, + l_probes); + + REQUIRE( l_poll_results == true ); + + // Check for errors + { + fapi2::buffer<uint64_t> l_read; + + REQUIRE( 0x20000000000000 == (l_status & l_fir_mask) ); + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBSTATQ, l_read) ); + REQUIRE(l_read == 0); + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MBSEC1Q, l_read) ); + REQUIRE(l_read == 0); + } + } + + + SECTION("Test sf_read to end of port") + { + // Loading of patterns is tested in the mcbist unit test. + + // The addresses here are calculated so that we get a few iterations + // of polling on an AWAN, but not so much that we run the risk of timing out + mss::mcbist::address l_start; + mss::mcbist::address().get_range<mss::mcbist::address::DIMM>(l_start); + l_start.set_bank(0); + l_start.set_bank_group(0); + l_start.set_column(0); + + REQUIRE_FALSE( memdiags::sf_read(i_target, mss::mcbist::stop_conditions::STOP_AFTER_ADDRESS, + mss::mcbist::thresholds(), l_start) ); + + // Check the things we default to so that we have a canary in case the defaults change + // Zero out cmd timebase - mcbist::program constructor does that for us. + { + fapi2::buffer<uint64_t> l_read; + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBPARMQ, l_read) ); + REQUIRE( 0 == l_read ); + } + + // Load stop conditions - default state - already 0's from mcbist::program's ctor. + { + fapi2::buffer<uint64_t> l_read; + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBCFGQ, l_read) ); + REQUIRE( 0x00000000000000a0 == l_read ); + } + + // Load thresholds - default state (expecting 0's) + { + fapi2::buffer<uint64_t> l_read; + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MBSTRQ, l_read) ); + REQUIRE( 0x0 == l_read ); + } + + // Enable maint addressing mode - enabled by default in the mcbist::program ctor + { + fapi2::buffer<uint64_t> l_read; + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBAGRAQ, l_read) ); + REQUIRE( 0x0020000000000000 == l_read ); + } + + // Check the address registers + { + fapi2::buffer<uint64_t> l_read; + + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBSA0Q, l_read) ); + REQUIRE(l_read == 0x1FFFFFC000000000); + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBEA0Q, l_read) ); + REQUIRE(l_read == 0x1FFFFFFFFC000000); + } + + // Poll for the fir bit. We expect this to be set ... + fapi2::buffer<uint64_t> l_status; + + // A small vector of addresses to poll during the polling loop + static const std::vector<mss::poll_probe<fapi2::TARGET_TYPE_MCBIST>> l_probes = + { + {i_target, "mcbist current address", MCBIST_MCBMCATQ}, + }; + + poll_parameters l_poll_parameters; + bool l_poll_results = mss::poll(i_target, MCBIST_MCBISTFIRQ, l_poll_parameters, + [&l_status](const size_t poll_remaining, const fapi2::buffer<uint64_t>& stat_reg) -> bool + { + FAPI_DBG("mcbist firq 0x%llx, remaining: %d", stat_reg, poll_remaining); + l_status = stat_reg; + return l_status.getBit<MCBIST_MCBISTFIRQ_MCBIST_PROGRAM_COMPLETE>() == true; + }, + l_probes); + + REQUIRE( l_poll_results == true ); + + // Check for errors + { + fapi2::buffer<uint64_t> l_read; + + REQUIRE( 0x20000000000000 == (l_status & l_fir_mask) ); + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBSTATQ, l_read) ); + REQUIRE(l_read == 0); + REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MBSEC1Q, l_read) ); + REQUIRE(l_read == 0); + } + + } + + return 0; + }); +} + +} // ns test +} // ns mss diff --git a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_memdiags.xml b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_memdiags.xml index fa713e756..306703b15 100644 --- a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_memdiags.xml +++ b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_memdiags.xml @@ -39,5 +39,66 @@ </callout> </hwpError> + <hwpError> + <rc>RC_MSS_MEMDIAGS_INVALID_PATTERN_INDEX</rc> + <description>An invalid pattern index was passed to the pattern loader</description> + <ffdc>INDEX</ffdc> + <callout> + <target>TARGET</target> + <priority>HIGH</priority> + </callout> + </hwpError> + + <hwpError> + <rc>RC_MSS_MEMDIAGS_INVALID_PATTERN_SIZE</rc> + <description>An invalid pattern (incorrect size) was passed to the pattern loader</description> + <ffdc>SIZE</ffdc> + <callout> + <target>TARGET</target> + <priority>HIGH</priority> + </callout> + </hwpError> + + <hwpError> + <rc>RC_MSS_MEMDIAGS_MCBIST_FAILED_TO_START</rc> + <description>The MCBIST engine failed to start its program</description> + <ffdc>TARGET</ffdc> + <callout> + <target>TARGET</target> + <priority>HIGH</priority> + </callout> + </hwpError> + + <hwpError> + <rc>RC_MSS_MEMDIAGS_PORT_NOT_FUNCTIONAL</rc> + <description>The port used in an MCBIST program is not functional</description> + <ffdc>RELATIVE_PORT_POSITION</ffdc> + <ffdc>ADDRESS</ffdc> + <callout> + <target>TARGET</target> + <priority>HIGH</priority> + </callout> + </hwpError> + + <hwpError> + <rc>RC_MSS_MEMDIAGS_SUPERFAST_READ_FAILED_TO_INIT</rc> + <description>A superfast read operation failed initialization</description> + <ffdc>TARGET</ffdc> + <callout> + <target>TARGET</target> + <priority>HIGH</priority> + </callout> + </hwpError> + + <hwpError> + <rc>RC_MSS_MEMDIAGS_SUPERFAST_INIT_FAILED_TO_INIT</rc> + <description>A superfast init operation failed initialization</description> + <ffdc>TARGET</ffdc> + <callout> + <target>TARGET</target> + <priority>HIGH</priority> + </callout> + </hwpError> + </hwpErrors> |