summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9
diff options
context:
space:
mode:
authorBrian Silver <bsilver@us.ibm.com>2016-05-24 11:09:40 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2016-06-03 16:54:20 -0400
commitbcb6c08798d47bff3a8b6939d1514c2739cda3a6 (patch)
treeb4c3cd006a85363fc31034655840f2bf1164235a /src/import/chips/p9
parent3889e6f5c30b61d12947726a616be1186b60c0ff (diff)
downloadtalos-hostboot-bcb6c08798d47bff3a8b6939d1514c2739cda3a6.tar.gz
talos-hostboot-bcb6c08798d47bff3a8b6939d1514c2739cda3a6.zip
Add memdiags implementation for superfast operations
Change the actions to repair test fails. Change the translation test to repair fails. Change-Id: I3c6c0a02efce5cb6562fba0f4cda5487eeb79f32 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/25168 Tested-by: PPE CI Tested-by: Jenkins Server Tested-by: Hostboot CI Reviewed-by: ANDRE A. MARIN <aamarin@us.ibm.com> Reviewed-by: Louis Stermole <stermole@us.ibm.com> Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com> Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/25170 Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com> Tested-by: FSP CI Jenkins Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9')
-rw-r--r--src/import/chips/p9/common/include/p9_mc_scom_addresses_fld_fixes.H3
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lab/sdk/example/C/mss_lab_sfwrite.C124
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lab/sdk/example/C/mss_lab_sfwrite.mk25
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/address.H18
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.C105
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.H280
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/memdiags.C359
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/memdiags.H354
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/patterns.C82
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/patterns.H70
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/settings.H475
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/sim.C160
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/sim.H58
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/utils/find.H50
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/utils/scom.H2
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/p9_mss_memdiag.C38
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/p9_mss_scrub.C107
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/tests/mss_memdiags_ut.C455
-rw-r--r--src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_memdiags.xml61
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>
OpenPOWER on IntegriCloud