summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp
diff options
context:
space:
mode:
authorBrian Silver <bsilver@us.ibm.com>2016-06-02 06:28:57 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2016-06-10 14:46:49 -0400
commit3d485fbdab55175f716253b4fe4c52835c93a5a0 (patch)
tree1a36d89d454e170b69d0b93e921033d1e1512722 /src/import/chips/p9/procedures/hwp
parent0c34e40e9061b3431e294931659dc67c8f340130 (diff)
downloadtalos-hostboot-3d485fbdab55175f716253b4fe4c52835c93a5a0.tar.gz
talos-hostboot-3d485fbdab55175f716253b4fe4c52835c93a5a0.zip
Add memdiags scrub capability
Change-Id: I1f42c836a8fc4ff3ca31401ec53f2a3aeda77513 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/25376 Reviewed-by: Zane C. Shelley <zshelle@us.ibm.com> Tested-by: Jenkins Server Tested-by: Hostboot CI Reviewed-by: ANDRE A. MARIN <aamarin@us.ibm.com> Reviewed-by: STEPHEN GLANCY <sglancy@us.ibm.com> Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com> Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/25377 Tested-by: FSP CI Jenkins Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9/procedures/hwp')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/eff_config/memory_size.C36
-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.C19
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.H363
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/memdiags.C481
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/memdiags.H267
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/settings.H31
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/mcbist/sim.C3
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H8
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/p9_mss_scrub.C4
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/tests/mss_memdiags_ut.C264
11 files changed, 1271 insertions, 223 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/memory_size.C b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/memory_size.C
index 48da0578f..6f6d50995 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/memory_size.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/eff_config/memory_size.C
@@ -33,8 +33,11 @@
#include <lib/shared/mss_const.H>
#include <lib/eff_config/memory_size.H>
+#include <lib/utils/find.H>
+
namespace mss
{
+
///
/// @brief Return the total memory size behind an MCA
/// @param[in] i_target the MCA target
@@ -44,12 +47,12 @@ namespace mss
template<>
fapi2::ReturnCode eff_memory_size( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target, uint64_t& o_size )
{
- uint32_t l_sizes[PORTS_PER_MCS];
+ uint32_t l_sizes[MAX_DIMM_PER_PORT];
o_size = 0;
FAPI_TRY( mss::eff_dimm_size(i_target, &(l_sizes[0])) );
- for (size_t i = 0; i < PORTS_PER_MCS; ++i)
+ for (size_t i = 0; i < MAX_DIMM_PER_PORT; ++i)
{
o_size += l_sizes[i];
}
@@ -58,5 +61,34 @@ fapi_try_exit:
return fapi2::current_err;
}
+///
+/// @brief Return the total memory size behind an MBIST
+/// @param[in] i_target the MCBIST target
+/// @param[out] o_size the size of memory in GB behind the target
+/// @return FAPI2_RC_SUCCESS if ok
+///
+template<>
+fapi2::ReturnCode eff_memory_size( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target, uint64_t& o_size )
+{
+ o_size = 0;
+
+ for (const auto& mcs : mss::find_targets<fapi2::TARGET_TYPE_MCS>(i_target))
+ {
+ uint32_t l_sizes[PORTS_PER_MCS][MAX_DIMM_PER_PORT];
+ FAPI_TRY( mss::eff_dimm_size(mcs, &(l_sizes[0][0])) );
+
+ for (size_t i = 0; i < PORTS_PER_MCS; ++i)
+ {
+ for (size_t j = 0; j < MAX_DIMM_PER_PORT; ++j)
+ {
+ o_size += l_sizes[i][j];
+ }
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
}
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 ff9cd9f24..707e27dad 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
@@ -141,6 +141,24 @@ class address
o_end.iv_address.setBit<START, LEN>();
}
+
+ ///
+ /// @brief Get an end address for sim mode
+ /// @param[out] o_end representing an address to end at
+ /// @note this pointer is the start address
+ ///
+ inline void get_sim_end_address( address& o_end ) const
+ {
+ // This magic number represents a range of addresses which cover all
+ // cache lines the training algorithms touch. By effecting 0 - this end
+ // address you'll effect everything which has bad ECC in the sim.
+ constexpr uint64_t l_magic_sim_number = 0b1000000;
+
+ get_range<COL>(o_end);
+ o_end.set_column(l_magic_sim_number);
+ return;
+ }
+
///
/// @brief Get a range of addresses given a master rank
/// @param[in] i_start representing an address to start from
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 7971d2248..7f1a08b6b 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
@@ -213,17 +213,14 @@ fapi2::ReturnCode execute( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
bool l_poll_result = false;
poll_parameters l_poll_parameters;
- FAPI_TRY( i_program.clear_errors(i_target) );
+ FAPI_TRY( clear_errors(i_target) );
- // Slam the subtests in to the mcbist registers
- FAPI_TRY( load_mcbmr(i_target, i_program) );
+ // Slam the address generator config
+ FAPI_TRY( load_addr_gen(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) );
@@ -233,6 +230,16 @@ fapi2::ReturnCode execute( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
// Slam the control register down
FAPI_TRY( load_control( i_target, i_program) );
+ // Load the patterns and any associated bits for random, etc
+ FAPI_TRY( load_pattern( i_target, i_program) );
+
+ // Load the thresholds
+ FAPI_TRY( load_thresholds( i_target, i_program) );
+
+ // Slam the subtests in to the mcbist registers
+ // Always do this last so the action file triggers see the other bits set
+ FAPI_TRY( load_mcbmr(i_target, i_program) );
+
// Start the engine, and then poll for completion
FAPI_TRY(start_stop(i_target, mss::START));
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 ca5b75cfc..b135f16b0 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
@@ -36,6 +36,7 @@
#include <p9_mc_scom_addresses_fld.H>
#include <lib/utils/poll.H>
+#include <lib/eff_config/memory_size.H>
#include <lib/shared/mss_const.H>
#include <lib/utils/bit_count.H>
#include <lib/mcbist/patterns.H>
@@ -84,6 +85,7 @@ class mcbistTraits<fapi2::TARGET_TYPE_MCBIST>
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 LAST_ADDR_REG = MCBIST_MCBMCATQ;
static constexpr uint64_t MCBAMR0A0Q_REG = MCBIST_MCBAMR0A0Q;
static constexpr uint64_t MCBAMR1A0Q_REG = MCBIST_MCBAMR1A0Q;
@@ -117,6 +119,11 @@ class mcbistTraits<fapi2::TARGET_TYPE_MCBIST>
COMPL_3RD_CMD = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_COMPL_3RD_CMD,
ADDR_REV_MODE = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_ADDR_REV_MODE,
ADDR_RAND_MODE = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_ADDR_RAND_MODE,
+
+ // Goto subtests use the compl_1st - rand_mode to define the subtest to jump to
+ GOTO_SUBTEST = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_COMPL_1ST_CMD,
+ GOTO_SUBTEST_LEN = 5,
+
ECC_MODE = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_ECC_MODE,
DATA_MODE = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_DATA_MODE,
DATA_MODE_LEN = MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_DATA_MODE_LEN,
@@ -135,6 +142,7 @@ class mcbistTraits<fapi2::TARGET_TYPE_MCBIST>
MCBIST_START = MCBIST_MCB_CNTLQ_START,
MCBIST_STOP = MCBIST_MCB_CNTLQ_STOP,
+ MCBIST_RESUME = MCBIST_MCB_CNTLQ_RESUME_FROM_PAUSE,
MCBIST_IN_PROGRESS = MCBIST_MCB_CNTLSTATQ_IP,
MCBIST_DONE = MCBIST_MCB_CNTLSTATQ_DONE,
@@ -266,6 +274,39 @@ class subtest_t
return;
}
+ ///
+ /// @brief Get the port from this subtest
+ /// @note The port number is relative to the MCBIST
+ /// @return the port of the subtest
+ ///
+ inline uint64_t get_port()
+ {
+ uint64_t l_port = 0;
+ constexpr uint64_t l_len = (TT::COMPL_2ND_CMD - TT::COMPL_1ST_CMD) + 1;
+ iv_mcbmr.template extractToRight<TT::COMPL_1ST_CMD, l_len>(l_port);
+ return l_port;
+ }
+
+ ///
+ /// @brief Get the DIMM from this subtest
+ /// @return the DIMM this subtest has been configured for
+ ///
+ inline uint64_t get_dimm()
+ {
+ return iv_mcbmr.template getBit<TT::COMPL_3RD_CMD>() ? 1 : 0;
+ }
+
+ ///
+ /// @brief Add the subtest to go to
+ /// @param[in] the subtest to jump to
+ /// @return void
+ ///
+ inline void change_goto_subtest( const uint64_t i_jmp_to )
+ {
+ iv_mcbmr.template insertFromRight<TT::GOTO_SUBTEST, TT::GOTO_SUBTEST_LEN>(i_jmp_to);
+ FAPI_INF("changing subtest to jump to %d (0x%02x)", i_jmp_to, iv_mcbmr);
+ return;
+ }
///
/// @brief Generate addresses in reverse order
@@ -342,8 +383,9 @@ class subtest_t
inline void change_addr_sel( const uint16_t i_index )
{
// Roll the index around - tidy support for an index which is out of range.
- static const uint16_t MAX_ADDRESS_START_END_REGISTERS = 3 + 1;
+ constexpr uint16_t MAX_ADDRESS_START_END_REGISTERS = 3 + 1;
iv_mcbmr.template insertFromRight<TT::ADDR_SEL, TT::ADDR_SEL_LEN>(i_index % MAX_ADDRESS_START_END_REGISTERS);
+ FAPI_INF("changed address select to index %d (0x%x)", i_index, iv_mcbmr);
return;
}
@@ -398,6 +440,39 @@ inline subtest_t<T> write_subtest()
}
///
+/// @brief Return a scrub subtest - configured simply
+/// @tparam T the fapi2::TargetType - derived
+/// @tparam TT the mcbistTraits associated with T - derived
+/// @return mss::mcbist::subtest_t
+/// @note Turns on ECC mode for the returned subtest - caller can turn it off
+/// @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> scrub_subtest()
+{
+ // Starts life full of 0's
+ subtest_t<T> l_subtest;
+
+ // 0:3 = 1001 - we want subtest type to be a Scrub
+ l_subtest.iv_mcbmr.template insertFromRight<TT::OP_TYPE, TT::OP_TYPE_LEN>(op_type::SCRUB_RRWR);
+
+ // - Not a special subtest, so no other configs associated
+ // 4 = 0 - we don't want to complement data for our Writes
+ // 5:6 = 00 - don't know whether we complement 2nd and 3rd subcommand, caller to fix
+ // 7 = 0 - forward address generation
+ // 8 = 0 - non random address generation
+ // - Don't need to set up anything for LFSRs
+ // 9:11 = 000 - Fixed data mode
+
+ // 14:15 = 0 address select config registers 0
+
+ // By default we want to turn on ECC. Caller can turn it off.
+ l_subtest.change_ecc_mode(mss::ON);
+
+ return l_subtest;
+}
+
+///
/// @brief Return a read subtest - configured simply
/// @tparam T the fapi2::TargetType - derived
/// @tparam TT the mcbistTraits associated with T - derived
@@ -431,6 +506,29 @@ inline subtest_t<T> read_subtest()
}
///
+/// @brief Return a goto subtest - configured simply
+/// @tparam T the fapi2::TargetType - derived
+/// @tparam TT the mcbistTraits associated with T - derived
+/// @param[in] the subtest we should go to
+/// @return mss::mcbist::subtest_t
+/// @note Turns on ECC mode for the returned subtest - caller can turn it off
+/// @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> goto_subtest( const uint64_t i_jump_to )
+{
+ // Starts life full of 0's
+ subtest_t<T> l_subtest;
+
+ // 0:3 = 0111 - we want subtest type to be a Goto
+ l_subtest.iv_mcbmr.template insertFromRight<TT::OP_TYPE, TT::OP_TYPE_LEN>(op_type::GOTO_SUBTEST_N);
+
+ // Plug in the subtest the user passed in
+ l_subtest.change_goto_subtest(i_jump_to);
+ return l_subtest;
+}
+
+///
/// @brief Return an init subtest - configured simply
/// @tparam T the fapi2::TargetType - derived
/// @tparam TT the mcbistTraits associated with T - derived
@@ -501,7 +599,8 @@ class program
iv_addr_map3(0),
iv_config(0),
iv_control(0),
- iv_async(false)
+ iv_async(false),
+ iv_pattern(PATTERN_0)
{
// Enable the maintenance mode addressing
change_maint_address_mode(mss::ON);
@@ -512,6 +611,10 @@ class program
// Turn off counting mode for all address configs
iv_addr_gen.insertFromRight<TT::ADDR_COUNTER_MODE, TT::ADDR_COUNTER_MODE_LEN>(0b0000);
+
+ // By default if there's an error, we stop after the errored address
+ iv_config.insertFromRight<TT::CFG_PAUSE_ON_ERROR_MODE, TT::CFG_PAUSE_ON_ERROR_MODE_LEN>(
+ stop_conditions::STOP_AFTER_ADDRESS);
}
///
@@ -526,19 +629,141 @@ class program
}
///
+ /// @brief Change the mcbist thresholds
+ /// @param[in] i_thresholds the new thresholds
+ /// @return void
+ ///
+ inline void change_thresholds( const thresholds& i_thresholds )
+ {
+ iv_thresholds = i_thresholds;
+ return;
+ }
+
+ ///
+ /// @brief Change MCBIST Speed
+ /// @param[in] i_target the target behind which the memory sits
+ /// @param[in] i_speed the speed eunmeration
+ /// @return FAPI2_RC_SUCCSS iff ok
+ ///
+ inline fapi2::ReturnCode change_speed( const fapi2::Target<T>& i_target, const speed i_speed )
+ {
+ switch (i_speed)
+ {
+ case speed::LUDICROUS:
+ change_min_cmd_gap(0);
+ change_min_gap_timebase(mss::OFF);
+ return fapi2::FAPI2_RC_SUCCESS;
+ break;
+
+ case speed::BG_SCRUB:
+ {
+ uint64_t l_freq = 0;
+ uint64_t l_size = 0;
+ uint64_t l_min_cmd_gap = 0;
+
+ constexpr uint64_t l_seconds = SEC_IN_HOUR * BG_SCRUB_IN_HOURS;
+
+ FAPI_TRY( mss::freq(i_target, l_freq) );
+ FAPI_TRY( mss::eff_memory_size(i_target, l_size) );
+
+ // MIN CMD GAP = TOTAL CYCLES / TOTAL ADDRESSES
+ // TOTAL CYCLES = 12 hours x 60 min/hr x 60 sec/min x [DRAM freq] cycles/sec x
+ // 1/2 (MEM logic runs half DRAM freq)
+ // TOTAL ADDRESSES = sum over all dimms of ( [DIMM CAPACITY]/128B )
+ l_min_cmd_gap = ((l_seconds * (l_freq * T_PER_MT)) / 2) / ((l_size * BYTES_PER_GB) / 128);
+
+ FAPI_INF("setting bg scrub speed: %dMT/s, memory: %dGB, duration: %ds, gap: %d",
+ l_freq, l_size, l_seconds, l_min_cmd_gap);
+
+ if (CMD_TIMEBASE < l_min_cmd_gap)
+ {
+ change_min_cmd_gap(l_min_cmd_gap / CMD_TIMEBASE);
+ change_min_gap_timebase(mss::ON);
+ }
+ else
+ {
+ change_min_cmd_gap(l_min_cmd_gap);
+ change_min_gap_timebase(mss::OFF);
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+ }
+ break;
+
+ // Otherwise it's SAME_SPEED or something else in which case we do nothing
+ default:
+ break;
+ };
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+
+ ///
/// @brief Change MCBIST Stop conditions
/// @param[in] i_stops the stop conditions
+ /// @param[in] i_only_if_error forces the stop conditions to only be in effect if there is an error
+ /// if there is not an error the subtest continues. Defaults to mss::NO, meaning these are forced 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
+ /// @note By default the MCBIST is programmed to always stop after an errored address. This API
+ /// allows the caller to force a stop at a boundary or to force no stopping on errors
///
- inline void change_stops( const stop_conditions i_stops )
+ inline void change_stops( const stop_conditions i_stops, const bool i_only_if_error = mss::NO )
{
- if (i_stops != DONT_CHANGE)
+ // If there's no change, just get outta here
+ if (i_stops == DONT_CHANGE)
+ {
+ goto fapi_try_exit;
+ }
+
+ // If these conditions only take effect when there's an error, set that up in the ERROR_MODE field
+ // NO_STOP_ON_ERROR is specific to the ERROR MODE field, so set that up here too
+ if ((i_only_if_error == mss::YES) || (i_stops == NO_STOP_ON_ERROR))
{
iv_config.insertFromRight<TT::CFG_PAUSE_ON_ERROR_MODE, TT::CFG_PAUSE_ON_ERROR_MODE_LEN>(i_stops);
+ goto fapi_try_exit;
}
+ // Otherwise, these are forced conditions and they need to be put in their specific fields
+ switch(i_stops)
+ {
+ case STOP_AFTER_ADDRESS:
+ iv_config.setBit<TT::MCBIST_CFG_FORCE_PAUSE_AFTER_ADDR>();
+ break;
+
+ case STOP_AFTER_RANK:
+ iv_config.setBit<TT::MCBIST_CFG_PAUSE_AFTER_RANK>();
+ break;
+
+ case STOP_AFTER_SUBTEST:
+ iv_config.setBit<TT::MCBIST_CFG_FORCE_PAUSE_AFTER_SUBTEST>();
+ break;
+
+ // Same as don't-change
+ default:
+ break;
+ };
+
+ fapi_try_exit:
FAPI_INF("load MCBIST stops: 0x%016lx (0x%016lx)", i_stops, iv_config);
+
+ return;
+ }
+
+ ///
+ /// @brief Change MCBIST End boundaries
+ /// @param[in] i_end the end boundary
+ /// @return FAPI2_RC_SUCCSS iff ok
+ /// @note this really is just deciding if the stop conditions are master or slave rank boundaries
+ ///
+ inline void change_end_boundary( const end_boundary i_end )
+ {
+ // This is a little funny ... the hardware has one bit representing 'master' and 'slave'
+ // So, NONE really represents a stop condition. We probably should combine the two, but the
+ // API doc from PRD asks for them separate.
+ uint64_t l_detect_slave = i_end == end_boundary::SLAVE_RANK ? 1 : 0;
+ FAPI_INF("load MCBIST end boundaries: detect slave? %s", (l_detect_slave == 1 ? "yes" : "no") );
+ iv_addr_gen.writeBit<TT::MAINT_DETECT_SRANK_BOUNDARIES>(l_detect_slave);
}
///
@@ -849,23 +1074,29 @@ class program
}
///
- /// @brief Clear mcbist errors
- /// @param[in] i_target fapi2::Target<T> of the MCBIST
- /// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
+ /// @brief Store off the pattern index. We'll use this to write the patterns when we load the program
+ /// @param[in] i_index an index such as mss::mcbist::PATTERN_0
+ /// @return fapi2::ReturnCode checks for bad pattern index
+ /// @warning if you give a pattern index which does not exist your pattern will not change.
+ /// @note patterns default to PATTERN_0
///
- inline fapi2::ReturnCode clear_errors( const fapi2::Target<T> i_target ) const
+ inline fapi2::ReturnCode change_pattern( const uint64_t i_pattern )
{
- // 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_INF("change MCBIST pattern index %d", i_pattern);
+
+ // Sanity check the pattern since they're just numbers.
+ FAPI_ASSERT( i_pattern <= mcbist::NO_PATTERN,
+ fapi2::MSS_MEMDIAGS_INVALID_PATTERN_INDEX().set_INDEX(i_pattern),
+ "Attempting to change a pattern which does not exist %d", i_pattern );
+
+ iv_pattern = i_pattern;
+
+ return fapi2::FAPI2_RC_SUCCESS;
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
// (16 bits/test, 4 x 16 == 64, 4x8 = 32 subtests)
@@ -901,6 +1132,12 @@ class program
// True iff we want to run in asynchronous mode
bool iv_async;
+
+ // The pattern for the pattern generator
+ uint64_t iv_pattern;
+
+ // The error thresholds for the program
+ thresholds iv_thresholds;
};
///
@@ -1073,6 +1310,25 @@ fapi_try_exit:
}
///
+/// @brief Resume the MCBIST engine
+/// @tparam T the fapi2::TargetType - derived
+/// @tparam TT the mcbistTraits associated with T - derived
+/// @param[in] i_target the target to effect
+/// @return fapi2::ReturnCode, FAPI2_RC_SUCCESS iff OK
+///
+template< fapi2::TargetType T, typename TT = mcbistTraits<T> >
+inline fapi2::ReturnCode resume( const fapi2::Target<T>& i_target )
+{
+ fapi2::buffer<uint64_t> l_buf;
+
+ FAPI_TRY( mss::getScom(i_target, TT::CNTLQ_REG, l_buf) );
+ FAPI_TRY( mss::putScom(i_target, TT::CNTLQ_REG, l_buf.setBit<TT::MCBIST_RESUME>()) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
/// @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
@@ -1159,12 +1415,34 @@ inline fapi2::ReturnCode load_mcbparm( const fapi2::Target<T>& i_target, const m
}
///
+/// @brief Clear mcbist errors
+/// @tparam T, the fapi2::TargetType - derived
+/// @tparam TT, the mcbistTraits associated with T - derived
+/// @param[in] i_target fapi2::Target<T> of the MCBIST
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
+///
+template< fapi2::TargetType T, typename TT = mcbistTraits<T> >
+inline fapi2::ReturnCode clear_errors( const fapi2::Target<T> i_target )
+{
+ // 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;
+}
+
+
+///
/// @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
+/// @note this overload disappears when we have real patterns.
/// @return FAPI2_RC_SUCCSS iff ok
///
template< fapi2::TargetType T, typename TT = mcbistTraits<T> >
@@ -1172,11 +1450,9 @@ inline fapi2::ReturnCode load_pattern( const fapi2::Target<T>& i_target, const p
{
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() );
+ // TODO RTC:155561 Add random pattern support.
+ // TK: algorithm for patterns which include ECC bits in them
// 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)
@@ -1198,33 +1474,32 @@ fapi_try_exit:
/// @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
+/// @param[in] i_index the pattern index
/// @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 )
+inline fapi2::ReturnCode load_pattern( const fapi2::Target<T>& i_target, uint64_t i_pattern )
{
- if (NO_PATTERN != i_index)
+ if (NO_PATTERN != i_pattern)
{
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 );
+ // Belt-and-suspenders FAPI_ASSERT as the sim-only uses this API directly.
+ FAPI_ASSERT( i_pattern <= mcbist::LAST_PATTERN,
+ fapi2::MSS_MEMDIAGS_INVALID_PATTERN_INDEX().set_INDEX(i_pattern),
+ "Attempting to load a pattern which does not exist %d", i_pattern );
// 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)
+ if ((i_pattern % 2) != 0)
{
l_invert = true;
- i_index -= 1;
+ i_pattern -= 1;
}
- return load_pattern(i_target, patterns[i_index / 2], l_invert);
+ return load_pattern(i_target, patterns[i_pattern / 2], l_invert);
}
return fapi2::FAPI2_RC_SUCCESS;
@@ -1234,6 +1509,20 @@ fapi_try_exit:
}
///
+/// @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_program the mcbist::program
+/// @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 mcbist::program<T>& i_program )
+{
+ return load_pattern(i_target, i_program.iv_pattern);
+}
+
+///
/// @brief Load MCBIST Threshold Register
/// @tparam T, the fapi2::TargetType - derived
/// @tparam TT, the mcbistTraits associated with T - derived
@@ -1248,6 +1537,20 @@ inline fapi2::ReturnCode load_thresholds( const fapi2::Target<T>& i_target, cons
return mss::putScom(i_target, TT::THRESHOLD_REG, i_thresholds);
}
+///
+/// @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_program the program containing 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 mcbist::program<T>& i_program )
+{
+ return load_thresholds(i_target, i_program.iv_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
index 4318e111c..f3e4a3908 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/memdiags.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/memdiags.C
@@ -38,11 +38,14 @@
#include <lib/mcbist/settings.H>
#include <lib/mcbist/sim.H>
+#include <lib/utils/poll.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;
+using fapi2::FAPI2_RC_INVALID_PARAMETER;
namespace memdiags
{
@@ -55,19 +58,54 @@ namespace memdiags
template<>
fapi2::ReturnCode stop( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
{
+ // Too long, make shorter
+ using TT = mss::mcbist::mcbistTraits<TARGET_TYPE_MCBIST>;
+
+ // Poll parameters are defined as TK so that we wait a nice time for operations
+ // For now use the defaults
+ mss::poll_parameters l_poll_parameters;
+ fapi2::buffer<uint64_t> l_status;
+ fapi2::buffer<uint64_t> l_last_address;
+ bool l_poll_result = false;
+
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);
+ FAPI_TRY( mss::mcbist::start_stop(i_target, mss::STOP) );
+
+ // Poll waiting for the engine to stop
+ 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 not in-progress, 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>() == false;
+ });
+
+ // Pass or fail output the current address. This is useful for debugging when we can get it.
+ // It's in the register FFDC for memdiags so we don't need it below
+ FAPI_TRY( mss::getScom(i_target, TT::LAST_ADDR_REG, l_last_address) );
+ FAPI_INF("MCBIST last address (during stop): 0x%016lx", l_last_address);
+
+ // So we've either stopped or we timed out
+ FAPI_ASSERT( l_poll_result == true,
+ fapi2::MSS_MEMDIAGS_MCBIST_FAILED_TO_STOP().set_TARGET(i_target),
+ "The MCBIST engine failed to stop its program" );
+
+fapi_try_exit:
+ return fapi2::current_err;
+
}
///
-/// @brief memdiags::base initializer
+/// @brief memdiags init helper
+/// Initializes common sections. Broken out rather than the base class ctor to enable checking return codes
+/// in subclassed constructors more easily.
/// @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()
+fapi2::ReturnCode operation<TARGET_TYPE_MCBIST>::base_init()
{
FAPI_INF("memdiags base init");
@@ -77,23 +115,21 @@ fapi2::ReturnCode memdiags::base<TARGET_TYPE_MCBIST>::init()
// 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) );
+ FAPI_TRY( iv_program.change_pattern(iv_const.iv_pattern) );
// Load stop conditions
iv_program.change_stops(iv_const.iv_stop);
+ // Load end boundaries
+ iv_program.change_end_boundary(iv_const.iv_end_boundary);
+
// Load thresholds
- FAPI_TRY( mss::mcbist::load_thresholds(iv_target, iv_const.iv_thresholds) );
+ iv_program.change_thresholds(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);
- }
+ // Setup the requested speed
+ FAPI_TRY( iv_program.change_speed(iv_target, iv_const.iv_speed) );
// 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
@@ -107,17 +143,15 @@ fapi_try_exit:
}
///
-/// @brief Super Fast Base initializer
-/// @note Uses broadcast mode if possible
+/// @brief memdiags multi-port init helper
+/// Initializes common sections. Broken out rather than the base class ctor to enable checking return codes
+/// in subclassed constructors more easily.
/// @return FAPI2_RC_SUCCESS iff everything ok
///
template<>
-fapi2::ReturnCode memdiags::sf_operation<TARGET_TYPE_MCBIST>::init()
+fapi2::ReturnCode operation<TARGET_TYPE_MCBIST>::multi_port_init()
{
- FAPI_INF("superfast init");
-
- // Initialize the base class
- FAPI_TRY( base::init() );
+ FAPI_INF("multi-port init");
// Deterimine which ports are functional and whether we can broadcast to them
// TK on the broadcast BRS
@@ -129,7 +163,7 @@ fapi2::ReturnCode memdiags::sf_operation<TARGET_TYPE_MCBIST>::init()
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;
+ auto l_subtest = iv_subtest;
l_subtest.enable_port(mss::relative_pos<TARGET_TYPE_MCBIST>(p));
l_subtest.enable_dimm(mss::index(d));
@@ -138,26 +172,36 @@ fapi2::ReturnCode memdiags::sf_operation<TARGET_TYPE_MCBIST>::init()
}
}
+ // A 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<mss::mcbist::address::DIMM>(iv_const.iv_end_address);
+ }
+
+ // Configure the address range
+ FAPI_TRY( mss::mcbist::config_address_range0(iv_target, iv_const.iv_start_address, iv_const.iv_end_address) );
+
+ // Initialize the common sections
+ FAPI_TRY( base_init() );
+
fapi_try_exit:
return fapi2::current_err;
}
///
-/// @brief Super Fast Read (End of Port) initializer
-/// @note Uses broadcast mode if possible
+/// @brief Single port initializer
+/// Initializes common sections. Broken out rather than the base class ctor to enable checking return codes
+/// in subclassed constructors more easily.
/// @return FAPI2_RC_SUCCESS iff everything ok
///
template<>
-fapi2::ReturnCode memdiags::sf_read_operation<TARGET_TYPE_MCBIST>::end_of_port_init()
+fapi2::ReturnCode operation<TARGET_TYPE_MCBIST>::single_port_init()
{
- FAPI_INF("superfast read (end of port) init");
+ FAPI_INF("single 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()
@@ -166,10 +210,6 @@ fapi2::ReturnCode memdiags::sf_read_operation<TARGET_TYPE_MCBIST>::end_of_port_i
.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
{
@@ -178,16 +218,170 @@ fapi2::ReturnCode memdiags::sf_read_operation<TARGET_TYPE_MCBIST>::end_of_port_i
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);
+ FAPI_INF("adding subtest 0x%x for port %d, DIMM %d", l_subtest, l_relative_port_number, l_dimm_number);
}
- return FAPI2_RC_SUCCESS;
+ // The address should have the port and DIMM noted in it. All we need to do is calculate the
+ // remainder of the address, assuming the caller didn't setup an end address already.
+ // *INDENT-OFF*
+ if (iv_const.iv_end_address == 0)
+ {
+ iv_is_sim ?
+ iv_const.iv_start_address.get_sim_end_address(iv_const.iv_end_address) :
+ iv_const.iv_start_address.get_range<mss::mcbist::address::DIMM>(iv_const.iv_end_address);
+ }
+ // *INDENT-ON*
+
+ // Configure the address range
+ FAPI_TRY( mss::mcbist::config_address_range0(iv_target, iv_const.iv_start_address, iv_const.iv_end_address) );
+
+ // Initialize the common sections
+ FAPI_TRY( base_init() );
fapi_try_exit:
return fapi2::current_err;
}
///
+/// @brief memdiags::continuous_scrub_operation constructor
+/// @param[in] i_target the target of the mcbist engine
+/// @param[in] i_const the contraints of the operation
+/// @param[out] o_rc the fapi2::ReturnCode of the intialization process
+///
+template<>
+continuous_scrub_operation<TARGET_TYPE_MCBIST>::continuous_scrub_operation(
+ const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
+ const constraints i_const,
+ fapi2::ReturnCode& o_rc ):
+ operation<TARGET_TYPE_MCBIST>(i_target, mss::mcbist::scrub_subtest<TARGET_TYPE_MCBIST>(), i_const)
+{
+ mss::mcbist::address l_generic_start_address;
+ mss::mcbist::address l_generic_end_address;
+
+ FAPI_INF("setting up for continuous scrub");
+
+ // Scrub operations run 128B
+ iv_program.change_len64(mss::OFF);
+
+ // We build a little program here which allows us to restart the loop in the event of a pause.
+ // So we need to craft some of the address ranges and some of the subtests by hand.
+
+ // Setup address config 0 to cover all the addresses for a port/dimm.
+ // We leverage the MCBIST's ability to skip invalid addresses, and just setup
+ // If we're running in the simulator, we want to only touch the addresses which training touched
+ // *INDENT-OFF*
+ iv_is_sim ?
+ l_generic_start_address.get_sim_end_address(l_generic_end_address) :
+ l_generic_start_address.get_range<mss::mcbist::address::DIMM>(l_generic_end_address);
+ // *INDENT-ON*
+
+ FAPI_TRY( mss::mcbist::config_address_range0(i_target, l_generic_start_address, l_generic_end_address) );
+
+ // We push on a fake subtest 0 and subtest 1. We fix them up after we fill in the
+ // rest of the subtests.
+ iv_program.iv_subtests.push_back(iv_subtest);
+ iv_program.iv_subtests.push_back(iv_subtest);
+
+ // a generic 0 - DIMM address range.
+ //
+ // Subtests 2-9: One subtest per port/dimm each covering the whole range of that
+ // port/dimm. scrub_subtests by default are using address config 0, so each of
+ // these get their full address complement.
+ for (const auto& p : iv_target.template getChildren<TARGET_TYPE_MCA>())
+ {
+ for (const auto& d : p.template getChildren<TARGET_TYPE_DIMM>())
+ {
+ // Don't destroy the subtest passed in, copy it
+ auto 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 scrub subtest for %s (dimm %d) (0x%x)", mss::c_str(d), mss::index(d), l_subtest);
+ }
+ }
+
+ //
+ // Subtest 10: goto subtest 2. This causes us to loop back to the first port/dimm and go thru them all
+ // This subtest will be marked the last when the MCBMR registers are filled in.
+ //
+ iv_program.iv_subtests.push_back(mss::mcbist::goto_subtest<TARGET_TYPE_MCBIST>(2));
+ FAPI_INF("last goto subtest (10) is going to subtest 2 (0x%x)", iv_program.iv_subtests[2]);
+
+ // Ok, now we can go back in to fill in the first two subtests.
+
+ {
+ auto l_subtest = iv_subtest;
+ auto l_port = iv_const.iv_start_address.get_port();
+ auto l_dimm = iv_const.iv_start_address.get_dimm();
+ size_t l_index = 2;
+
+ // By default if we don't find our port/dimm in the subtests, we just go back to the beginning.
+ uint64_t l_goto_subtest = 2;
+
+ //
+ // subtest 0
+ //
+
+ // load the start address given and calculate the end address. Stick this into address config 1
+ // We don't need to account for the simulator here as the caller can do that when they setup the
+ // start address.
+ // *INDENT-OFF*
+ iv_is_sim ?
+ iv_const.iv_start_address.get_sim_end_address(iv_const.iv_end_address) :
+ iv_const.iv_start_address.get_range<mss::mcbist::address::DIMM>(iv_const.iv_end_address);
+ // *INDENT-ON*
+
+ FAPI_TRY( mss::mcbist::config_address_range1(i_target, iv_const.iv_start_address, iv_const.iv_end_address) );
+
+ // We need to use this address range. We know it's ok to write to element 0 as we pushed it on above
+ l_subtest.change_addr_sel(1);
+ l_subtest.enable_port(l_port);
+ l_subtest.enable_dimm(l_dimm);
+
+ iv_program.iv_subtests[0] = l_subtest;
+ FAPI_INF("adding scrub subtest 0 for port %d dimm %d (0x%02x)", l_port, l_dimm, l_subtest);
+
+ //
+ // subtest 1
+ //
+
+ // From the port/dimm specified in the start address, we know what subtest should execute next. The idea
+ // being that this 0'th subtest is a mechanism to allow the caller to start a scrub 'in the middle' and
+ // jump to the next port/dimm which would have been scrubbed. The hard part is that we don't know where
+ // in the subtest vector the 'next' port/dimm are placed. So we look for our port/dimm (skipping subtest 0
+ // since we know that's us and skipping subtest 1 since it isn't there yet.)
+ for (; l_index < iv_program.iv_subtests.size(); ++l_index)
+ {
+ auto l_my_dimm = iv_program.iv_subtests[l_index].get_dimm();
+ auto l_my_port = iv_program.iv_subtests[l_index].get_port();
+
+ if ((l_dimm == l_my_dimm) && (l_port == l_my_port))
+ {
+ l_goto_subtest = l_index + 1;
+ break;
+ }
+ }
+
+ // Since we set l_goto_subtest up with a meaningful default, we can just make a subtest with the
+ // l_goto_subtest subtest specified and pop that in to index 1.
+ FAPI_INF("adding scrub subtest 1 to goto subtest %d (port %d, dimm %d, test 0x%02x)", l_goto_subtest,
+ iv_program.iv_subtests[l_goto_subtest].get_port(),
+ iv_program.iv_subtests[l_goto_subtest].get_dimm(),
+ iv_program.iv_subtests[l_goto_subtest] );
+
+ iv_program.iv_subtests[1] = mss::mcbist::goto_subtest<TARGET_TYPE_MCBIST>(l_goto_subtest);
+ }
+
+ // Initialize the common sections
+ FAPI_TRY( base_init() );
+
+fapi_try_exit:
+ o_rc = fapi2::current_err;
+ return;
+}
+
+///
/// @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
@@ -201,8 +395,7 @@ fapi2::ReturnCode sf_init( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
{
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;
+ uint8_t is_sim = false;
FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<TARGET_TYPE_SYSTEM>(), is_sim) );
if (is_sim)
@@ -216,7 +409,8 @@ fapi2::ReturnCode sf_init( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
else
{
fapi2::ReturnCode l_rc;
- sf_init_operation<TARGET_TYPE_MCBIST> l_init_op(i_target, i_pattern, l_rc);
+ constraints l_const(i_pattern);
+ sf_init_operation<TARGET_TYPE_MCBIST> l_init_op(i_target, l_const, l_rc);
FAPI_ASSERT( l_rc == FAPI2_RC_SUCCESS,
fapi2::MSS_MEMDIAGS_SUPERFAST_INIT_FAILED_TO_INIT().set_TARGET(i_target),
@@ -240,13 +434,14 @@ fapi_try_exit:
///
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 stop_conditions i_stop,
+ const 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);
+ constraints l_const(i_stop, i_thresholds);
+ sf_read_operation<TARGET_TYPE_MCBIST> l_read_op(i_target, l_const, l_rc);
FAPI_ASSERT( l_rc == FAPI2_RC_SUCCESS,
fapi2::MSS_MEMDIAGS_SUPERFAST_READ_FAILED_TO_INIT().set_TARGET(i_target),
@@ -269,14 +464,15 @@ fapi_try_exit:
///
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 )
+ const stop_conditions i_stop,
+ const thresholds& i_thresholds,
+ const mss::mcbist::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);
+ constraints l_const(i_stop, i_thresholds, i_address);
+ sf_read_eop_operation<TARGET_TYPE_MCBIST> l_read_op(i_target, l_const, l_rc);
FAPI_ASSERT( l_rc == FAPI2_RC_SUCCESS,
fapi2::MSS_MEMDIAGS_SUPERFAST_READ_FAILED_TO_INIT().set_TARGET(i_target),
@@ -289,71 +485,210 @@ fapi_try_exit:
}
///
-/// @brief Scrub - scrub all memory behind the target
+/// @brief Scrub - continuous 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 )
+fapi2::ReturnCode background_scrub( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
+ const stop_conditions i_stop,
+ const thresholds& i_thresholds,
+ const speed i_speed,
+ const mss::mcbist::address& i_address )
{
- // TK implementation (because Glancy couldn't figure that out <grin>)
- FAPI_INF("scrub");
- return FAPI2_RC_SUCCESS;
+ FAPI_INF("continuous (background) scrub");
+
+ fapi2::ReturnCode l_rc;
+ constraints l_const(i_stop, i_thresholds, i_speed, end_boundary::NONE, i_address);
+ continuous_scrub_operation<TARGET_TYPE_MCBIST> l_op(i_target, l_const, l_rc);
+
+ FAPI_ASSERT( l_rc == FAPI2_RC_SUCCESS,
+ fapi2::MSS_MEMDIAGS_CONTINUOUS_SCRUB_FAILED_TO_INIT().set_TARGET(i_target),
+ "Unable to initialize the MCBIST engine for a continuous scrub %s", mss::c_str(i_target) );
+
+ return l_op.execute();
+
+fapi_try_exit:
+ return fapi2::current_err;
}
///
-/// @brief Continue current command on next address
+/// @brief Scrub - targeted 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
+/// @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 targeted_scrub( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
+ const stop_conditions i_stop,
+ const thresholds& i_thresholds,
+ const speed i_speed,
+ const mss::mcbist::address& i_address,
+ const end_boundary i_end )
+{
+ FAPI_INF("targeted scrub");
+
+ if (i_stop == memdiags::stop_conditions::DONT_STOP)
+ {
+ FAPI_ERR("targeted scrub must have stop conditions");
+ return FAPI2_RC_INVALID_PARAMETER;
+ }
+
+ fapi2::ReturnCode l_rc;
+ constraints l_const(i_stop, i_thresholds, i_speed, i_end, i_address);
+ targeted_scrub_operation<TARGET_TYPE_MCBIST> l_op(i_target, l_const, l_rc);
+
+ FAPI_ASSERT( l_rc == FAPI2_RC_SUCCESS,
+ fapi2::MSS_MEMDIAGS_TARGETED_SCRUB_FAILED_TO_INIT().set_TARGET(i_target),
+ "Unable to initialize the MCBIST engine for a targeted scrub %s", mss::c_str(i_target) );
+
+ return l_op.execute();
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @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
+/// @note overloaded as there's no 'invalid' state for thresholds.
///
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 )
+ const thresholds& i_thresholds,
+ const end_boundary i_end,
+ const stop_conditions i_stop,
+ const speed i_speed )
{
- // TK implementation (because Glancy couldn't figure that out <grin>)
+ // Too long, make shorter
+ using TT = mss::mcbist::mcbistTraits<TARGET_TYPE_MCBIST>;
+
+ // We can use a local mcbist::program to help with the bit processing, and then write just the registers we touch.
+ mss::mcbist::program<TARGET_TYPE_MCBIST> l_program;
+ fapi2::buffer<uint64_t> l_status;
+
FAPI_INF("continue_cmd");
- return FAPI2_RC_SUCCESS;
+
+ // TODO RTC:155518 Check for stop or in progress before allowing continue. Not critical
+ // as the caller should know and can check the in-progress bit in the event they don't
+
+ // This is OK as because the i_end is optional, for the caller to specify a
+ // stop condition other than DONT_CHANGE, they'd have to specify the end too
+ // It doean't make any sense to have a 'don't stop' in the end boundaries as
+ // you need to tell the stop conditions that.
+ if (i_stop != stop_conditions::DONT_CHANGE)
+ {
+ // Before we go too far, check to see if we're already stopped at the boundary we are asking to stop at
+ bool l_stopped_at_boundary = false;
+ uint64_t l_error_mode = 0;
+
+ FAPI_TRY( mss::getScom(i_target, MCBIST_MCBCFGQ, l_program.iv_config) );
+ l_program.iv_config.extractToRight<TT::CFG_PAUSE_ON_ERROR_MODE, TT::CFG_PAUSE_ON_ERROR_MODE_LEN>(l_error_mode);
+
+ switch (i_stop)
+ {
+ case stop_conditions::STOP_AFTER_ADDRESS:
+ l_stopped_at_boundary =
+ l_program.iv_config.getBit<TT::MCBIST_CFG_FORCE_PAUSE_AFTER_ADDR>() ||
+ l_error_mode == stop_conditions::STOP_AFTER_ADDRESS;
+ break;
+
+ case stop_conditions::STOP_AFTER_RANK:
+ l_stopped_at_boundary =
+ l_program.iv_config.getBit<TT::MCBIST_CFG_PAUSE_AFTER_RANK>() ||
+ l_error_mode == stop_conditions::STOP_AFTER_RANK;
+ break;
+
+ case stop_conditions::STOP_AFTER_SUBTEST:
+ l_stopped_at_boundary =
+ l_program.iv_config.getBit<TT::MCBIST_CFG_FORCE_PAUSE_AFTER_SUBTEST>() ||
+ l_error_mode == stop_conditions::STOP_AFTER_SUBTEST;
+ break;
+
+ // By default we're not stopped at a boundary we're going to continue from
+ default:
+ break;
+ };
+
+ FAPI_ASSERT( l_stopped_at_boundary == false,
+ fapi2::MSS_MEMDIAGS_ALREADY_AT_BOUNDARY().set_TARGET(i_target).set_BOUNDARY(i_stop),
+ "Asked to stop at a boundary, but we're already there" );
+
+ // Ok, if we're here either we need to change the stop and boundary conditions.
+ // Read-modify-write the fields in the program.
+ FAPI_TRY( mss::getScom(i_target, TT::MCBAGRAQ_REG, l_program.iv_addr_gen) );
+
+ l_program.change_stops(i_stop);
+
+ l_program.change_end_boundary(i_end);
+
+ FAPI_TRY( mss::mcbist::load_addr_gen(i_target, l_program) );
+
+ FAPI_TRY( mss::mcbist::load_config(i_target, l_program) );
+ }
+
+ // Thresholds
+ FAPI_TRY( mss::mcbist::load_thresholds(i_target, i_thresholds) );
+
+ // Setup speed
+ FAPI_TRY( l_program.change_speed(i_target, i_speed) );
+
+ // Clear the program complete FIR
+ FAPI_TRY( mss::putScom(i_target, MCBIST_MCBISTFIRQ_AND,
+ fapi2::buffer<uint64_t>().setBit<MCBIST_MCBISTFIRQ_MCBIST_PROGRAM_COMPLETE>().invert()) );
+
+ // Tickle the resume from pause
+ FAPI_TRY( mss::mcbist::resume(i_target) );
+
+fapi_try_exit:
+ return fapi2::current_err;
}
///
-/// @brief Continue current command on next address - change thresholds
+/// @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_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)
+/// @param[in] i_end where to end, if stop conditions change (defaults to Master Rank)
+/// @param[in] i_stop stop conditions (default - DONT_CHANGE meaning 'don't change conditions')
+/// @param[in] i_speed the speed to scrub (default - SAM_SPEED 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 )
+ const end_boundary i_end,
+ const stop_conditions i_stop,
+ const speed i_speed )
{
- // TK implementation (because Glancy couldn't figure that out <grin>)
- FAPI_INF("continue_cmd - change thresholds");
- return FAPI2_RC_SUCCESS;
+ FAPI_INF("continue_cmd - no change thresholds");
+
+ // Read current thresholds and pass them as if they're changed.
+ fapi2::buffer<uint64_t> i_thresholds;
+ FAPI_TRY( mss::getScom(i_target, mss::mcbist::mcbistTraits<TARGET_TYPE_MCBIST>::THRESHOLD_REG, i_thresholds) );
+
+ return continue_cmd( i_target, thresholds(i_thresholds), i_end, i_stop, i_speed );
+
+fapi_try_exit:
+ return fapi2::current_err;
}
+
+
}
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
index 92d01e3a4..961fc5f73 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/memdiags.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/memdiags.H
@@ -48,11 +48,15 @@ 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;
+// Why not mss::mcbist::address? Because the fields can't be pulled in via using,
+// and it seems even more confusing to have a memdiags address but have to use
+// mcbist fields. So, we all use mcbist address until such time that its promoted
+// to some other general namespace.
+
using mss::mcbist::PATTERN_ZEROS;
using mss::mcbist::PATTERN_0;
using mss::mcbist::PATTERN_ONES;
@@ -69,35 +73,45 @@ using mss::mcbist::LAST_PATTERN;
using mss::mcbist::NO_PATTERN;
///
+/// @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 );
+
+///
/// @class Base class for memdiags operations
/// @tparam T fapi2::TargetType of the MCBIST engine
///
template< fapi2::TargetType T >
-class base
+class operation
{
public:
///
- /// @brief memdiags::base constructor
+ /// @brief memdiags::operation constructor
/// @param[in] i_target the target of the mcbist engine
+ /// @param[in] i_subtest the proper subtest for this operation
/// @param[in] i_const mss::constraint structure
///
- base( const fapi2::Target<T>& i_target,
- const memdiags::constraints i_const ):
+ operation( const fapi2::Target<T>& i_target,
+ const mss::mcbist::subtest_t<T> i_subtest,
+ const constraints i_const ):
iv_target(i_target),
+ iv_subtest(i_subtest),
iv_const(i_const)
{
+ FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), iv_is_sim) );
+ return;
+
+ fapi_try_exit:
+ // Seems like a safe risk to take ...
+ FAPI_ERR("Unable to get the attribute ATTR_IS_SIMULATION");
+ return;
}
- 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();
+ operation() = delete;
///
/// @brief Execute the memdiags operation
@@ -109,134 +123,177 @@ class base
}
///
- /// @brief memdiags::base destructor
+ /// @brief memdiags::operation destructor
///
- virtual ~base() = default;
-
- protected:
- fapi2::Target<T> iv_target;
- constraints iv_const;
- mss::mcbist::program<T> iv_program;
-};
+ virtual ~operation() = default;
-///
-/// @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
+ /// @brief memdiags init helper
+ /// Initializes common sections. Broken out rather than the base class ctor to enable checking return codes
+ /// in subclassed constructores more easily.
+ /// @return FAPI2_RC_SUCCESS iff everything ok
///
- 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)
- {
- }
+ fapi2::ReturnCode base_init();
- sf_operation() = delete;
+ ///
+ /// @brief memdiags multi-port init helper
+ /// Initializes common sections. Broken out rather than the base class ctor to enable checking return codes
+ /// in subclassed constructores more easily.
+ /// @return FAPI2_RC_SUCCESS iff everything ok
+ ///
+ fapi2::ReturnCode multi_port_init();
///
- /// @brief memdiags::sf_operation initializer
+ /// @brief Single port initializer
+ /// Initializes common sections. Broken out rather than the base class ctor to enable checking return codes
+ /// in subclassed constructores more easily.
/// @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();
+ fapi2::ReturnCode single_port_init();
///
- /// @brief memdiags::sf_operation destructor
+ /// @brief get the protected mcbist program - useful for testing
+ /// @return a reference to the iv_program member
+ /// @note Intentionally not const ref; allows getter to set.
///
- virtual ~sf_operation() = default;
+ mss::mcbist::program<T>& get_program()
+ {
+ return iv_program;
+ }
protected:
+ fapi2::Target<T> iv_target;
mss::mcbist::subtest_t<T> iv_subtest;
+ constraints iv_const;
+ mss::mcbist::program<T> iv_program;
+ uint8_t iv_is_sim;
};
///
-/// @class Base class for memdiags' super-fast init
+/// @class 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>
+struct sf_init_operation : public 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[in] i_const mss::constraint structure
/// @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,
+ const constraints i_const,
fapi2::ReturnCode& o_rc ):
- sf_operation<T>(i_target, constraints(i_pattern), mss::mcbist::init_subtest<T>())
+ operation<T>(i_target, mss::mcbist::init_subtest<T>(), i_const)
{
- o_rc = sf_operation<T>::init();
+ // We're a multi-port operation
+ o_rc = this->multi_port_init();
}
sf_init_operation() = delete;
};
///
-/// @class Base class for memdiags' super-fast read
+/// @class 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>
+struct sf_read_operation : public 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[in] i_const mss::constraint structure
/// @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 constraints i_const,
fapi2::ReturnCode& o_rc ):
- sf_operation<T>(i_target, constraints(i_stop, i_thresholds), mss::mcbist::read_subtest<T>())
+ operation<T>(i_target, mss::mcbist::read_subtest<T>(), i_const)
{
- o_rc = sf_operation<T>::init();
+ // We're a multi-port operation
+ o_rc = this->multi_port_init();
}
+ sf_read_operation() = delete;
+};
+
+///
+/// @class Class for memdiags' super-fast read to end of port
+/// @tparam T fapi2::TargetType of the MCBIST engine
+///
+template< fapi2::TargetType T >
+struct sf_read_eop_operation : public operation<T>
+{
///
- /// @brief memdiags::sf_read_operation constructor - given starting address
+ /// @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[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[in] i_const mss::constraint structure
/// @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>())
+ sf_read_eop_operation( const fapi2::Target<T>& i_target,
+ const constraints i_const,
+ fapi2::ReturnCode& o_rc ):
+ operation<T>(i_target, mss::mcbist::read_subtest<T>(), i_const)
{
- o_rc = sf_read_operation<T>::end_of_port_init();
+ // We're a single-port operation
+ o_rc = this->single_port_init();
}
- sf_read_operation() = delete;
+ sf_read_eop_operation() = delete;
+};
+
+///
+/// @class Class for memdiags' continuous scrub
+/// @tparam T fapi2::TargetType of the MCBIST engine
+///
+template< fapi2::TargetType T >
+struct continuous_scrub_operation : public operation<T>
+{
///
- /// @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
+ /// @brief memdiags::continuous_scrub_operation constructor
+ /// @param[in] i_target the target of the mcbist engine
+ /// @param[in] i_const the contraints of the operation
+ /// @param[out] o_rc the fapi2::ReturnCode of the intialization process
///
- fapi2::ReturnCode end_of_port_init();
+ continuous_scrub_operation( const fapi2::Target<T>& i_target,
+ const constraints i_const,
+ fapi2::ReturnCode& o_rc );
+
+ continuous_scrub_operation() = delete;
+};
+
+///
+/// @class Class for memdiags' targeted scrub
+/// @tparam T fapi2::TargetType of the MCBIST engine
+///
+template< fapi2::TargetType T >
+struct targeted_scrub_operation : public operation<T>
+{
+
+ ///
+ /// @brief memdiags::targeted_scrub_operation constructor
+ /// @param[in] i_target the target of the mcbist engine
+ /// @param[in] i_const the contraints of the operation
+ /// @param[out] o_rc the fapi2::ReturnCode of the intialization process
+ ///
+ targeted_scrub_operation( const fapi2::Target<T>& i_target,
+ const constraints i_const,
+ fapi2::ReturnCode& o_rc ):
+ operation<T>(i_target, mss::mcbist::scrub_subtest<T>(), i_const)
+ {
+ // Scrub operations run 128B
+ this->iv_program.change_len64(mss::OFF);
+
+ // We're a single-port operation
+ o_rc = this->single_port_init();
+ }
+
+ targeted_scrub_operation() = delete;
};
///
@@ -281,27 +338,45 @@ 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 );
+ const mss::mcbist::address& i_address );
+
+///
+/// @brief Scrub - continuous 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.
+/// @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 background_scrub( const fapi2::Target<T>& i_target,
+ const stop_conditions i_stop,
+ const thresholds& i_thresholds,
+ const speed i_speed,
+ const mss::mcbist::address& i_address );
///
-/// @brief Scrub - scrub all memory behind the target
+/// @brief Scrub - targeted scrub all memory described by the input address (rank, slave, etc.)
/// @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)
+/// @param[in] i_end whether to end, and where
/// @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 );
+fapi2::ReturnCode targeted_scrub( const fapi2::Target<T>& i_target,
+ const stop_conditions i_stop,
+ const thresholds& i_thresholds,
+ const speed i_speed,
+ const mss::mcbist::address& i_address,
+ const end_boundary i_end );
///
/// @brief Continue current command on next address
@@ -316,7 +391,7 @@ fapi2::ReturnCode scrub( const fapi2::Target<T>& i_target,
///
template< fapi2::TargetType T >
fapi2::ReturnCode continue_cmd( const fapi2::Target<T>& i_target,
- const end_boundary i_end = end_boundary::DONT_STOP,
+ const end_boundary i_end = end_boundary::NONE,
const stop_conditions i_stop = stop_conditions::DONT_CHANGE,
const speed i_speed = speed::SAME_SPEED );
@@ -335,18 +410,10 @@ fapi2::ReturnCode continue_cmd( const fapi2::Target<T>& i_target,
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 end_boundary i_end = end_boundary::NONE,
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
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
index d9e564c62..4ab89090c 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/settings.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/settings.H
@@ -47,6 +47,7 @@ namespace mcbist
enum stop_conditions
{
NO_STOP_ON_ERROR = 0b00,
+ DONT_STOP = NO_STOP_ON_ERROR,
STOP_AFTER_ADDRESS = 0b01,
STOP_AFTER_RANK = 0b10,
STOP_AFTER_SUBTEST = 0b11,
@@ -61,7 +62,6 @@ enum end_boundary
NONE = 0,
CONTINUOUS = NONE,
NEVER = NONE,
- DONT_STOP = NONE,
MASTER_RANK = 1,
MRANK = MASTER_RANK,
SLAVE_RANK = 2,
@@ -98,6 +98,15 @@ class thresholds
iv_value(0)
{ }
+
+ ///
+ /// @brief Thresholds class ctor
+ /// @param[in] uint64_t representing the threshold register contents
+ ///
+ thresholds(const uint64_t i_value):
+ iv_value(i_value)
+ { }
+
///
/// @brief Thresholds class dtor
///
@@ -414,6 +423,7 @@ struct constraints
iv_thresholds(),
iv_pattern(NO_PATTERN),
iv_end_boundary(NONE),
+ iv_speed(LUDICROUS),
iv_start_address(0),
iv_end_address(0)
{
@@ -460,10 +470,29 @@ struct constraints
i_stop, uint64_t(i_thresholds), uint64_t(i_start_address));
}
+ ///
+ /// @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 speed i_speed,
+ const end_boundary i_end_boundary,
+ const address& i_start_address ):
+ constraints(i_stop, i_thresholds, i_start_address)
+ {
+ iv_end_boundary = i_end_boundary;
+ iv_speed = i_speed;
+ FAPI_INF("setting up constraints with end boundary %d and speed 0x%x", i_end_boundary, i_speed);
+ }
+
stop_conditions iv_stop;
thresholds iv_thresholds;
uint64_t iv_pattern;
end_boundary iv_end_boundary;
+ speed iv_speed;
mcbist::address iv_start_address;
mcbist::address iv_end_address;
};
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
index 029072fe9..8e6aca12b 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/sim.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/mcbist/sim.C
@@ -88,9 +88,8 @@ fapi2::ReturnCode sf_init( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
// 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);
+ l_start.get_sim_end_address(l_end);
// 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
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H b/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H
index 5a9a53037..5c32022a5 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H
@@ -49,6 +49,9 @@ enum sizes
MAX_SLEW_VALUE = 15, ///< 4 bit value
MAX_SUPPORTED_FREQUENCIES = 1, ///< Number of supported frequencies. Right now it's only 2400
+ BYTES_PER_GB = 1000000000, ///< Multiplier to go from GB to B
+ T_PER_MT = 1000000, ///< Multiplier to go from MT/s to T/s
+
// All need to be attributes - BRS
// 48:51, 0b1100, (def_is_sim); # BIG_STEP = 12 (changed from default for SIM)
// 48:51, 0b0000, any; # BIG_STEP = 0 SWyatt
@@ -87,6 +90,11 @@ enum times
// From the DDR4spec 2400 speed - need to be changed to read attributes. BRS
tWLO = 10,
tWLOE = 2,
+
+ SEC_IN_HOUR = 60 * 60, ///< seconds in an hour, used for scrub times
+ BG_SCRUB_IN_HOURS = 12,
+
+ CMD_TIMEBASE = 8192, ///< Represents the timebase multiplier for the MCBIST inter cmd gap
};
enum states
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 18d3e74dc..20fed5c89 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
@@ -65,8 +65,8 @@ fapi2::ReturnCode p9_mss_scrub( const fapi2::Target<TARGET_TYPE_MCBIST>& i_targe
}
// 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());
+ return memdiags::background_scrub(i_target, mss::mcbist::stop_conditions::NO_STOP_ON_ERROR, mss::mcbist::thresholds(),
+ mss::mcbist::speed::LUDICROUS, mss::mcbist::address());
fapi_try_exit:
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
index a5a167a78..a16e3230c 100644
--- 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
@@ -37,6 +37,7 @@
#include <lib/mcbist/memdiags.H>
#include <lib/mcbist/address.H>
#include <lib/mcbist/settings.H>
+#include <lib/eff_config/memory_size.H>
#include <lib/utils/poll.H>
#include <tests/target_fixture.H>
@@ -45,6 +46,7 @@ using fapi2::FAPI2_RC_SUCCESS;
using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_MCS;
+using fapi2::TARGET_TYPE_DIMM;
namespace mss
{
@@ -64,6 +66,7 @@ TEST_CASE_METHOD(mss::test::mcbist_target_test_fixture, "memdiags", "[memdiags]"
// 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;
@@ -194,8 +197,8 @@ TEST_CASE_METHOD(mss::test::mcbist_target_test_fixture, "memdiags", "[memdiags]"
// 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() );
+ memdiags::operation<TARGET_TYPE_MCBIST> l_bob(i_target, mss::mcbist::init_subtest<TARGET_TYPE_MCBIST>(), l_const);
+ REQUIRE_FALSE( l_bob.multi_port_init() );
REQUIRE_FALSE( l_bob.execute() );
// Check the things we default to so that we have a canary in case the defaults change
@@ -239,6 +242,7 @@ TEST_CASE_METHOD(mss::test::mcbist_target_test_fixture, "memdiags", "[memdiags]"
// Poll for the fir bit. We expect this to be set ...
fapi2::buffer<uint64_t> l_status;
+ fapi2::buffer<uint64_t> l_last_address;
// A small vector of addresses to poll during the polling loop
static const std::vector<mss::poll_probe<fapi2::TARGET_TYPE_MCBIST>> l_probes =
@@ -256,6 +260,10 @@ TEST_CASE_METHOD(mss::test::mcbist_target_test_fixture, "memdiags", "[memdiags]"
},
l_probes);
+ // Pass or fail output the current address. This is useful for debugging when we can get it.
+ REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBMCATQ, l_last_address) );
+ FAPI_INF("MCBIST last address: 0x%016lx", l_last_address);
+
REQUIRE( l_poll_results == true );
// Check for errors
@@ -282,8 +290,8 @@ TEST_CASE_METHOD(mss::test::mcbist_target_test_fixture, "memdiags", "[memdiags]"
// 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() );
+ memdiags::operation<TARGET_TYPE_MCBIST> l_bob(i_target, mss::mcbist::read_subtest<TARGET_TYPE_MCBIST>(), l_const);
+ REQUIRE_FALSE( l_bob.multi_port_init() );
REQUIRE_FALSE( l_bob.execute() );
// Check the things we default to so that we have a canary in case the defaults change
@@ -327,6 +335,7 @@ TEST_CASE_METHOD(mss::test::mcbist_target_test_fixture, "memdiags", "[memdiags]"
// Poll for the fir bit. We expect this to be set ...
fapi2::buffer<uint64_t> l_status;
+ fapi2::buffer<uint64_t> l_last_address;
// A small vector of addresses to poll during the polling loop
static const std::vector<mss::poll_probe<fapi2::TARGET_TYPE_MCBIST>> l_probes =
@@ -344,6 +353,10 @@ TEST_CASE_METHOD(mss::test::mcbist_target_test_fixture, "memdiags", "[memdiags]"
},
l_probes);
+ // Pass or fail output the current address. This is useful for debugging when we can get it.
+ REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBMCATQ, l_last_address) );
+ FAPI_INF("MCBIST last address: 0x%016lx", l_last_address);
+
REQUIRE( l_poll_results == true );
// Check for errors
@@ -386,7 +399,7 @@ TEST_CASE_METHOD(mss::test::mcbist_target_test_fixture, "memdiags", "[memdiags]"
{
fapi2::buffer<uint64_t> l_read;
REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBCFGQ, l_read) );
- REQUIRE( 0x00000000000000a0 == l_read );
+ REQUIRE( 0x00000000000000a8 == l_read );
}
// Load thresholds - default state (expecting 0's)
@@ -408,13 +421,14 @@ TEST_CASE_METHOD(mss::test::mcbist_target_test_fixture, "memdiags", "[memdiags]"
fapi2::buffer<uint64_t> l_read;
REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBSA0Q, l_read) );
- REQUIRE(l_read == 0x1FFFFFC000000000);
+ REQUIRE(l_read == 0x1fffffc000000000);
REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBEA0Q, l_read) );
- REQUIRE(l_read == 0x1FFFFFFFFC000000);
+ REQUIRE(l_read == 0x1fffffe07c000000);
}
// Poll for the fir bit. We expect this to be set ...
fapi2::buffer<uint64_t> l_status;
+ fapi2::buffer<uint64_t> l_last_address;
// A small vector of addresses to poll during the polling loop
static const std::vector<mss::poll_probe<fapi2::TARGET_TYPE_MCBIST>> l_probes =
@@ -432,6 +446,10 @@ TEST_CASE_METHOD(mss::test::mcbist_target_test_fixture, "memdiags", "[memdiags]"
},
l_probes);
+ // Pass or fail output the current address. This is useful for debugging when we can get it.
+ REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBMCATQ, l_last_address) );
+ FAPI_INF("MCBIST last address: 0x%016lx", l_last_address);
+
REQUIRE( l_poll_results == true );
// Check for errors
@@ -447,6 +465,238 @@ TEST_CASE_METHOD(mss::test::mcbist_target_test_fixture, "memdiags", "[memdiags]"
}
+ SECTION("Test continuous scrub")
+ {
+ // How many DIMM do we have? This effects the subtests we create
+ const auto l_dimm_count = mss::find_targets<TARGET_TYPE_DIMM>(i_target).size();
+ FAPI_INF("seeing %d DIMM", l_dimm_count);
+
+ // 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::background_scrub(i_target, memdiags::stop_conditions::NO_STOP_ON_ERROR, memdiags::thresholds(),
+ memdiags::speed::BG_SCRUB, l_start) );
+
+ // check the state of the mcbist engine
+
+ // Check the iv_parameters
+ {
+ fapi2::buffer<uint64_t> l_read;
+ uint64_t l_size;
+ REQUIRE_FALSE( mss::eff_memory_size(i_target, l_size) );
+ REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBPARMQ, l_read) );
+
+ FAPI_INF("seeing memory size %d", l_size);
+
+ switch (l_size)
+ {
+ case 128:
+ REQUIRE(l_read == 0x68000000000000);
+ break;
+
+ case 64:
+ REQUIRE(l_read == 0xC8000000000000);
+ break;
+
+ default:
+ FAIL("Memory size not supported");
+ break;
+ };
+ }
+
+ // Check the address registers
+ {
+ // Address config 0 should have the start and end for a complete DIMM (in sim)
+ 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 == 0x000000207C000000);
+ }
+ {
+ // Address 1 should have the start we configured and an end which is the
+ // real end of the DIMM address range
+ fapi2::buffer<uint64_t> l_read;
+
+ REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBSA1Q, l_read) );
+ REQUIRE(l_read == 0x1fffffc000000000);
+ REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBEA1Q, l_read) );
+ REQUIRE(l_read == 0x1fffffe07c000000);
+ }
+
+ // Check the subtests
+ {
+ if (l_dimm_count == 8)
+ {
+ fapi2::buffer<uint64_t> l_read;
+
+ REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBMR0Q, l_read) );
+ REQUIRE(l_read == 0x9009718090089208);
+ REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBMR1Q, l_read) );
+ REQUIRE(l_read == 0x9408960898089a08);
+ REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBMR2Q, l_read) );
+ REQUIRE(l_read == 0x9c089e0871040000);
+ }
+ }
+
+ // Make sure continuous scrub doesn't set the FIR bit. More for verifying our actions than
+ // anything else
+ {
+ fapi2::buffer<uint64_t> l_read;
+ REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBISTFIRQ, l_read) );
+ REQUIRE( l_read.getBit<MCBIST_MCBISTFIRQ_MCBIST_PROGRAM_COMPLETE>() == false );
+ }
+
+ // We should have the LEN64 bit turned off
+ {
+ fapi2::buffer<uint64_t> l_read;
+ REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBCFGQ, l_read) );
+ REQUIRE( 0x0000000000000000 == l_read );
+ }
+
+
+ }
+
+ SECTION("Test targeted scrub")
+ {
+ // Test that passing in no-stop is a bug
+ REQUIRE( memdiags::targeted_scrub(i_target, memdiags::stop_conditions::DONT_STOP, memdiags::thresholds(),
+ memdiags::speed::LUDICROUS, mss::mcbist::address(),
+ memdiags::end_boundary::MASTER_RANK) );
+
+ REQUIRE_FALSE( memdiags::targeted_scrub(i_target, memdiags::stop_conditions::STOP_AFTER_RANK, memdiags::thresholds(),
+ memdiags::speed::LUDICROUS, mss::mcbist::address(),
+ memdiags::end_boundary::MASTER_RANK) );
+
+ // Make sure targeted scrub sets the FIR bit. More for verifying our actions than
+ // anything else
+ {
+ fapi2::buffer<uint64_t> l_read;
+ REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBISTFIRQ, l_read) );
+ REQUIRE( l_read.getBit<MCBIST_MCBISTFIRQ_MCBIST_PROGRAM_COMPLETE>() == true );
+ }
+
+ // Check the address registers
+ {
+ // Address config 0 should have the start and end for a complete DIMM (in sim)
+ 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 == 0x000000207C000000);
+ }
+
+ // Check the subtests
+ {
+ fapi2::buffer<uint64_t> l_read;
+
+ REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBMR0Q, l_read) );
+ REQUIRE(l_read == 0x900c000000000000);
+ }
+
+ // We should have the LEN64 bit turned off but we turned on pause-on-rank boundary
+ {
+ fapi2::buffer<uint64_t> l_read;
+ REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBCFGQ, l_read) );
+ REQUIRE( 0x0000000020000020 == l_read );
+ }
+
+ }
+
+ SECTION("Test what happens on stop-after-rank")
+ {
+ mss::mcbist::address l_start_address;
+ mss::mcbist::address l_end_address;
+ fapi2::ReturnCode l_rc;
+
+ // Make our start be really close to the end of the rank an our end be the end so we
+ // can check to see what happens at the end of the rank
+ l_start_address.get_range<mss::mcbist::address::MRANK>(l_end_address);
+ l_start_address = l_end_address - 10;
+
+ memdiags::constraints l_const(memdiags::stop_conditions::STOP_AFTER_RANK, memdiags::thresholds(),
+ memdiags::speed::LUDICROUS, memdiags::end_boundary::MASTER_RANK,
+ l_start_address);
+
+ l_const.iv_end_address = l_end_address;
+
+ memdiags::targeted_scrub_operation<TARGET_TYPE_MCBIST> l_op(i_target, l_const, l_rc);
+
+ REQUIRE_FALSE( l_rc );
+
+ // Add a goto on to the end of this program so that if it stops we know it stopped because
+ // of the rank boundary.
+ l_op.get_program().iv_subtests.push_back(mss::mcbist::goto_subtest<TARGET_TYPE_MCBIST>(0));
+
+ REQUIRE_FALSE( l_op.execute() );
+
+ // 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;
+ fapi2::buffer<uint64_t> l_status;
+ fapi2::buffer<uint64_t> l_last_address;
+
+ 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);
+
+ // Pass or fail output the current address. This is useful for debugging when we can get it.
+ REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBMCATQ, l_last_address) );
+ FAPI_INF("MCBIST last address: 0x%016lx", l_last_address);
+
+ 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);
+ }
+
+ // We asked to stop at the end of a rank, so we should not be able to continue to the end of the rank
+ REQUIRE( memdiags::continue_cmd(i_target, memdiags::end_boundary::MRANK, memdiags::stop_conditions::STOP_AFTER_RANK) );
+
+ // Continue but ask to stop at the end of the subtest
+ REQUIRE_FALSE( memdiags::continue_cmd(i_target, memdiags::end_boundary::NONE,
+ memdiags::stop_conditions::STOP_AFTER_SUBTEST) );
+
+ 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);
+
+ // Pass or fail output the current address. This is useful for debugging when we can get it.
+ REQUIRE_FALSE( mss::getScom(i_target, MCBIST_MCBMCATQ, l_last_address) );
+ FAPI_INF("MCBIST last address: 0x%016lx", l_last_address);
+
+ REQUIRE( l_poll_results == true );
+ }
+
+
return 0;
});
}
OpenPOWER on IntegriCloud