From 9900129f86ae2fd82f59f643e71d15b5143959c2 Mon Sep 17 00:00:00 2001 From: Louis Stermole Date: Wed, 7 Feb 2018 10:47:16 -0600 Subject: Fix command gap calculation for MSS scrub to prevent truncation Change-Id: Ifcebaf4b2d2145c3351d80c92b9c77f1ef8e4183 CQ:SW415825 RTC:187080 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/53554 Tested-by: FSP CI Jenkins Reviewed-by: STEPHEN GLANCY Tested-by: Jenkins Server Tested-by: HWSV CI Tested-by: Hostboot CI Reviewed-by: ANDRE A. MARIN Reviewed-by: Jennifer A. Stofer Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/53633 Tested-by: Jenkins OP Build CI Tested-by: Jenkins OP HW Reviewed-by: Daniel M. Crowell --- .../p9/procedures/hwp/memory/lib/mcbist/mcbist.H | 100 +++++++++++++++++---- .../procedures/hwp/memory/lib/shared/mss_const.H | 1 + 2 files changed, 82 insertions(+), 19 deletions(-) (limited to 'src/import/chips/p9/procedures/hwp/memory') 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 160db78ac..64743e365 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 @@ -1741,6 +1741,79 @@ class program return; } + /// + /// @brief Calculate minimum command gap for BG_SCRUB + /// @param[in] i_target the target behind which the memory sits + /// @param[in] i_freq the DRAM frequency + /// @param[in] i_size the sum of all DIMM sizes + /// @param[out] o_min_cmd_gap the setting for MCBPARMQ_CFG_MIN_CMD_GAP + /// @param[out] o_timebase the setting for MCBPARMQ_CFG_MIN_GAP_TIMEBASE + /// + inline void calculate_min_cmd_gap( const fapi2::Target& i_target, + const uint64_t i_freq, + const uint64_t i_size, + uint64_t& o_min_cmd_gap, + mss::states& o_timebase ) + { + constexpr uint64_t l_seconds = SEC_IN_HOUR * BG_SCRUB_IN_HOURS; + constexpr uint64_t MIN_CMD_GAP = 0x001; + + // Sanity check our inputs, just assert if bad since they come directly from eff_config + // this will prevent us from any divide by zero problems + if ((i_freq == 0) || (i_size == 0)) + { + FAPI_ERR("received zero memory freq or size in calculate_min_cmd_gap"); + fapi2::Assert(false); + } + + // 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) + const uint64_t l_mem_cycles_per_sec = (i_freq * T_PER_MT) / 2; + const uint64_t l_total_cycles = l_seconds * l_mem_cycles_per_sec; + + // TOTAL ADDRESSES = sum over all dimms of ( [DIMM CAPACITY]/128B ) + const uint64_t l_total_addresses = i_size * BYTES_PER_GB / 128; + + const auto l_min_cmd_gap = l_total_cycles / l_total_addresses; + + // If we're greater than the timebase, set the multiplier and divide down to get the gap setting + if (CMD_TIMEBASE < l_min_cmd_gap) + { + o_min_cmd_gap = l_min_cmd_gap / CMD_TIMEBASE; + o_timebase = mss::ON; + return; + } + + // If we're greater than the max gap setting, get as close to 12 hours as we can instead of just truncating + if (l_min_cmd_gap > MAX_CMD_GAP) + { + // work backwards to calculate what the total scrub time would be with the highest cmd gap with no multiplier... + const uint64_t l_scrub_time_fff = (l_total_addresses * MAX_CMD_GAP) / l_mem_cycles_per_sec; + // and with the lowest cmd gap with the multiplier + const uint64_t l_scrub_time_001 = (l_total_addresses * CMD_TIMEBASE) / l_mem_cycles_per_sec; + + if ((l_seconds - l_scrub_time_fff) > (l_scrub_time_001 - l_seconds)) + { + FAPI_INF("%s gap is greater than the field will allow. Setting to: %03x", mss::c_str(i_target), MIN_CMD_GAP); + o_min_cmd_gap = MIN_CMD_GAP; + o_timebase = mss::ON; + } + else + { + FAPI_INF("%s gap is greater than the field will allow. Setting to: %03x", mss::c_str(i_target), MAX_CMD_GAP); + o_min_cmd_gap = MAX_CMD_GAP; + o_timebase = mss::OFF; + } + + return; + } + + // Else, we're good to just set the calculated gap value directly + o_min_cmd_gap = l_min_cmd_gap; + o_timebase = mss::OFF; + } + /// /// @brief Change MCBIST Speed /// @param[in] i_target the target behind which the memory sits @@ -1762,31 +1835,20 @@ class program uint64_t l_freq = 0; uint64_t l_size = 0; uint64_t l_min_cmd_gap = 0; + mss::states l_timebase = mss::OFF; 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); - } + calculate_min_cmd_gap(i_target, l_freq, l_size, l_min_cmd_gap, l_timebase); + + FAPI_INF("%s setting bg scrub speed: %dMT/s, memory: %dGB, duration: %ds, gap: %d", + mss::c_str(i_target), l_freq, l_size, l_seconds, l_min_cmd_gap); + + change_min_cmd_gap(l_min_cmd_gap); + change_min_gap_timebase(l_timebase); return fapi2::FAPI2_RC_SUCCESS; } 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 4af49c5ef..e6027a580 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 @@ -140,6 +140,7 @@ enum times BG_SCRUB_IN_HOURS = 12, CMD_TIMEBASE = 8192, ///< Represents the timebase multiplier for the MCBIST inter cmd gap + MAX_CMD_GAP = 4095, ///< Represents the maximum (non-multplied) time for MCBIST inter cmd gap FULL_DLL_CAL_DELAY = 37382, ///< Full DLL calibration (in ddphy_nck cycles) }; -- cgit v1.2.1