summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9
diff options
context:
space:
mode:
authorAndre Marin <aamarin@us.ibm.com>2018-01-10 12:17:50 -0600
committerDaniel M. Crowell <dcrowell@us.ibm.com>2018-02-15 17:21:28 -0500
commit8c104ea1e91975df04c82f18cd672d9d4a7e4862 (patch)
treedf899b192b8e977c04f11d8e60bfedd6301b703e /src/import/chips/p9
parentf89ef741249515aac55b44bb25f0bbbd69f090d2 (diff)
downloadtalos-hostboot-8c104ea1e91975df04c82f18cd672d9d4a7e4862.tar.gz
talos-hostboot-8c104ea1e91975df04c82f18cd672d9d4a7e4862.zip
Add VPD lookup to build a supported frequency list, and bin-down support
Bypassing FFDC collection in p9_get_mem_vpd_keyword.C for unsupported configs that appear while polling the VPD for supported frequencies in the memory procedure p9_mss_freq.C. This removes the fail trace during istep to avoid user confusion. Change-Id: Ic679fb2fd8357567059f87d689acc0e0c534cd9f CQ:SW415931 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/51836 Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Dev-Ready: Brent Wieman <bwieman@us.ibm.com> Reviewed-by: STEPHEN GLANCY <sglancy@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: HWSV CI <hwsv-ci+hostboot@us.ibm.com> Tested-by: PPE CI <ppe-ci+hostboot@us.ibm.com> Tested-by: Hostboot CI <hostboot-ci+hostboot@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/51842 Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com> Tested-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9')
-rw-r--r--src/import/chips/p9/procedures/hwp/accessors/p9_get_mem_vpd_keyword.C58
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.C469
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.H291
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.C382
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.H143
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H7
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.C132
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.H21
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C89
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H9
-rw-r--r--src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_freq.xml25
-rw-r--r--src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_general_errors.xml18
12 files changed, 1018 insertions, 626 deletions
diff --git a/src/import/chips/p9/procedures/hwp/accessors/p9_get_mem_vpd_keyword.C b/src/import/chips/p9/procedures/hwp/accessors/p9_get_mem_vpd_keyword.C
index c03ab1304..e44363989 100644
--- a/src/import/chips/p9/procedures/hwp/accessors/p9_get_mem_vpd_keyword.C
+++ b/src/import/chips/p9/procedures/hwp/accessors/p9_get_mem_vpd_keyword.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -422,29 +422,39 @@ extern "C"
}
}
- //Was a matching row found?
- //Was a valid keyword name found?
- FAPI_ASSERT( (0 != l_second) &&
- (static_cast<char>(MAPPING_LAYOUT_INVALID) != l_second),
- fapi2::GET_MEM_VPD_UNSUPPORTED_CONFIG().
- set_MCS(fapi2::ATTR_MEMVPD_POS_Type(l_mcsPos)).
- set_FREQ(uint32_t(i_vpd_info.iv_freq_mhz)).
- set_DIMM0RANK(uint64_t(i_vpd_info.iv_rank_count_dimm_0)).
- set_DIMM1RANK(uint64_t(i_vpd_info.iv_rank_count_dimm_1)).
- set_HEADER(mappingHeader_t(*l_mappingHeader)).
- set_MCS_TARGET(i_target).
- set_VPDTYPE(i_vpd_info.iv_vpd_type).
- set_MAPROW0(l_ffdc_MAPROW[0]).
- set_MAPROW1(l_ffdc_MAPROW[1]).
- set_MAPROW2(l_ffdc_MAPROW[2]).
- set_MAPROW3(l_ffdc_MAPROW[3]).
- set_MAPROW4(l_ffdc_MAPROW[4]).
- set_MAPROW5(l_ffdc_MAPROW[5]).
- set_MAPROW6(l_ffdc_MAPROW[6]).
- set_MAPROW7(l_ffdc_MAPROW[7]).
- set_MAPROW8(l_ffdc_MAPROW[8]).
- set_MAPROW9(l_ffdc_MAPROW[9]),
- "Unsupported configuration, no match in memory vpd mapping table");
+ // Was a matching row found?
+ // Was a valid keyword name found?
+ if( (0 == l_second) || ((static_cast<char>(MAPPING_LAYOUT_INVALID) == l_second)) )
+ {
+ // If we are in this conditional then we have encountered a fail and must decide
+ // how to proceed further. If iv_is_config_ffdc_enabled is true we will collect
+ // FFDC and assert out here.
+ FAPI_ASSERT( !i_vpd_info.iv_is_config_ffdc_enabled,
+ fapi2::GET_MEM_VPD_UNSUPPORTED_CONFIG().
+ set_MCS(fapi2::ATTR_MEMVPD_POS_Type(l_mcsPos)).
+ set_FREQ(uint32_t(i_vpd_info.iv_freq_mhz)).
+ set_DIMM0RANK(uint64_t(i_vpd_info.iv_rank_count_dimm_0)).
+ set_DIMM1RANK(uint64_t(i_vpd_info.iv_rank_count_dimm_1)).
+ set_HEADER(mappingHeader_t(*l_mappingHeader)).
+ set_MCS_TARGET(i_target).
+ set_VPDTYPE(i_vpd_info.iv_vpd_type).
+ set_MAPROW0(l_ffdc_MAPROW[0]).
+ set_MAPROW1(l_ffdc_MAPROW[1]).
+ set_MAPROW2(l_ffdc_MAPROW[2]).
+ set_MAPROW3(l_ffdc_MAPROW[3]).
+ set_MAPROW4(l_ffdc_MAPROW[4]).
+ set_MAPROW5(l_ffdc_MAPROW[5]).
+ set_MAPROW6(l_ffdc_MAPROW[6]).
+ set_MAPROW7(l_ffdc_MAPROW[7]).
+ set_MAPROW8(l_ffdc_MAPROW[8]).
+ set_MAPROW9(l_ffdc_MAPROW[9]),
+ "Unsupported configuration, no match in memory vpd mapping table");
+
+ // If iv_is_config_ffdc_enabled is false we will arrive here and exit with a bad ReturnCode
+ // but won't collect FFDC so we don't pollute users with false fails.
+ FAPI_INF("Unsupported configuration, no match in memory vpd mapping table");
+ return fapi2::FAPI2_RC_FALSE;
+ }
// build the keyword name
o_keywordInfo.kwName[0] = l_first;
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.C b/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.C
index 4c88f60d8..b81796771 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -41,10 +41,8 @@
#include <fapi2.H>
// mss lib
-#include <generic/memory/lib/spd/common/ddr4/spd_decoder_ddr4.H>
#include <lib/freq/cas_latency.H>
-#include <lib/freq/sync.H>
-#include <lib/utils/conversions.H>
+#include <lib/spd/spd_factory.H>
#include <lib/eff_config/timing.H>
#include <generic/memory/lib/utils/find.H>
#include <lib/utils/checker.H>
@@ -56,34 +54,27 @@ using fapi2::TARGET_TYPE_MCA;
namespace mss
{
-///
-/// @brief encoding for MSS_INVALID_TIMING so we can look up functions based on encoding
-///
-enum invalid_timing_function_encoding
-{
- TAAMIN = 10,
- TCKMIN = 11,
- TCKMAX = 12,
-};
-
/////////////////////////
// Member method implementation
/////////////////////////
///
-/// @brief Class constructor that retrieves required SPD data held by internal state
-/// @param[in] i_target the controller target
-/// @param[in] i_caches decoder caches
+/// @brief Class constructor that retrieves required SPD data held by internal state
+/// @param[in] i_target the controller target
+/// @param[in] i_caches decoder caches
+/// @param[in] i_supported_freqs vector of supported freqs
/// @param[out] o_rc returns FAPI2_RC_SUCCESS if constructor initialzed successfully
///
cas_latency::cas_latency(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
const std::vector< std::shared_ptr<spd::decoder> >& i_caches,
- fapi2::ReturnCode& o_rc ):
+ const std::vector<uint32_t>& i_supported_freqs,
+ fapi2::ReturnCode& o_rc):
iv_dimm_list_empty(false),
iv_target(i_target),
iv_largest_taamin(0),
iv_proposed_tck(0),
- iv_common_cl(UINT64_MAX) // Masks out supported CLs
+ iv_common_cl_bitmap(UINT64_MAX),
+ iv_supported_freqs(i_supported_freqs)
{
o_rc = fapi2::FAPI2_RC_SUCCESS;
@@ -97,16 +88,17 @@ cas_latency::cas_latency(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
for ( const auto& l_cache : i_caches )
{
// Retrieve timing values from the SPD
+ const auto l_target = l_cache->iv_target;
uint64_t l_taa_min_in_ps = 0;
uint64_t l_tckmax_in_ps = 0;
uint64_t l_tck_min_in_ps = 0;
FAPI_TRY( get_taamin(l_cache, l_taa_min_in_ps),
- "%s. Failed to get tAAmin", mss::c_str(iv_target) );
+ "%s. Failed to get tAAmin", mss::c_str(l_target) );
FAPI_TRY( get_tckmax(l_cache, l_tckmax_in_ps),
- "%s. Failed to get tCKmax", mss::c_str(iv_target) );
+ "%s. Failed to get tCKmax", mss::c_str(l_target) );
FAPI_TRY( get_tckmin(l_cache, l_tck_min_in_ps),
- "%s. Failed to get tCKmin", mss::c_str(iv_target) );
+ "%s. Failed to get tCKmin", mss::c_str(l_target) );
// Determine largest tAAmin value
iv_largest_taamin = std::max(iv_largest_taamin, l_taa_min_in_ps);
@@ -133,56 +125,28 @@ cas_latency::cas_latency(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
// Retrieve dimm supported cas latencies from SPD
uint64_t l_dimm_supported_cl = 0;
FAPI_TRY( l_cache->supported_cas_latencies(l_dimm_supported_cl),
- "%s. Failed to get supported CAS latency", mss::c_str(iv_target) );
+ "%s. Failed to get supported CAS latency", mss::c_str(l_target) );
// Bitwise ANDING the bitmap from all modules creates a bitmap w/a common CL
- iv_common_cl &= l_dimm_supported_cl;
+ iv_common_cl_bitmap &= l_dimm_supported_cl;
}
}// caches
- // Limit tCK from the max supported dimm speed in the system
- // So that this is taken into account when calculating CL
- {
- // Defaulting to non-zero speed
- uint64_t l_freq_override = fapi2::ENUM_ATTR_MSS_FREQ_MT2666;
- uint64_t l_tck_override_in_ps = 0;
-
- FAPI_TRY( select_supported_freq(iv_target, l_freq_override),
- "%s. Failed select_supported_freq()", mss::c_str(iv_target) );
- FAPI_TRY( freq_to_ps(l_freq_override, l_tck_override_in_ps),
- "%s. Failed freq_to_ps()", mss::c_str(iv_target) );
-
- FAPI_INF("%s. Selected supported dimm speed %d MT/s (Clock period %d in ps)",
- mss::c_str(iv_target), l_freq_override, l_tck_override_in_ps);
-
- iv_proposed_tck = std::max( l_tck_override_in_ps, iv_proposed_tck );
- FAPI_INF("%s. Initial proposed tCK in ps: %d", mss::c_str(iv_target), iv_proposed_tck);
-
-
- // Sanity check
- FAPI_ASSERT(iv_proposed_tck > 0,
- fapi2::MSS_INVALID_CALCULATED_TCK().
- set_TAAMIN(iv_largest_taamin).
- set_PROPOSED_TCK(iv_proposed_tck).
- set_IS_3DS(iv_is_3ds).
- set_FREQUENCY(l_freq_override).
- set_MCA_TARGET(iv_target),
- "%s. Invalid calculated clock period(<= 0) : %d",
- mss::c_str(iv_target),
- iv_proposed_tck);
- }
-
// Why didn't I encapsulate common CL operations and checking in a function
// like the timing params? Well, I want to check the "final" common CL and
// the creation of common CLs (bitwise ANDING) is at the dimm level operation
- FAPI_ASSERT(iv_common_cl != 0,
+ FAPI_ASSERT(iv_common_cl_bitmap != 0,
fapi2::MSS_NO_COMMON_SUPPORTED_CL().
- set_CL_SUPPORTED(iv_common_cl).
+ set_CL_SUPPORTED(iv_common_cl_bitmap).
set_MCA_TARGET(iv_target),
"%s. No common CAS latencies (CL bitmap = 0)",
mss::c_str(iv_target) );
- FAPI_INF("%s. Supported CL bitmap 0x%llX", mss::c_str(iv_target), iv_common_cl);
+ FAPI_INF("Largest tAAmin (ps): %d, tCKmin (ps): %d, and supported CL bitmap 0x%llX for all modules across %s",
+ iv_largest_taamin, iv_proposed_tck, iv_common_cl_bitmap, mss::c_str(iv_target));
+
+ iv_common_cl = integral_bitmap_to_vector(iv_common_cl_bitmap);
+ FAPI_TRY( mss::required_synch_mode(iv_req_sync_mode) );
fapi_try_exit:
o_rc = fapi2::current_err;
@@ -191,24 +155,30 @@ fapi_try_exit:
///
-/// @brief Constructor that allows the user to set desired data in lieu of SPD
-/// @param[in] i_target the controller target
-/// @param[in] i_taa_min largest tAAmin we want to set in picoseconds
-/// @param[in] i_tck_min proposed tCKmin in picoseconds
-/// @param[in] i_common_cl_mask common CAS latency mask we want to force (bitmap)
-/// @param[in] i_is_3ds loading::IS_3DS if this is for 3DS, loading::NOT_3DS otherwise
+/// @brief Constructor that allows the user to set desired data in lieu of SPD - helpful for testing
+/// @param[in] i_target the controller target
+/// @param[in] i_taa_min largest tAAmin we want to set in picoseconds
+/// @param[in] i_tck_min proposed tCKmin in picoseconds
+/// @param[in] i_common_cl_mask common CAS latency mask we want to force (bitmap)
+/// @param[in] i_is_3ds loading::IS_3DS if this is for 3DS, loading::NOT_3DS otherwise
+/// @param[in] i_req_sync_mode required synchronous mode -- defaulted to SYNCH_MODE_UNDETERMINED,
+/// @param[in] i_supported_freqs vector of supported freqs -- defaulted to NIMBUS_SUPPORTED_FREQS
///
cas_latency::cas_latency(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
const uint64_t i_taa_min,
const uint64_t i_tck_min,
const uint64_t i_common_cl_mask,
- const loading i_is_3ds):
+ const loading i_is_3ds,
+ const uint8_t i_req_sync_mode,
+ const std::vector<uint32_t>& i_supported_freqs):
iv_dimm_list_empty(false),
iv_target(i_target),
iv_largest_taamin(i_taa_min),
iv_proposed_tck(i_tck_min),
- iv_common_cl(i_common_cl_mask),
- iv_is_3ds(i_is_3ds)
+ iv_is_3ds(i_is_3ds),
+ iv_common_cl_bitmap(i_common_cl_mask),
+ iv_req_sync_mode(i_req_sync_mode),
+ iv_supported_freqs(i_supported_freqs)
{
const auto l_dimm_list = find_targets<TARGET_TYPE_DIMM>(iv_target);
@@ -217,52 +187,122 @@ cas_latency::cas_latency(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
FAPI_INF("cas latency ctor seeing no DIMM on %s", mss::c_str(iv_target));
iv_dimm_list_empty = true;
}
+
+ iv_common_cl = integral_bitmap_to_vector(iv_common_cl_bitmap);
}
///
-/// @brief Calculates CAS latency and checks if it is supported and within JEDEC spec.
+/// @brief Calculates CAS latency and checks if it is supported and within JEDEC spec.
/// @param[out] o_cas_latency selected CAS latency
/// @param[out] o_tck cycle time corresponding to selected CAS latency
-/// @return fapi2::FAPI2_RC_SUCCESS if ok
+/// @return fapi2::FAPI2_RC_SUCCESS if ok
///
fapi2::ReturnCode cas_latency::find_cl(uint64_t& o_cas_latency,
uint64_t& o_tck)
{
- uint64_t l_desired_cas_latency = 0;
-
fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
- if(!iv_dimm_list_empty)
+ // note: iv_common_cl is sorted in increasing order
+ const uint64_t l_max_cl = iv_common_cl.back();
+ const uint64_t l_min_cl = *iv_common_cl.begin();
+
+ bool l_is_cl_in_common = false;
+ bool l_is_cl_exceeding_taa = true;
+ uint64_t l_desired_cas_latency = 0;
+ bool l_is_1st_iteration = true;
+
+ if(iv_dimm_list_empty)
{
- // Create a vector filled with common CLs from buffer
- std::vector<uint64_t> l_supported_cls = integral_bitmap_to_vector(iv_common_cl);
+ // If the MCA has no dimm configured then both
+ // CAS latency and tCK are safe as 0's
+ o_cas_latency = 0;
+ o_tck = 0;
+ return fapi2::FAPI2_RC_SUCCESS;
+ }
- // Make sure we have at least one entry. We should since iv_common_cl is checked in ctor
- FAPI_ASSERT( !l_supported_cls.empty(),
- fapi2::MSS_NO_COMMON_SUPPORTED_CL().
- set_CL_SUPPORTED(iv_common_cl).
- set_MCA_TARGET(iv_target),
- "%s. Error making support cas latency vector. No common CAS latencies",
- mss::c_str(iv_target) );
+ while(!l_is_cl_in_common && l_is_cl_exceeding_taa)
+ {
+ if( l_is_1st_iteration )
+ {
+ // Our first run should try to run the highest common supported freq.
+ // If we don't meet JEDEC requirements then every iteration afterwards
+ // will bin down
+ l_is_1st_iteration = false;
+ FAPI_TRY( apply_freq_constraints<HIGHEST_COMMON>(iv_proposed_tck) );
+ }
+ else
+ {
+ // Limit tCK from system constraints such as supported VPD for the system
+ // as well as MRW frequency overrides, if enabled. This guy will bin freq down until
+ // we can't and then we fail out, prevents infinite loop when raising tCK
+ FAPI_TRY( apply_freq_constraints<BIN_DOWN>(iv_proposed_tck) );
+ }
// For a proposed tCK value between tCKmin(all) and tCKmax, determine the desired CAS Latency.
FAPI_TRY( calc_cas_latency(iv_largest_taamin, iv_proposed_tck, l_desired_cas_latency),
"%s. Failed to calculate CAS latency", mss::c_str(iv_target) );
- // Chose an actual CAS Latency (CLactual) that is greater than or equal to CLdesired
+ // Choose an actual CAS Latency (CLactual) that is greater than or equal to CLdesired
// and is supported by all modules on the memory channel
- FAPI_TRY( is_cl_supported_in_common(l_supported_cls, l_desired_cas_latency),
- "%s. Failed to find a common CAS latency supported among all modules", mss::c_str(iv_target) );
+ l_is_cl_in_common = is_cl_supported_in_common(iv_common_cl, l_desired_cas_latency);
+
+ while( !l_is_cl_in_common && (l_desired_cas_latency < l_max_cl) )
+ {
+ ++l_desired_cas_latency;
+ l_is_cl_in_common = is_cl_supported_in_common(iv_common_cl, l_desired_cas_latency);
+
+ }
+
+ // If no such value exists, choose a higher tCKproposed value and repeat until a solution is found.
+ if(!l_is_cl_in_common)
+ {
+ FAPI_INF("Desired CL isn't supported by all DIMMs, choosing a higher tCK");
+ continue;
+ }
// Once the calculation of CLactual is completed
// verify that this CAS Latency value does not exceed tAAmax.
- FAPI_TRY( is_cl_exceeding_taa_max (l_desired_cas_latency, iv_proposed_tck),
- "%s. Failed to find a CL value that doesn't exceed tAAmax", mss::c_str(iv_target) );
- }
+ l_is_cl_exceeding_taa = is_cl_exceeding_taa_max (l_desired_cas_latency, iv_proposed_tck);
+
+ // If not, choose a lower CL value and repeat until a solution is found.
+ while( l_is_cl_exceeding_taa && (l_desired_cas_latency > l_min_cl) )
+ {
+ --l_desired_cas_latency;
+ l_is_cl_exceeding_taa = is_cl_exceeding_taa_max (l_desired_cas_latency, iv_proposed_tck);
+ }
+
+ l_is_cl_in_common = is_cl_supported_in_common(iv_common_cl, l_desired_cas_latency);
+
+ }// end while
+
+ FAPI_ASSERT( !l_is_cl_exceeding_taa,
+ fapi2::MSS_CL_EXCEEDS_TAA_MAX()
+ .set_CAS_LATENCY(l_desired_cas_latency)
+ .set_TCK(iv_proposed_tck)
+ .set_COMPARE(l_desired_cas_latency * iv_proposed_tck)
+ .set_TAA_MAX(iv_largest_taamin)
+ .set_IS_3DS(iv_is_3ds),
+ "%s: Calculated Cas Latency (CL %d * tCK %d) exceeds JEDEC value of tAAmax %d",
+ mss::c_str(iv_target),
+ l_desired_cas_latency, iv_proposed_tck, iv_largest_taamin);
+
+ // If the cas_latency wasn't found, we return an error
+ // Passing in timing values which were used to calculated i_cas_latency for extra info
+ // iv_common_cl contains all of the valid cas latencies that populate the input vector
+ FAPI_ASSERT( l_is_cl_in_common,
+ fapi2::MSS_FAILED_TO_FIND_SUPPORTED_CL()
+ .set_DESIRED_CAS_LATENCY(l_desired_cas_latency)
+ .set_TAA(iv_largest_taamin)
+ .set_TCK(iv_proposed_tck)
+ .set_COMMON_CLS(iv_common_cl_bitmap)
+ .set_MCA_TARGET(iv_target),
+ "%s. Failed to find a common CAS latency supported among all modules"
+ "Desired %d, common CL's %016lx",
+ mss::c_str(iv_target),
+ l_desired_cas_latency,
+ iv_common_cl_bitmap);
// Update output values after all criteria is met
- // If the MCA has no dimm configured than both
- // l_desired_latency & iv_proposed_tck is 0 by initialization
o_cas_latency = l_desired_cas_latency;
o_tck = iv_proposed_tck;
@@ -271,10 +311,10 @@ fapi_try_exit:
}
///
-/// @brief Retrieves SDRAM Minimum CAS Latency Time (tAAmin) from SPD
-/// @param[in] i_pDecoder the SPD decoder
+/// @brief Retrieves SDRAM Minimum CAS Latency Time (tAAmin) from SPD
+/// @param[in] i_pDecoder the SPD decoder
/// @param[out] o_value tCKmin value in ps
-/// @return FAPI2_RC_SUCCESS iff ok
+/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode cas_latency::get_taamin( const std::shared_ptr<mss::spd::decoder>& i_pDecoder,
uint64_t& o_value )
@@ -284,15 +324,18 @@ fapi2::ReturnCode cas_latency::get_taamin( const std::shared_ptr<mss::spd::decod
int64_t l_medium_timebase = 0;
int64_t l_fine_timebase = 0;
int64_t l_temp = 0;
+
// Retrieve timing parameters
+ const auto l_target = i_pDecoder->iv_target;
+
FAPI_TRY( i_pDecoder->medium_timebase(l_medium_timebase),
- "%s. Failed medium_timebase()", mss::c_str(iv_target) );
+ "%s. Failed medium_timebase()", mss::c_str(l_target) );
FAPI_TRY( i_pDecoder->fine_timebase(l_fine_timebase),
- "%s. Failed fine_timebase()", mss::c_str(iv_target) );
+ "%s. Failed fine_timebase()", mss::c_str(l_target) );
FAPI_TRY( i_pDecoder->min_taa(l_timing_mtb),
- "%s. Failed min_taa()", mss::c_str(iv_target) );
+ "%s. Failed min_taa()", mss::c_str(l_target) );
FAPI_TRY( i_pDecoder->fine_offset_min_taa(l_timing_ftb),
- "%s. Failed fine_offset_min_taa()", mss::c_str(iv_target) );
+ "%s. Failed fine_offset_min_taa()", mss::c_str(l_target) );
// Calculate timing value
l_temp = spd::calc_timing_from_timebase(l_timing_mtb,
@@ -304,127 +347,28 @@ fapi2::ReturnCode cas_latency::get_taamin( const std::shared_ptr<mss::spd::decod
FAPI_ASSERT(l_temp > 0,
fapi2::MSS_INVALID_TIMING_VALUE().
set_VALUE(o_value).
- set_FUNCTION(TAAMIN).
- set_DIMM_TARGET(iv_target),
+ set_FUNCTION(GET_TAAMIN).
+ set_DIMM_TARGET(l_target),
"%s. tAAmin invalid (<= 0) : %d",
- mss::c_str(iv_target),
+ mss::c_str(l_target),
l_temp);
o_value = l_temp;
FAPI_INF( "%s. tAAmin (ps): %d",
- mss::c_str(iv_target),
+ mss::c_str(l_target),
o_value);
-fapi_try_exit:
- return fapi2::current_err;
-}
-
-///
-/// @brief Retrieves SDRAM Minimum Cycle Time (tCKmin) from SPD
-/// @param[in] i_pDecoder the SPD decoder
-/// @param[out] o_value tCKmin value in ps
-/// @return FAPI2_RC_SUCCESS iff ok
-///
-fapi2::ReturnCode cas_latency::get_tckmin( const std::shared_ptr<mss::spd::decoder>& i_pDecoder,
- uint64_t& o_value )
-{
- int64_t l_timing_ftb = 0;
- int64_t l_timing_mtb = 0;
- int64_t l_medium_timebase = 0;
- int64_t l_fine_timebase = 0;
- int64_t l_temp = 0;
-
- // Retrieve timing parameters
- FAPI_TRY( i_pDecoder->medium_timebase(l_medium_timebase),
- "%s. Failed medium_timebase()", mss::c_str(iv_target) );
- FAPI_TRY( i_pDecoder->fine_timebase(l_fine_timebase),
- "%s. Failed fine_timebase()", mss::c_str(iv_target) );
- FAPI_TRY( i_pDecoder->min_tck(l_timing_mtb),
- "%s. Failed min_tck()", mss::c_str(iv_target) );
- FAPI_TRY( i_pDecoder->fine_offset_min_tck(l_timing_ftb),
- "%s. Failed fine_offset_min_tck()", mss::c_str(iv_target) );
-
- // Calculate timing value
- l_temp = spd::calc_timing_from_timebase(l_timing_mtb,
- l_medium_timebase,
- l_timing_ftb,
- l_fine_timebase);
-
- // Sanity check
- FAPI_ASSERT(l_temp > 0,
- fapi2::MSS_INVALID_TIMING_VALUE().
- set_VALUE(l_temp).
- set_FUNCTION(TCKMIN).
- set_DIMM_TARGET(iv_target),
- "%s. tCKmin invalid (<= 0) : %d",
- mss::c_str(iv_target),
- l_temp);
-
- o_value = l_temp;
-
- FAPI_INF("%s. tCKmin (ps): %d",
- mss::c_str(iv_target),
- o_value );
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
-///
-/// @brief Retrieves SDRAM Maximum Cycle Time (tCKmax) from SPD
-/// @param[in] i_pDecoder SPD decoder
-/// @param[out] o_value tCKmax value in ps
-/// @return FAPI2_RC_SUCCESS iff ok
-///
-fapi2::ReturnCode cas_latency::get_tckmax( const std::shared_ptr<mss::spd::decoder>& i_pDecoder,
- uint64_t& o_value )
-{
- int64_t l_timing_ftb = 0;
- int64_t l_timing_mtb = 0;
- int64_t l_medium_timebase = 0;
- int64_t l_fine_timebase = 0;
- int64_t l_temp = 0;
- // Retrieve timing parameters
- FAPI_TRY( i_pDecoder->medium_timebase(l_medium_timebase),
- "%s. Failed medium_timebase()", mss::c_str(iv_target) );
- FAPI_TRY( i_pDecoder->fine_timebase(l_fine_timebase),
- "%s. Failed fine_timebase()", mss::c_str(iv_target) );
- FAPI_TRY( i_pDecoder->max_tck(l_timing_mtb),
- "%s. Failed max_tck()", mss::c_str(iv_target) );
- FAPI_TRY( i_pDecoder->fine_offset_max_tck(l_timing_ftb),
- "%s. Failed fine_offset_max_tck()", mss::c_str(iv_target) );
-
- // Calculate timing value
- l_temp = spd::calc_timing_from_timebase(l_timing_mtb,
- l_medium_timebase,
- l_timing_ftb,
- l_fine_timebase);
-
- // Sanity check
- FAPI_ASSERT(l_temp > 0,
- fapi2::MSS_INVALID_TIMING_VALUE().
- set_VALUE(l_temp).
- set_FUNCTION(TCKMAX).
- set_DIMM_TARGET(iv_target),
- "%s. tCKmax invalid (<= 0) : %d",
- mss::c_str(iv_target),
- l_temp);
-
- o_value = l_temp;
-
- FAPI_INF( "%s. tCKmax (ps): %d",
- mss::c_str(iv_target),
- o_value);
+ return fapi2::FAPI2_RC_SUCCESS;
fapi_try_exit:
return fapi2::current_err;
}
///
-/// @brief Gets max CAS latency (CL) for the appropriate High/Low Range
-/// @param[in] i_supported_cl
-/// @return the maximum supported CL
-/// @note Depends on bit 7 of byte 23 from the DDR4 SPD
+/// @brief Gets max CAS latency (CL) for the appropriate High/Low Range
+/// @param[in] i_supported_cl
+/// @return the maximum supported CL
+/// @note Depends on bit 7 of byte 23 from the DDR4 SPD
///
inline uint64_t cas_latency::get_max_cl(const fapi2::buffer<uint64_t> i_supported_cl) const
{
@@ -438,10 +382,10 @@ inline uint64_t cas_latency::get_max_cl(const fapi2::buffer<uint64_t> i_supporte
}
///
-/// @brief Gets min CAS latency (CL) for the appropriate High/Low Range
-/// @param[in] i_supported_cl
-/// @return the minimum supported CL
-/// @note Depends on bit 7 of byte 23 from the DDR4 SPD
+/// @brief Gets min CAS latency (CL) for the appropriate High/Low Range
+/// @param[in] i_supported_cl
+/// @return the minimum supported CL
+/// @note Depends on bit 7 of byte 23 from the DDR4 SPD
///
inline uint64_t cas_latency::get_min_cl(const fapi2::buffer<uint64_t>& i_supported_cl) const
{
@@ -456,10 +400,10 @@ inline uint64_t cas_latency::get_min_cl(const fapi2::buffer<uint64_t>& i_support
///
/// @brief Calculates CAS latency time from tCK and tAA
-/// @param[in] i_taa cas latency time
-/// @param[in] i_tck min cycle time
+/// @param[in] i_taa cas latency time
+/// @param[in] i_tck min cycle time
/// @param[out] o_cas_latency calculated CAS latency
-/// @return FAPI2_RC_SUCCESS iff okay
+/// @return FAPI2_RC_SUCCESS iff okay
///
inline fapi2::ReturnCode cas_latency::calc_cas_latency(const uint64_t i_taa,
const uint64_t i_tck,
@@ -478,26 +422,26 @@ fapi_try_exit:
}
///
-/// @brief Helper function to create a vector of supported CAS latencies from a bitmap
-/// @param[in] i_common_cl common CAS latency bitmap
-/// @return vector of supported CAS latencies
+/// @brief Helper function to create a vector of supported CAS latencies from a bitmap
+/// @param[in] i_common_cl common CAS latency bitmap
+/// @return vector of supported CAS latencies
///
std::vector<uint64_t> cas_latency::integral_bitmap_to_vector(const uint64_t i_common_cl) const
{
std::vector<uint64_t> l_vector;
fapi2::buffer<uint64_t> l_cl_mask(i_common_cl);
- uint64_t min_cl = get_min_cl(l_cl_mask);
- uint64_t max_cl = get_max_cl(l_cl_mask);
+ const uint64_t l_min_cl = get_min_cl(l_cl_mask);
+ const uint64_t l_max_cl = get_max_cl(l_cl_mask);
- FAPI_INF("%s. min CL %lu", mss::c_str(iv_target), min_cl);
- FAPI_INF("%s. max CL %lu", mss::c_str(iv_target), max_cl);
+ FAPI_INF("%s. min CL %lu", mss::c_str(iv_target), l_min_cl);
+ FAPI_INF("%s. max CL %lu", mss::c_str(iv_target), l_max_cl);
- for(uint64_t l_cas_latency = min_cl; l_cas_latency <= max_cl; ++l_cas_latency)
+ for(uint64_t l_cas_latency = l_min_cl; l_cas_latency <= l_max_cl; ++l_cas_latency)
{
// 64 bit is buffer length - indexed at 0 - 63
constexpr uint64_t l_buffer_length = 64 - 1;
- uint64_t l_bit_pos = l_buffer_length - (l_cas_latency - min_cl);
+ uint64_t l_bit_pos = l_buffer_length - (l_cas_latency - l_min_cl);
// Traversing through buffer one bit at a time
// 0 means unsupported CAS latency
@@ -506,8 +450,8 @@ std::vector<uint64_t> cas_latency::integral_bitmap_to_vector(const uint64_t i_co
if( l_cl_mask.getBit(l_bit_pos) )
{
// I want don't this to print all the time, DBG is fine
- FAPI_DBG( "%s. Supported CL (%d) from common CL mask",
- mss::c_str(iv_target), l_cas_latency );
+ FAPI_DBG( "%s. Supported CL (%d) from common CL mask (0x%llX)",
+ mss::c_str(iv_target), l_cas_latency, i_common_cl );
l_vector.push_back(l_cas_latency);
}
@@ -517,85 +461,44 @@ std::vector<uint64_t> cas_latency::integral_bitmap_to_vector(const uint64_t i_co
}
///
-/// @brief Determines if a requested CAS latency (CL) is supported in the bin of common CLs
-/// @param[in] i_common_cls vector of common CAS latencies
-/// @param[in] i_cas_latency CAS latency we are comparing against
-/// @return FAPI2_RC_SUCCESS iff ok
+/// @brief Determines if a requested CAS latency (CL) is supported in the bin of common CLs
+/// @param[in] i_common_cls vector of common CAS latencies (must be sorted)
+/// @param[in] i_cas_latency CL we are comparing against
+/// @return true iff desired CL was found in the bitmap of common CLs, false otherwise
///
-inline fapi2::ReturnCode cas_latency::is_cl_supported_in_common(const std::vector<uint64_t>& i_common_cls,
+inline bool cas_latency::is_cl_supported_in_common(const std::vector<uint64_t>& i_common_cls,
const uint64_t i_cas_latency) const
{
- fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
+ const bool l_found = std::binary_search(i_common_cls.begin(), i_common_cls.end(), i_cas_latency);
- // Grabbing freq info for ffdc
- std::vector<uint32_t> l_mrw_freqs(NUM_MRW_FREQS, 0);
- std::vector<uint32_t> l_max_freqs(NUM_MAX_FREQS, 0);
+ FAPI_INF("Found CL: %d in common CL mask: 0x%llX ? %s for %s",
+ i_cas_latency, iv_common_cl_bitmap, l_found ? "yes" : "no", mss::c_str(iv_target));
- FAPI_TRY( mss::mrw_supported_freq(l_mrw_freqs.data()) );
- FAPI_TRY( mss::max_allowed_dimm_freq(l_max_freqs.data()) );
-
- // If the cas_latency wasn't found, we return an error
- // Passing in timing values which were used to calculated i_cas_latency for extra info
- // iv_common_cl contains all of the valid cas latencies that populate the input vector
- FAPI_ASSERT( std::binary_search(i_common_cls.begin(), i_common_cls.end(), i_cas_latency),
- fapi2::MSS_FAILED_TO_FIND_SUPPORTED_CL()
- .set_DESIRED_CAS_LATENCY(i_cas_latency)
- .set_TAA(iv_largest_taamin)
- .set_TCK(iv_proposed_tck)
- .set_COMMON_CLS(iv_common_cl)
- .set_MSS_MRW_FREQ_0(l_mrw_freqs[0])
- .set_MSS_MRW_FREQ_1(l_mrw_freqs[1])
- .set_MSS_MRW_FREQ_2(l_mrw_freqs[2])
- .set_MSS_MRW_FREQ_3(l_mrw_freqs[3])
- .set_MSS_MAX_FREQ_0(l_max_freqs[0])
- .set_MSS_MAX_FREQ_1(l_max_freqs[1])
- .set_MSS_MAX_FREQ_2(l_max_freqs[2])
- .set_MSS_MAX_FREQ_3(l_max_freqs[3])
- .set_MSS_MAX_FREQ_4(l_max_freqs[4])
- .set_MCA_TARGET(iv_target),
- "%s. Failed to find a common CAS latency supported among all modules"
- "Desired %d, common CL's %016lx",
- mss::c_str(iv_target),
- i_cas_latency,
- iv_common_cl);
-fapi_try_exit:
- return fapi2::current_err;
+ return l_found;
}
///
-/// @brief Checks that CAS latency doesn't exceed largest CAS latency time
-/// @param[in] i_cas_latency cas latency
-/// @param[in] i_tck cycle time
-/// @return FAPI2_RC_SUCCESS iff ok
+/// @brief Checks that CAS latency doesn't exceed largest CAS latency time
+/// @param[in] i_cas_latency cas latency
+/// @param[in] i_tck cycle time
+/// @return true iff CL exceeds tAAmax, false otherwise
///
-inline fapi2::ReturnCode cas_latency::is_cl_exceeding_taa_max(const uint64_t i_cas_latency,
+inline bool cas_latency::is_cl_exceeding_taa_max(const uint64_t i_cas_latency,
const uint64_t i_tck) const
{
- fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
// JEDEC SPD spec requirement
const size_t l_taa_max = (iv_is_3ds == loading::NOT_3DS) ? TAA_MAX_DDR4 : TAA_MAX_DDR4_3DS;
+ const bool l_is_cl_exceeding_taa = (i_cas_latency * i_tck) > l_taa_max;
- FAPI_INF("%s. CL (%d) * tCK (%d) = %d > %d",
+ FAPI_INF("%s. CL (%d) * tCK (%d) = %d > %d ? %s",
mss::c_str(iv_target),
i_cas_latency,
i_tck,
i_cas_latency * i_tck,
- l_taa_max);
+ l_taa_max,
+ l_is_cl_exceeding_taa ? "yes" : "no");
- FAPI_ASSERT( ((i_cas_latency * i_tck) <= l_taa_max),
- fapi2::MSS_CL_EXCEEDS_TAA_MAX()
- .set_CAS_LATENCY(i_cas_latency)
- .set_TCK(i_tck)
- .set_COMPARE(i_cas_latency * i_tck)
- .set_TAA_MAX(l_taa_max)
- .set_IS_3DS(iv_is_3ds),
- "%s: Calculated Cas Latency (i_cas_latency %d * i_tck %d) exceeds JEDEC value of TAA MAX %d",
- mss::c_str(iv_target),
- i_cas_latency,
- i_tck,
- l_taa_max);
-fapi_try_exit:
- return fapi2::current_err;
+ return l_is_cl_exceeding_taa;
}
}// mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.H b/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.H
index c4b1e82c5..6c9ad087c 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/freq/cas_latency.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -46,6 +46,8 @@
// mss lib
#include <generic/memory/lib/spd/common/ddr4/spd_decoder_ddr4.H>
+#include <lib/utils/conversions.H>
+#include <lib/freq/sync.H>
namespace mss
{
@@ -60,6 +62,50 @@ enum class loading : size_t
IS_3DS,
};
+enum freq_select : uint8_t
+{
+ BIN_DOWN, ///< option to bin down frequency
+ HIGHEST_COMMON ///< option to find highest common freq w/o bin down - useful for testing
+};
+
+///
+/// @brief Returns the iterator if a given freq is found
+/// @tparam T the freq_select type
+/// @param[in] i_supported_freqs a vector of sorted frequences
+/// @param[im] i_dimm_freq current dimm speed
+/// @return FAPI2_RC_SUCESS iff okay
+///
+template< freq_select T >
+static inline std::vector<uint32_t>::const_iterator search_list( const std::vector<uint32_t>& i_supported_freqs,
+ const uint32_t i_dimm_freq);
+
+///
+/// @brief Returns the iterator if a given freq is found - BIN_DOWN specialization
+/// @param[in] i_supported_freqs a vector of sorted frequences
+/// @param[in] i_dimm_freq current dimm speed
+/// @return FAPI2_RC_SUCESS iff okay
+///
+template< >
+inline std::vector<uint32_t>::const_iterator search_list<BIN_DOWN>( const std::vector<uint32_t>& i_supported_freqs,
+ const uint32_t i_dimm_freq)
+{
+ return std::lower_bound(i_supported_freqs.begin(), i_supported_freqs.end(), i_dimm_freq);
+}
+
+///
+/// @brief Returns the iterator if a given freq is found - HIGHEST_COMMON specialization
+/// @param[in] i_supported_freqs a vector of sorted frequences
+/// param[in] i_dimm_freq current dimm speed
+/// @return FAPI2_RC_SUCESS iff okay
+///
+template< >
+inline std::vector<uint32_t>::const_iterator search_list<HIGHEST_COMMON>( const std::vector<uint32_t>&
+ i_supported_freqs,
+ const uint32_t i_dimm_freq)
+{
+ return std::upper_bound(i_supported_freqs.begin(), i_supported_freqs.end(), i_dimm_freq);
+}
+
///
/// @class cas_latency
/// @brief CAS latency class that encapsulates JEDEC calculation algorithm
@@ -79,28 +125,34 @@ class cas_latency
cas_latency() = delete;
///
- /// @brief Class constructor that retrieves required SPD data held by internal state
- /// @param[in] i_target the controller target
- /// @param[in] i_caches decoder caches
+ /// @brief Class constructor that retrieves required SPD data held by internal state
+ /// @param[in] i_target the controller target
+ /// @param[in] i_caches decoder caches
+ /// @param[in] i_supported_freqs vector of supported frequencies
/// @param[out] o_rc returns FAPI2_RC_SUCCESS if constructor initialzed successfully
///
cas_latency(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target_mcs,
const std::vector< std::shared_ptr<spd::decoder> >& i_caches,
+ const std::vector<uint32_t>& i_supported_freqs,
fapi2::ReturnCode& o_rc);
///
- /// @brief Constructor that allows the user to set desired data in lieu of SPD
- /// @param[in] i_target the controller target
- /// @param[in] i_taa_min largest tAAmin we want to set in picoseconds
- /// @param[in] i_tck_min proposed tCKmin in picoseconds
- /// @param[in] i_common_cl_mask common CAS latency mask we want to use (bitmap)
- /// @param[in] i_is_3ds loading::IS_3DS if this is for 3DS, loading::NOT_3DS otherwise
+ /// @brief Constructor that allows the user to set desired data in lieu of SPD - helpful for testing
+ /// @param[in] i_target the controller target
+ /// @param[in] i_taa_min largest tAAmin we want to set in picoseconds
+ /// @param[in] i_tck_min proposed tCKmin in picoseconds
+ /// @param[in] i_common_cl_mask common CAS latency mask we want to use (bitmap)
+ /// @param[in] i_is_3ds loading::IS_3DS if this is for 3DS, loading::NOT_3DS otherwise
+ /// @param[in] i_req_sync_mode required synchronous mode -- defaulted to SYNCH_MODE_UNDETERMINED,
+ /// @param[in] i_supported_freqs vector of supported frequencies -- defaulted to NIMBUS_SUPPORTED_FREQS
///
cas_latency(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
const uint64_t i_taa_min,
const uint64_t i_tck_min,
const uint64_t i_common_cl_mask,
- const loading i_is_3ds);
+ const loading i_is_3ds,
+ const uint8_t i_req_sync_mode = fapi2::ENUM_ATTR_REQUIRED_SYNCH_MODE_UNDETERMINED,
+ const std::vector<uint32_t>& i_supported_freqs = NIMBUS_SUPPORTED_FREQS);
///
/// @brief Default destructor
@@ -108,14 +160,83 @@ class cas_latency
~cas_latency() = default;
///
- /// @brief Calculates CAS latency and checks if it is supported and within JEDEC spec.
+ /// @brief Calculates CAS latency and checks if it is supported and within JEDEC spec.
/// @param[out] o_cas_latency selected CAS latency
/// @param[out] o_tck cycle time corresponding to seleted CAS latency
- /// @return fapi2::FAPI2_RC_SUCCESS if ok
+ /// @return fapi2::FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode find_cl(uint64_t& o_cas_latency,
uint64_t& o_tck);
+ ///
+ /// @brief Selects DIMM frequency to run based on supported system frequencies -- helper function for testing
+ /// @tparam TT the freq_select type
+ /// @param[in] i_supported_freqs vector supported frequencies
+ /// @param[in,out] io_dimm_freq input is current dimm freq & output is next
+ /// lowest dimm freq between 1866 MT/s - 2666 MT/s
+ /// @return FAPI2_RC_SUCCESS iff ok
+ /// @note Frequency values obtained from:
+ /// @note From P9 User's Manual Version 0.8 - June 08, 2015
+ /// @note Memory Controller Unit - page 199 of 456
+ ///
+ template< freq_select TT >
+ inline fapi2::ReturnCode select_supported_freq_helper( const std::vector<uint32_t>& i_supported_freqs,
+ uint64_t& io_dimm_freq)
+ {
+ FAPI_ASSERT( !i_supported_freqs.empty(),
+ fapi2::MSS_EMPTY_VECTOR().
+ set_FUNCTION(SELECT_SUPPORTED_FREQ).
+ set_TARGET(iv_target),
+ "Empty supported frequency vector received for %s",
+ mss::c_str(iv_target));
+
+ for( const auto& freq : i_supported_freqs )
+ {
+ FAPI_DBG("Supported freqs taking into account VPD, SPD, & MRW constraints %d for %s", freq, mss::c_str(iv_target) );
+ }
+
+ FAPI_DBG("Input frequency %d for %s", io_dimm_freq, mss::c_str(iv_target) );
+ {
+ auto l_iterator = search_list<TT>(i_supported_freqs, io_dimm_freq);
+
+ // Doing this because the HB compiler freaks out if we have it within the FAPI_ASSERT.
+ // Outputting the value and then incrementing the iterator, that's why it's a post increment
+ // We have at most 4 memory freqs (1866, 2133, 2400, & 2666), if we ever get a list with < 4 items
+ // a value of 0 is logged in FFDC once we hit i_supported_freqs.end()...which is better than no logging.
+ auto l_supported = i_supported_freqs.begin();
+
+ const auto l_freq0 = (l_supported != i_supported_freqs.end()) ? *(l_supported++) : 0;
+ const auto l_freq1 = (l_supported != i_supported_freqs.end()) ? *(l_supported++) : 0;
+ const auto l_freq2 = (l_supported != i_supported_freqs.end()) ? *(l_supported++) : 0;
+ const auto l_freq3 = (l_supported != i_supported_freqs.end()) ? *(l_supported++) : 0;
+
+ // We can't choose a lower freq than the 1st element of this vector,
+ // hitting this case means that we exhausted all possible frequencies
+ FAPI_ASSERT( l_iterator != i_supported_freqs.begin(),
+ fapi2::MSS_SELECTED_FREQ_NOT_SUPPORTED()
+ .set_FREQ(io_dimm_freq)
+ .set_SUPPORTED_FREQ_0( l_freq0 )
+ .set_SUPPORTED_FREQ_1( l_freq1 )
+ .set_SUPPORTED_FREQ_2( l_freq2 )
+ .set_SUPPORTED_FREQ_3( l_freq3 )
+ .set_TARGET(iv_target),
+ "%s Error finding selected freq (%d) from list",
+ mss::c_str(iv_target),
+ io_dimm_freq );
+
+ // Lower bound checks for greater than or equal to input freq,
+ // we decrement to get the next lowest freq
+ io_dimm_freq = *(--l_iterator);
+
+ FAPI_DBG("Output frequency %d for %s", io_dimm_freq, mss::c_str(iv_target) );
+ }
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+
private:
enum
@@ -147,89 +268,131 @@ class cas_latency
fapi2::Target<fapi2::TARGET_TYPE_MCA> iv_target;
uint64_t iv_largest_taamin;// cas latency time
uint64_t iv_proposed_tck;// cycle time
- uint64_t iv_common_cl; // common cas latency
loading iv_is_3ds;
+ uint64_t iv_common_cl_bitmap;
+ bool iv_enable_freq_overrides;
+ std::vector<uint64_t> iv_common_cl; // common cas latency
+ uint8_t iv_req_sync_mode;
+ std::vector<uint32_t> iv_supported_freqs;
///
- /// @brief Retrieves SDRAM Minimum CAS Latency Time (tAAmin) from SPD
- /// @param[in] i_pDecoder the SPD decoder
+ /// @brief Retrieves SDRAM Minimum CAS Latency Time (tAAmin) from SPD
+ /// @param[in] i_pDecoder the SPD decoder
/// @param[out] o_value tCKmin value in ps
- /// @return FAPI2_RC_SUCCESS iff ok
+ /// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode get_taamin(const std::shared_ptr<mss::spd::decoder>& i_pDecoder,
uint64_t& o_value);
+
///
- /// @brief Retrieves SDRAM Minimum Cycle Time (tCKmin) from SPD
- /// @param[in] i_pDecoder the SPD decoder
- /// @param[out] o_value tCKmin value in ps
- /// @return FAPI2_RC_SUCCESS iff ok
+ /// @brief Gets max CAS latency (CL) for the appropriate High/Low Range
+ /// @param[in] i_supported_cl
+ /// @return the maximum supported CL
+ /// @note Depends on bit 7 of byte 23 from the DDR4 SPD
///
- fapi2::ReturnCode get_tckmin(const std::shared_ptr<mss::spd::decoder>& i_pDecoder,
- uint64_t& o_value);
+ uint64_t get_max_cl(const fapi2::buffer<uint64_t> i_supported_cl) const;
///
- /// @brief Retrieves SDRAM Maximum Cycle Time (tCKmax) from SPD
- /// @param[in] i_pDecoder SPD decoder
- /// @param[out] o_value tCKmax value in ps
- /// @return FAPI2_RC_SUCCESS iff ok
+ /// @brief Gets min CAS latency (CL) for the appropriate High/Low Range
+ /// @param[in] i_supported_cl
+ /// @return the minimum supported CL
+ /// @note Depends on bit 7 of byte 23 from the DDR4 SPD
///
- fapi2::ReturnCode get_tckmax(const std::shared_ptr<mss::spd::decoder>& i_pDecoder,
- uint64_t& o_value);
+ uint64_t get_min_cl(const fapi2::buffer<uint64_t>& i_supported_cl) const;
///
- /// @brief Gets max CAS latency (CL) for the appropriate High/Low Range
- /// @param[in] i_supported_cl
- /// @return the maximum supported CL
- /// @note Depends on bit 7 of byte 23 from the DDR4 SPD
+ /// @brief Calculates CAS latency time from tCK and tAA
+ /// @param[in] i_taa cas latency time
+ /// @param[in] i_tck min cycle time
+ /// @param[out] o_cas_latency calculated CAS latency
+ /// @return FAPI2_RC_SUCCESS iff okay
///
- inline uint64_t get_max_cl(const fapi2::buffer<uint64_t> i_supported_cl) const;
+ fapi2::ReturnCode calc_cas_latency(const uint64_t i_taa,
+ const uint64_t i_tck,
+ uint64_t& o_cas_latency) const;
///
- /// @brief Gets min CAS latency (CL) for the appropriate High/Low Range
- /// @param[in] i_supported_cl
- /// @return the minimum supported CL
- /// @note Depends on bit 7 of byte 23 from the DDR4 SPD
+ /// @brief Helper function to create a vector of supported CAS latencies from a bitmap
+ /// @param[in] i_common_cl common CAS latency bitmap
+ /// @return vector of supported CAS latencies
///
- inline uint64_t get_min_cl(const fapi2::buffer<uint64_t>& i_supported_cl) const;
+ std::vector<uint64_t> integral_bitmap_to_vector(const uint64_t i_bitmap) const;
///
- /// @brief Calculates CAS latency time from tCK and tAA
- /// @param[in] i_taa cas latency time
- /// @param[in] i_tck min cycle time
- /// @param[out] o_cas_latency calculated CAS latency
- /// @return FAPI2_RC_SUCCESS iff okay
+ /// @brief Determines if a requested CAS latency (CL) is supported in the bin of common CLs
+ /// @param[in] i_common_cls vector of common CAS latencies
+ /// @param[in] i_cas_latency CAS latency we are comparing against
+ /// @return true iff desired CL was found in the bitmap of common CLs, false otherwise
///
- inline fapi2::ReturnCode calc_cas_latency(const uint64_t i_taa,
- const uint64_t i_tck,
- uint64_t& o_cas_latency) const;
+ bool is_cl_supported_in_common(const std::vector<uint64_t>& i_common_cls,
+ const uint64_t i_cas_latency) const;
///
- /// @brief Helper function to create a vector of supported CAS latencies from a bitmap
- /// @param[in] i_common_cl common CAS latency bitmap
- /// @return vector of supported CAS latencies
+ /// @brief Checks that CAS latency doesn't exceed largest CAS latency time
+ /// @param[in] i_cas_latency cas latency
+ /// @param[in] i_tck cycle time
+ /// @return true iff CL exceeds tAAmax, false otherwise
///
- std::vector<uint64_t> integral_bitmap_to_vector(const uint64_t i_bitmap) const;
+ bool is_cl_exceeding_taa_max(const uint64_t i_cas_latency,
+ const uint64_t i_tck) const;
///
- /// @brief Determines if a requested CAS latency (CL) is supported in the bin of common CLs
- /// @param[in] i_common_cls vector of common CAS latencies
- /// @param[in] i_cas_latency CAS latency we are comparing against
- /// @return fapi2::FAPI2_RC_SUCCESS if ok
+ /// @brief Selects DIMM frequency to run based on supported system frequencies
+ /// @tparam TT the freq_select type
+ /// @param[in,out] io_dimm_freq input is current dimm freq & output is next
+ /// lowest dimm freq between 1866 MT/s - 2666 MT/s
+ /// @return FAPI2_RC_SUCCESS iff ok
+ /// @note Frequency values obtained from:
+ /// @note From P9 User's Manual Version 0.8 - June 08, 2015
+ /// @note Memory Controller Unit - page 199 of 456
///
- inline fapi2::ReturnCode is_cl_supported_in_common(const std::vector<uint64_t>& i_common_cls,
- const uint64_t i_cas_latency) const;
+ template< freq_select TT >
+ inline fapi2::ReturnCode select_supported_freq(uint64_t& io_dimm_freq)
+ {
+ FAPI_TRY( (select_supported_freq_helper<TT>(iv_supported_freqs, io_dimm_freq)) );
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
///
- /// @brief Checks that CAS latency doesn't exceed largest CAS latency time
- /// @param[in] i_cas_latency cas latency
- /// @param[in] i_tck cycle time
- /// @return fapi2::FAPI2_RC_SUCCESS if ok
+ /// @brief Limits tCK to system constraints (VPD and MRW)
+ /// @tparam T freq_select type
+ /// @param[in,out] io_tck input is current tCK, output is highest supported tCK (HIGHEST_COMMON specialization)
+ /// or the next highest supported tCK (BIN_DOWN specialization)
+ /// @return FAPI2_RC_SUCCESS iff okay
///
- inline fapi2::ReturnCode is_cl_exceeding_taa_max(const uint64_t i_cas_latency,
- const uint64_t i_tck) const;
+ template< freq_select T >
+ fapi2::ReturnCode apply_freq_constraints(uint64_t& io_tck)
+ {
+ uint64_t l_proposed_freq = 0;
+ FAPI_TRY( mss::ps_to_freq(io_tck, l_proposed_freq) );
-};// cas_latency
+ FAPI_TRY( (select_supported_freq<T>(l_proposed_freq)),
+ "%s. Failed select_supported_freq()", mss::c_str(iv_target) );
+
+ FAPI_TRY( freq_to_ps(l_proposed_freq, io_tck),
+ "%s. Failed freq_to_ps()", mss::c_str(iv_target) );
+ FAPI_INF("%s Supported dimm speed override %d MT/s (Clock period %d in ps)",
+ mss::c_str(iv_target), l_proposed_freq, io_tck);
+
+ // Sanity check
+ FAPI_ASSERT(io_tck > 0,
+ fapi2::MSS_INVALID_CALCULATED_TCK().
+ set_TAAMIN(iv_largest_taamin).
+ set_PROPOSED_TCK(io_tck).
+ set_IS_3DS(iv_is_3ds).
+ set_MCA_TARGET(iv_target),
+ "%s. Invalid calculated clock period(<= 0 nCK) : %d",
+ mss::c_str(iv_target),
+ io_tck);
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+
+};// cas_latency
}// mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.C b/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.C
index 2c0338b64..4e2930711 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -28,19 +28,21 @@
/// @brief Synchronous function implementations
///
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
-// *HWP HWP Backup: Jacob Harvey <jlharvey@us.ibm.com>
+// *HWP HWP Backup: Louis Stermole <stermole@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: HB:FSP
-#include <vector>
-#include <map>
-
#include <fapi2.H>
+#include <vpd_access.H>
+#include <algorithm>
+#include <vector>
+#include <map>
#include <mss.H>
#include <lib/freq/sync.H>
#include <generic/memory/lib/utils/find.H>
#include <lib/utils/assert_noexit.H>
+#include <lib/spd/spd_factory.H>
using fapi2::TARGET_TYPE_DIMM;
using fapi2::TARGET_TYPE_MCS;
@@ -310,59 +312,231 @@ fapi_try_exit:
}
///
+/// @brief Return whether a given freq is supported
+/// @param[in] a freq to check for
+/// @param[in] reference to a std::vector of supported freqs (sorted)
+/// @return bool, true iff input freq is supported
+///
+bool is_freq_supported(const uint32_t i_freq, const std::vector<uint32_t>& i_freqs)
+{
+ return std::binary_search(i_freqs.begin(), i_freqs.end(), i_freq);
+}
+
+///
+/// @brief Create a vector of support freq based on VPD config
+/// @param[in] MCBIST target for which to get the DIMM configs
+/// @param[out] reference to a std::vector of supported VPD frequencies
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode vpd_supported_freqs( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
+ std::vector<uint32_t>& o_vpd_supported_freqs)
+{
+ uint8_t l_rank_count_dimm[MAX_DIMM_PER_PORT] = {};
+ uint8_t l_mr_blob[mss::VPD_KEYWORD_MAX] = {};
+ bool is_first_supported_freq = true;
+
+ // Clearing output Just.In.Case
+ o_vpd_supported_freqs.clear();
+
+ fapi2::VPDInfo<fapi2::TARGET_TYPE_MCS> l_vpd_info(fapi2::MemVpdData::MR);
+ l_vpd_info.iv_is_config_ffdc_enabled = false;
+
+ for( const auto& mcs : mss::find_targets<TARGET_TYPE_MCS>(i_target) )
+ {
+ for( const auto& p : mss::find_targets<TARGET_TYPE_MCA>(mcs) )
+ {
+ FAPI_TRY( mss::eff_num_master_ranks_per_dimm(p, &(l_rank_count_dimm[0])) );
+
+ l_vpd_info.iv_rank_count_dimm_0 = l_rank_count_dimm[0];
+ l_vpd_info.iv_rank_count_dimm_1 = l_rank_count_dimm[1];
+
+ // Iterate through all Nimbus supported freqs
+ for( const auto& freq : NIMBUS_SUPPORTED_FREQS )
+ {
+ l_vpd_info.iv_freq_mhz = freq;
+
+ FAPI_INF("%s. VPD info - frequency: %d MT/s, rank count for dimm_0: %d, dimm_1: %d",
+ mss::c_str(p), l_vpd_info.iv_freq_mhz, l_vpd_info.iv_rank_count_dimm_0, l_vpd_info.iv_rank_count_dimm_1);
+
+ // In order to retrieve the VPD contents we first need the keyword size.
+ // If we are unable to retrieve the keyword size then this speed isn't supported in the VPD
+ // and we skip to the next possible speed bin.
+ if( fapi2::getVPD(mcs, l_vpd_info, nullptr) != fapi2::FAPI2_RC_SUCCESS )
+ {
+ FAPI_INF("Couldn't retrieve MR size from VPD for this config %s -- skipping freq %d MT/s", mss::c_str(p), freq );
+
+ // If we added a freq that was supported in one MCA, but isn't supported for
+ // another MCA under the same MCBIST (such as one port running single drop and another dual drop),
+ // we remove it from the VPD supported freq list.
+ auto l_it = std::find(o_vpd_supported_freqs.begin(), o_vpd_supported_freqs.end(), freq);
+
+ if( l_it != o_vpd_supported_freqs.end() )
+ {
+ o_vpd_supported_freqs.erase(l_it);
+ }
+
+ continue;
+ }
+
+ FAPI_ASSERT( l_vpd_info.iv_size <= mss::VPD_KEYWORD_MAX,
+ fapi2::MSS_INVALID_VPD_KEYWORD_MAX().
+ set_MAX(mss::VPD_KEYWORD_MAX).
+ set_ACTUAL(l_vpd_info.iv_size).
+ set_KEYWORD(fapi2::MemVpdData::MR).
+ set_MCS_TARGET(i_target),
+ "VPD MR keyword size retrieved: %d, is larger than max: %d for %s",
+ l_vpd_info.iv_size, mss::VPD_KEYWORD_MAX, mss::c_str(i_target));
+
+ // If we are here then we should have a valid frequency selected from polling the VPD keyword size above.
+ // A hard-fail here means something is wrong and we want to return current_err instead of ignoring it.
+ FAPI_TRY( fapi2::getVPD(mcs, l_vpd_info, &(l_mr_blob[0])),
+ "Failed to retrieve VPD data for %s", mss::c_str(mcs) );
+
+ // Add non-repeating supported freqs
+ auto l_it = std::find(o_vpd_supported_freqs.begin(), o_vpd_supported_freqs.end(), freq);
+
+ if( l_it == o_vpd_supported_freqs.end() || is_first_supported_freq )
+ {
+ is_first_supported_freq = false;
+ FAPI_INF("VPD supported freq added: %d for %s", freq, mss::c_str(p) );
+ o_vpd_supported_freqs.push_back(freq);
+ }
+ }// freqs
+ }// mca
+ }//mcs
+
+ std::sort( o_vpd_supported_freqs.begin(), o_vpd_supported_freqs.end() );
+
+ return fapi2::FAPI2_RC_SUCCESS;
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Removes frequencies unsupported by SPD from a sorted list of supported freqs -- helper function for testing
+/// @param[in] i_target the MCBIST target
+/// @param[in] i_highest_freq largest SPD supported freq
+/// @param[in,out] io_freqs std::vector of VPD supported freqs (sorted)
+///
+void rm_unsupported_spd_freqs(const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
+ const uint32_t i_highest_freq,
+ std::vector<uint32_t>& io_freqs)
+{
+
+ // Don't use 'auto' since I want a const iterator and HB compiler
+ // bombs out using 'const auto'...
+ // The idea here is that if SPD across and MC can only support 2133 MT/s,
+ // we remove any supported frequencies in the vector higher than that (e.g. 2400, 2666)
+ auto it = std::upper_bound(io_freqs.begin(), io_freqs.end(), i_highest_freq);
+
+ // Remove all frequencies higher than max supported SPD freq per MCBIST
+ // since we set freq at that level
+ if( it != io_freqs.end() )
+ {
+ io_freqs.erase(it, io_freqs.end());
+ }
+
+ return;
+}
+
+///
+/// @brief Retrieves largest supported frequency the MC supports due to DIMM SPD
+/// @param[in] i_target the MCBIST target
+/// @param[out] o_highest_freq the largest SPD supported freq
+/// @return FAPI2_RC_SUCCESS iff okay
+///
+fapi2::ReturnCode largest_spd_supported_freq(const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
+ uint32_t& o_highest_freq)
+{
+ uint64_t l_largest_tck = 0;
+
+ // Get cached decoder
+ std::vector< std::shared_ptr<mss::spd::decoder> > l_factory_caches;
+
+ FAPI_TRY( mss::spd::populate_decoder_caches(i_target, l_factory_caches),
+ "%s. Failed to populate decoder cache", mss::c_str(i_target) );
+
+ // Looking for the biggest application period on an MC.
+ // This will further reduce supported frequencies the system can run on.
+ for ( const auto& l_cache : l_factory_caches )
+ {
+ const auto l_dimm = l_cache->iv_target;
+ uint64_t l_tckmax_in_ps = 0;
+ uint64_t l_tck_min_in_ps = 0;
+
+ FAPI_TRY( get_tckmax(l_cache, l_tckmax_in_ps),
+ "%s. Failed to get tCKmax", mss::c_str(l_dimm) );
+ FAPI_TRY( get_tckmin(l_cache, l_tck_min_in_ps),
+ "%s. Failed to get tCKmin", mss::c_str(l_dimm) );
+
+ // Determine a proposed tCK value that is greater than or equal tCKmin
+ // But less than tCKmax
+ l_largest_tck = std::max(l_largest_tck, l_tck_min_in_ps);
+ l_largest_tck = std::min(l_largest_tck, l_tckmax_in_ps);
+ }
+
+ FAPI_TRY( mss::ps_to_freq(l_largest_tck, o_highest_freq) );
+ FAPI_INF("Biggest freq supported from SPD %d MT/s for %s",
+ o_highest_freq, mss::c_str(i_target));
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
/// @brief Create and sort a vector of supported MT/s (freq)
-/// @param[in] MCA target for which to get the DIMM configs
-/// @param[out] reference to a std::vector<uint32_t> space to put the sorted vector
+/// @param[in] i_target MCBIST target for which to get the DIMM configs
+/// @param[out] o_freqs reference to a std::vector to put the sorted vector
/// @return FAPI2_RC_SUCCESS iff ok
-/// @note Taken from ATTR_MSS_MRW_SUPPORTED_FREQ. The result is sorted so such that the min
+/// @note Taken from VPD supported freqs. The result is sorted so such that the min
/// supported freq is std::vector<>.begin and the max is std::vector<>.end - 1. You can
/// search the resulting vector for valid frequencies as it is sorted.
///
-fapi2::ReturnCode supported_freqs(const fapi2::Target<TARGET_TYPE_MCA>& i_target, std::vector<uint32_t>& o_freqs)
+fapi2::ReturnCode supported_freqs(const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
+ std::vector<uint32_t>& o_freqs)
{
o_freqs.clear();
- std::vector<uint32_t> l_mrw_freqs(NUM_MRW_FREQS, 0);
- std::vector<uint32_t> l_max_freqs(NUM_MAX_FREQS, 0);
+ std::vector<uint32_t> l_vpd_supported_freqs;
+ uint32_t l_largest_spd_freq = 0;
uint8_t l_req_sync_mode = 0;
- FAPI_TRY( mss::mrw_supported_freq(l_mrw_freqs.data()) );
+ // Retrieve system MRW constraints
+ std::vector<uint32_t> l_max_freqs(NUM_MAX_FREQS, 0);
FAPI_TRY( mss::max_allowed_dimm_freq(l_max_freqs.data()) );
- FAPI_TRY( mss::required_synch_mode(l_req_sync_mode) );
-
- FAPI_INF("attribute supported freqs %d %d %d %d",
- l_mrw_freqs[0], l_mrw_freqs[1], l_mrw_freqs[2], l_mrw_freqs[3]);
- FAPI_INF("attribute supported max freqs %d %d %d %d %d",
- l_max_freqs[0], l_max_freqs[1], l_max_freqs[2], l_max_freqs[3], l_max_freqs[4]);
+ // Retrieve frequency constraints due to DIMM SPD and VPD per MCBIST
+ FAPI_TRY( largest_spd_supported_freq(i_target, l_largest_spd_freq) );
+ FAPI_TRY( vpd_supported_freqs(i_target, l_vpd_supported_freqs) );
+ rm_unsupported_spd_freqs(i_target, l_largest_spd_freq, l_vpd_supported_freqs);
- FAPI_INF("attribute required sync mode %d", l_req_sync_mode);
+ FAPI_TRY( mss::required_synch_mode(l_req_sync_mode) );
FAPI_TRY( supported_freqs_helper( i_target,
- l_mrw_freqs,
+ l_vpd_supported_freqs,
l_max_freqs,
l_req_sync_mode == fapi2::ENUM_ATTR_REQUIRED_SYNCH_MODE_ALWAYS,
o_freqs) );
-
fapi_try_exit:
return fapi2::current_err;
}
///
/// @brief Create and sort a vector of supported MT/s (freq) - helper for testing purposes
-/// @param[in] MCA target for which to get the DIMM configs
-/// @param[in] vector of MRW freqs
-/// @param[in] vector of max allowed freqs
-/// @param[in] bool whether or not we're forced into sync mode
-/// @param[out] reference to a std::vector<uint32_t> space to put the sorted vector
+/// @param[in] i_target MCBIST target for which to get the DIMM configs
+/// @param[in] i_hw_freqs vector of hardware supported freqs -- from VPD and SPD
+/// @param[in] i_max_mrw_freqs vector of max allowed freqs
+/// @param[in] i_req_sync_mode bool whether or not we're forced into sync mode
+/// @param[out] o_freqs reference to a std::vector to put the sorted vector
/// @return FAPI2_RC_SUCCESS iff ok
/// @note the attributes which drive this are read-only so they're hard to change when
/// testing. So this helper allows us to use the attributes for the main path but
/// have a path for testing (DFT I think the cool kids call it.)
///
-fapi2::ReturnCode supported_freqs_helper(const fapi2::Target<TARGET_TYPE_MCA>& i_target,
- const std::vector<uint32_t>& i_mrw_freqs,
- const std::vector<uint32_t>& i_max_freqs,
+fapi2::ReturnCode supported_freqs_helper(const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
+ const std::vector<uint32_t>& i_hw_freqs,
+ const std::vector<uint32_t>& i_max_mrw_freqs,
const bool i_req_sync_mode,
std::vector<uint32_t>& o_freqs)
{
@@ -377,44 +551,46 @@ fapi2::ReturnCode supported_freqs_helper(const fapi2::Target<TARGET_TYPE_MCA>& i
// frequencies allowed by the DIMM. So, we start way off the charts so std::min can do the lifting for us.
uint32_t l_our_max_freq = ~(0);
- // This magic number isn't the number of frequencies supported by the hardware, it's the number
- // of frequencies in the attribute or MRW. They may be different
- FAPI_ASSERT( i_mrw_freqs.size() == NUM_MRW_FREQS,
- fapi2::MSS_MRW_FREQ_SIZE_CHANGED()
- .set_ACTUAL_SIZE(i_mrw_freqs.size())
- .set_SUPPOSED_SIZE(NUM_MRW_FREQS)
- .set_MCA_TARGET(i_target),
- "%s Incorrect number of frequencies (%d)",
- mss::c_str(i_target),
- i_mrw_freqs.size());
-
- FAPI_INF("unsorted supported freqs %d %d %d %d",
- i_mrw_freqs[0], i_mrw_freqs[1], i_mrw_freqs[2], i_mrw_freqs[3]);
-
// This is the number of elements in the max_allowed_dimm_freq attribute, not the frequencies of
- // the system. Hence the magic number.
- FAPI_ASSERT( i_max_freqs.size() == NUM_MAX_FREQS,
+ // the system.
+ FAPI_ASSERT( i_max_mrw_freqs.size() == NUM_MAX_FREQS,
fapi2::MSS_MAX_FREQ_ATTR_SIZE_CHANGED()
- .set_ACTUAL_SIZE(i_max_freqs.size())
+ .set_ACTUAL_SIZE(i_max_mrw_freqs.size())
.set_SUPPOSED_SIZE(NUM_MAX_FREQS)
.set_MCA_TARGET(i_target),
"%s Incorrect number of max frequencies in attribute for (%d)",
mss::c_str(i_target),
- i_max_freqs.size());
+ i_max_mrw_freqs.size());
+
+ FAPI_INF("attribute supported max allowed dimm freqs %d %d %d %d %d for %s",
+ i_max_mrw_freqs[0], i_max_mrw_freqs[1], i_max_mrw_freqs[2], i_max_mrw_freqs[3], i_max_mrw_freqs[4],
+ mss::c_str(i_target));
- FAPI_INF("max supported freqs %d %d %d %d %d",
- i_max_freqs[0], i_max_freqs[1], i_max_freqs[2], i_max_freqs[3], i_max_freqs[4]);
+ // This is the list of supported frequencies for VPD and SPD
+ FAPI_ASSERT( !i_hw_freqs.empty(),
+ fapi2::MSS_EMPTY_VECTOR().
+ set_FUNCTION(SUPPORTED_FREQS).
+ set_TARGET(i_target),
+ "Supported system freqs from VPD and SPD are empty for %s",
+ mss::c_str(i_target));
+
+ for( const auto& freq : i_hw_freqs )
+ {
+ FAPI_DBG("VPD supported freqs %d for %s", freq, mss::c_str(i_target) );
+ }
+
+ for( const auto& p : mss::find_targets<fapi2::TARGET_TYPE_MCA>(i_target) )
{
- const auto l_dimms = mss::find_targets<TARGET_TYPE_DIMM>(i_target);
- uint64_t l_dimms_on_port = l_dimms.size();
+ const auto l_dimms = mss::find_targets<TARGET_TYPE_DIMM>(p);
+ const uint64_t l_dimms_on_port = l_dimms.size();
FAPI_ASSERT( (l_dimms_on_port <= MAX_DIMM_PER_PORT),
fapi2::MSS_TOO_MANY_DIMMS_ON_PORT()
.set_DIMM_COUNT(l_dimms_on_port)
- .set_MCA_TARGET(i_target),
+ .set_MCA_TARGET(p),
"Seeing %d DIMM on port %s",
l_dimms_on_port,
- mss::c_str(i_target));
+ mss::c_str(p));
for (const auto& d : l_dimms)
{
@@ -447,87 +623,85 @@ fapi2::ReturnCode supported_freqs_helper(const fapi2::Target<TARGET_TYPE_MCA>& i
FAPI_INF("%s rank config %d drop %d yields max freq attribute index of %d (%d)",
mss::c_str(d), l_num_master_ranks, l_dimms_on_port,
l_indexes[l_dimms_on_port - 1][l_num_master_ranks - 1],
- i_max_freqs[l_index] );
+ i_max_mrw_freqs[l_index] );
+
+ l_our_max_freq = std::min(l_our_max_freq, i_max_mrw_freqs[l_index]);
+ }// dimm
+ }// mca
- l_our_max_freq = std::min(l_our_max_freq, i_max_freqs[l_index]);
- }
- }
FAPI_INF("after processing DIMM, max freq is %d", l_our_max_freq);
// We need to push things as the memcpy doesn't update the vector's count, etc. and we don't
// create the vector, we get it passed in. It's not a big deal as we want to touch all the elements
// to check for 0's anyway.
- for (size_t i = 0; i < NUM_MRW_FREQS; ++i)
+ for (size_t i = 0; i < i_hw_freqs.size(); ++i)
{
// Funky if-tree makes things clearer than a combinatorialy explosive conditional
- if (i_mrw_freqs[i] == 0)
+ if (i_hw_freqs[i] == 0)
{
// Skip 0's
continue;
}
- if (i_mrw_freqs[i] > l_our_max_freq)
+ if (i_hw_freqs[i] > l_our_max_freq)
{
// Skip freqs larger than our max
continue;
}
// Add this freq if we're not in sync mode, or, if we are, add it if it matches a nest freq
- switch (i_req_sync_mode)
+ FAPI_INF("attribute required sync mode %d for %s", i_req_sync_mode, mss::c_str(i_target));
+
+ if( i_req_sync_mode && !is_nest_freq_valid(i_hw_freqs[i]) )
{
- case true :
- if (is_nest_freq_valid(i_mrw_freqs[i]))
- {
- o_freqs.push_back(i_mrw_freqs[i]);
- }
+ continue;
+ }
- break;
+ o_freqs.push_back(i_hw_freqs[i]);
- case false :
- o_freqs.push_back(i_mrw_freqs[i]);
- break;
- }
+ }//end for
+
+ {
+ // Doing this because the HB compiler freaks out if we have it within the FAPI_ASSERT.
+ // Outputting the value and then incrementing the iterator, that's why it's a post increment
+ // We have at most 4 memory freqs (1866, 2133, 2400, & 2666), if we ever get a list with < 4 items
+ // a value of 0 is logged in FFDC once we hit i_hw_freqs.end()...which is better than no logging.
+ auto l_supported = i_hw_freqs.begin();
+
+ const auto l_freq0 = (l_supported != i_hw_freqs.end()) ? *(l_supported++) : 0;
+ const auto l_freq1 = (l_supported != i_hw_freqs.end()) ? *(l_supported++) : 0;
+ const auto l_freq2 = (l_supported != i_hw_freqs.end()) ? *(l_supported++) : 0;
+ const auto l_freq3 = (l_supported != i_hw_freqs.end()) ? *(l_supported++) : 0;
+
+ // If we have an empty set, we have a problem
+ FAPI_ASSERT(o_freqs.size() != 0,
+ fapi2::MSS_MRW_FREQ_MAX_FREQ_EMPTY_SET()
+ .set_MSS_VPD_FREQ_0(l_freq0)
+ .set_MSS_VPD_FREQ_1(l_freq1)
+ .set_MSS_VPD_FREQ_2(l_freq2)
+ .set_MSS_VPD_FREQ_3(l_freq3)
+ .set_MSS_MAX_FREQ_0(i_max_mrw_freqs[0])
+ .set_MSS_MAX_FREQ_1(i_max_mrw_freqs[1])
+ .set_MSS_MAX_FREQ_2(i_max_mrw_freqs[2])
+ .set_MSS_MAX_FREQ_3(i_max_mrw_freqs[3])
+ .set_MSS_MAX_FREQ_4(i_max_mrw_freqs[4])
+ .set_MSS_NEST_FREQ_0(fapi2::ENUM_ATTR_FREQ_PB_MHZ_1600)
+ .set_MSS_NEST_FREQ_1(fapi2::ENUM_ATTR_FREQ_PB_MHZ_1866)
+ .set_MSS_NEST_FREQ_2(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2000)
+ .set_MSS_NEST_FREQ_3(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2133)
+ .set_MSS_NEST_FREQ_4(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2400)
+ .set_REQUIRED_SYNC_MODE(i_req_sync_mode)
+ .set_MAX_FREQ_FROM_DIMM(l_our_max_freq)
+ .set_MCBIST_TARGET(i_target),
+ "%s didn't find a frequency which was in VPD and was allowable max", mss::c_str(i_target));
}
// We now know o_freqs contains valid frequencies for this DIMM config, system contraints, and sync mode.
// Sort it so we know supported min is o_freq.begin and supported max is o_freq.end - 1
std::sort(o_freqs.begin(), o_freqs.end());
- // If we have an empty set, we have a problem
- FAPI_ASSERT(o_freqs.size() != 0,
- fapi2::MSS_MRW_FREQ_MAX_FREQ_EMPTY_SET()
- .set_MSS_MRW_FREQ_0(i_mrw_freqs[0])
- .set_MSS_MRW_FREQ_1(i_mrw_freqs[1])
- .set_MSS_MRW_FREQ_2(i_mrw_freqs[2])
- .set_MSS_MRW_FREQ_3(i_mrw_freqs[3])
- .set_MSS_MAX_FREQ_0(i_max_freqs[0])
- .set_MSS_MAX_FREQ_1(i_max_freqs[1])
- .set_MSS_MAX_FREQ_2(i_max_freqs[2])
- .set_MSS_MAX_FREQ_3(i_max_freqs[3])
- .set_MSS_MAX_FREQ_4(i_max_freqs[4])
- .set_MSS_NEST_FREQ_0(fapi2::ENUM_ATTR_FREQ_PB_MHZ_1600)
- .set_MSS_NEST_FREQ_1(fapi2::ENUM_ATTR_FREQ_PB_MHZ_1866)
- .set_MSS_NEST_FREQ_2(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2000)
- .set_MSS_NEST_FREQ_3(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2133)
- .set_MSS_NEST_FREQ_4(fapi2::ENUM_ATTR_FREQ_PB_MHZ_2400)
- .set_REQUIRED_SYNC_MODE(i_req_sync_mode)
- .set_MAX_FREQ_FROM_DIMM(l_our_max_freq)
- .set_MCA_TARGET(i_target),
- "%s didn't find a frequency which was in VPD and was allowable max", mss::c_str(i_target));
-
fapi_try_exit:
return fapi2::current_err;
}
-///
-/// @brief Return whether a given freq is supported
-/// @param[in] a freq to check for
-/// @param[in] reference to a std::vector<uint32_t> of freqs
-/// @return bool, true iff input freq is supported
-///
-bool is_freq_supported(const uint32_t i_freq, const std::vector<uint32_t>& i_freqs)
-{
- return std::binary_search(i_freqs.begin(), i_freqs.end(), i_freq);
-}
-
}// mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.H b/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.H
index 3c3b89d7e..ea057431b 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -27,7 +27,7 @@
/// @brief Synchronous function implementations
///
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
-// *HWP HWP Backup: Jacob Harvey <jlharvey@us.ibm.com>
+// *HWP HWP Backup: Louis Stermole <stermole@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: HB:FSP
@@ -45,8 +45,17 @@ namespace mss
enum class speed_equality : uint8_t
{
- NOT_EQUAL_DIMM_SPEEDS = 0,
- EQUAL_DIMM_SPEEDS = 1,
+ NOT_EQUAL_DIMM_SPEEDS = 0, ///< denotes all DIMMs don't have the same speed
+ EQUAL_DIMM_SPEEDS = 1, ///< denotes all DIMMs have the same speed
+};
+
+// DDR4 speed NIMBUS supports
+static const std::vector<uint32_t> NIMBUS_SUPPORTED_FREQS =
+{
+ fapi2::ENUM_ATTR_MSS_FREQ_MT1866,
+ fapi2::ENUM_ATTR_MSS_FREQ_MT2133,
+ fapi2::ENUM_ATTR_MSS_FREQ_MT2400,
+ fapi2::ENUM_ATTR_MSS_FREQ_MT2666,
};
///
@@ -62,8 +71,8 @@ inline bool is_nest_freq_valid (const uint64_t i_proposed_freq)
fapi2::ENUM_ATTR_FREQ_PB_MHZ_2133,
fapi2::ENUM_ATTR_FREQ_PB_MHZ_2400
};
- std::sort(l_nest_freqs_supported.begin(), l_nest_freqs_supported.end());
+ std::sort(l_nest_freqs_supported.begin(), l_nest_freqs_supported.end());
return ( std::binary_search(l_nest_freqs_supported.begin(), l_nest_freqs_supported.end(), i_proposed_freq) );
}
@@ -107,93 +116,69 @@ fapi2::ReturnCode select_sync_mode(const std::map< fapi2::Target<fapi2::TARGET_T
uint64_t& o_selected_freq);
///
-/// @brief Create and sort a vector of supported MT/s (freq) - helper for testing purposes
-/// @param[in] MCA target for which to get the DIMM configs
-/// @param[in] vector of MVPD freqs
-/// @param[in] vector of max allowed freqs
-/// @param[in] bool whether or not we're forced into sync mode
-/// @param[out] reference to a std::vector<uint32_t> space to put the sorted vector
+/// @brief Return whether a given freq is supported
+/// @param[in] a freq to check for
+/// @param[in] reference to a std::vector of supported freqs (sorted)
+/// @return bool true iff input freq is supported
+///
+bool is_freq_supported(const uint32_t i_freq, const std::vector<uint32_t>& i_freqs);
+
+/// @brief Create a vector of support freq based on VPD config
+/// @param[in] MCBIST target for which to get the DIMM configs
+/// @param[out] reference to a std::vector of supported VPD frequencies
/// @return FAPI2_RC_SUCCESS iff ok
-/// @note Taken from ATTR_MSS_MRW_SUPPORTED_FREQ. The result is sorted so such that the min
-/// supported freq is std::vector<>.begin and the max is std::vector<>.end - 1. You can
-/// search the resulting vector for valid frequencies as it is sorted.
///
-fapi2::ReturnCode supported_freqs_helper(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
- const std::vector<uint32_t>& i_freqs,
- const std::vector<uint32_t>& i_max_freqs,
- const bool i_req_sync_mode,
- std::vector<uint32_t>& o_freqs);
+fapi2::ReturnCode vpd_supported_freqs( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
+ std::vector<uint32_t>& o_vpd_supported_freqs);
+
+///
+/// @brief Removes frequencies unsupported by SPD from a sorted list of supported freqs -- helper function for testing
+/// @param[in] i_target the MCBIST target
+/// @param[in] i_highest_freq largest SPD supported freq
+/// @param[in,out] io_freqs std::vector of VPD supported freqs (sorted)
+///
+void rm_unsupported_spd_freqs(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
+ const uint32_t l_current_freq,
+ std::vector<uint32_t>& io_freqs);
+
+///
+/// @brief Retrieves largest supported frequency the MC supports due to DIMM SPD
+/// @param[in] i_target the MCBIST target
+/// @param[out] o_highest_freq the largest SPD supported freq
+/// @return FAPI2_RC_SUCCESS iff okay
+///
+fapi2::ReturnCode largest_spd_supported_freq(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
+ uint32_t& o_highest_freq);
///
/// @brief Create and sort a vector of supported MT/s (freq)
-/// @param[in] MCA target for which to get the DIMM configs
-/// @param[out] reference to a std::vector<uint32_t> space to put the sorted vector
+/// @param[in] i_target MCA target for which to get the DIMM configs
+/// @param[out] o_freqs reference to a std::vector to put the sorted vector
/// @return FAPI2_RC_SUCCESS iff ok
-/// @note Taken from ATTR_MSS_MRW_SUPPORTED_FREQ. The result is sorted so such that the min
+/// @note Taken from VPD supported freqs. The result is sorted so such that the min
/// supported freq is std::vector<>.begin and the max is std::vector<>.end - 1. You can
/// search the resulting vector for valid frequencies as it is sorted.
///
-fapi2::ReturnCode supported_freqs(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+fapi2::ReturnCode supported_freqs(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
std::vector<uint32_t>& o_freqs);
///
-/// @brief Return whether a given freq is supported
-/// @param[in] a freq to check for
-/// @param[in] reference to a std::vector<uint32_t> of freqs
-/// @return bool, true iff input freq is supported
-///
-bool is_freq_supported(const uint32_t i_freq, const std::vector<uint32_t>& i_freqs);
-
-///
-/// @brief Selects DIMM frequency to run based on supported system frequencies
-/// @tparam T the fapi2::TargetType for which the DIMM information exists.
-/// @param[in] target from which to get the dimm information
-/// @param[in,out] io_dimm_freq input is current dimm freq & output is next
-/// lowest dimm freq between 1866 MT/s (-5% margin) - 2666 MT/s (+5% margin)
-/// @return FAPI2_RC_SUCCESS iff ok
-/// @note Frequency values obtained from:
-/// @note From P9 User's Manual Version 0.8 - June 08, 2015
-/// @note Memory Controller Unit - page 199 of 456
+/// @brief Create and sort a vector of supported MT/s (freq) - helper for testing purposes
+/// @param[in] MCA target for which to get the DIMM configs
+/// @param[in] vector of VPD freqs
+/// @param[in] vector of max allowed freqs
+/// @param[in] bool whether or not we're forced into sync mode
+/// @param[out] reference to a std::vector to put the sorted vector
+/// @return FAPI2_RC_SUCCESS iff ok
+/// @note the attributes which drive this are read-only so they're hard to change when
+/// testing. So this helper allows us to use the attributes for the main path but
+/// have a path for testing (DFT I think the cool kids call it.)
///
-template< fapi2::TargetType T >
-inline fapi2::ReturnCode select_supported_freq(const fapi2::Target<T>& i_target, uint64_t& io_dimm_freq)
-{
- std::vector<uint32_t> l_freqs;
-
- FAPI_TRY( mss::supported_freqs(i_target, l_freqs) );
-
- {
- // supported_freqs sorts so upper_bound is valid.
- auto iterator = std::upper_bound(l_freqs.begin(), l_freqs.end(), io_dimm_freq);
-
- auto l_supported = l_freqs.begin();
-
- // Doing this because the HB compiler freaks out if we have it within the FAPI_ASSERT.
- // Outputting the value and then incrementing the iterator, that's why it's a post increment
- const auto l_0 = (l_supported != l_freqs.end()) ? *(l_supported++) : 0;
- const auto l_1 = (l_supported != l_freqs.end()) ? *(l_supported++) : 0;
- const auto l_2 = (l_supported != l_freqs.end()) ? *(l_supported++) : 0;
- const auto l_3 = (l_supported != l_freqs.end()) ? *(l_supported++) : 0;
-
- FAPI_ASSERT( (iterator != l_freqs.begin() && l_freqs.size() != 0),
- fapi2::MSS_SELECTED_FREQ_NOT_SUPPORTED()
- .set_FREQ(io_dimm_freq)
- .set_SUPPORTED_FREQ_0( l_0 )
- .set_SUPPORTED_FREQ_1( l_1 )
- .set_SUPPORTED_FREQ_2( l_2 )
- .set_SUPPORTED_FREQ_3( l_3 )
- .set_TARGET(i_target),
- "%s Error finding selected freq (%d) from list",
- mss::c_str(i_target),
- io_dimm_freq );
- // Upper bound checks just greater than, not equals. Return one up
- io_dimm_freq = *(--iterator);
- }
-
-fapi_try_exit:
- return fapi2::current_err;
-}
-
+fapi2::ReturnCode supported_freqs_helper(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
+ const std::vector<uint32_t>& i_vpd_freqs,
+ const std::vector<uint32_t>& i_max_freqs,
+ const bool i_req_sync_mode,
+ std::vector<uint32_t>& o_freqs);
}// mss
#endif
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 cee0e9b84..60aaa2f00 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
@@ -184,6 +184,13 @@ enum ffdc_function_codes
READ_RD_VREF_VALUES_FOR_DRAM = 93,
GET_DRAM_DISABLE_REG_AND_POS = 94,
GET_STARTING_WR_DQ_DELAY_VALUE = 95,
+
+ GET_TAAMIN = 96,
+ GET_TCKMIN = 97,
+ GET_TCKMAX = 98,
+
+ SUPPORTED_FREQS = 99,
+ SELECT_SUPPORTED_FREQ = 100,
};
enum states
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.C b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.C
index 92a3402cf..f57d414c0 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -52,6 +52,7 @@
#include <generic/memory/lib/utils/c_str.H>
#include <lib/utils/conversions.H>
#include <generic/memory/lib/utils/find.H>
+#include <lib/eff_config/timing.H>
using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_MCS;
@@ -60,6 +61,135 @@ using fapi2::FAPI2_RC_SUCCESS;
namespace mss
{
+
+
+///
+/// @brief Helper function to retrieves medium and fine timebase values
+/// @param[in] i_pDecoder the SPD decoder
+/// @param[out] o_mtb the medium timebase (MTB) from SPD
+/// @param[out] o_ftb the fine timebase (FTB) from SPD
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+static fapi2::ReturnCode get_timebases( const std::shared_ptr<mss::spd::decoder>& i_pDecoder,
+ int64_t& o_mtb,
+ int64_t& o_ftb )
+{
+ // Retrieve timing parameters
+ const auto l_target = i_pDecoder->iv_target;
+
+ FAPI_TRY( i_pDecoder->medium_timebase(o_mtb),
+ "%s. Failed medium_timebase()", mss::c_str(l_target) );
+ FAPI_TRY( i_pDecoder->fine_timebase(o_ftb),
+ "%s. Failed fine_timebase()", mss::c_str(l_target) );
+
+ FAPI_INF("MTB: %d, FTB: %d for %s", o_mtb, o_ftb, mss::c_str(l_target));
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Retrieves SDRAM Minimum Cycle Time (tCKmin) from SPD
+/// @param[in] i_pDecoder the SPD decoder
+/// @param[out] o_value tCKmin value in ps
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode get_tckmin( const std::shared_ptr<mss::spd::decoder>& i_pDecoder,
+ uint64_t& o_value )
+{
+ int64_t l_timing_ftb = 0;
+ int64_t l_timing_mtb = 0;
+ int64_t l_medium_timebase = 0;
+ int64_t l_fine_timebase = 0;
+ int64_t l_temp = 0;
+
+ // Retrieve timing parameters
+ const auto l_target = i_pDecoder->iv_target;
+
+ FAPI_TRY( get_timebases(i_pDecoder, l_medium_timebase, l_fine_timebase),
+ "%s. Failed get_timebases", mss::c_str(l_target) );
+ FAPI_TRY( i_pDecoder->min_tck(l_timing_mtb),
+ "%s. Failed min_tck()", mss::c_str(l_target) );
+ FAPI_TRY( i_pDecoder->fine_offset_min_tck(l_timing_ftb),
+ "%s. Failed fine_offset_min_tck()", mss::c_str(l_target) );
+
+ // Calculate timing value
+ l_temp = spd::calc_timing_from_timebase(l_timing_mtb,
+ l_medium_timebase,
+ l_timing_ftb,
+ l_fine_timebase);
+
+ // Sanity check
+ FAPI_ASSERT(l_temp > 0,
+ fapi2::MSS_INVALID_TIMING_VALUE().
+ set_VALUE(l_temp).
+ set_FUNCTION(GET_TCKMIN).
+ set_DIMM_TARGET(l_target),
+ "%s. tCKmin invalid (<= 0) : %d",
+ mss::c_str(l_target),
+ l_temp);
+
+ o_value = l_temp;
+
+ FAPI_INF("%s. tCKmin (ps): %d",
+ mss::c_str(l_target),
+ o_value );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Retrieves SDRAM Maximum Cycle Time (tCKmax) from SPD
+/// @param[in] i_pDecoder SPD decoder
+/// @param[out] o_value tCKmax value in ps
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode get_tckmax( const std::shared_ptr<mss::spd::decoder>& i_pDecoder,
+ uint64_t& o_value )
+{
+ int64_t l_timing_ftb = 0;
+ int64_t l_timing_mtb = 0;
+ int64_t l_medium_timebase = 0;
+ int64_t l_fine_timebase = 0;
+ int64_t l_temp = 0;
+
+ // Retrieve timing parameters
+ const auto l_target = i_pDecoder->iv_target;
+
+ FAPI_TRY( get_timebases(i_pDecoder, l_medium_timebase, l_fine_timebase),
+ "%s. Failed get_timebases", mss::c_str(l_target) );
+ FAPI_TRY( i_pDecoder->max_tck(l_timing_mtb),
+ "%s. Failed max_tck()", mss::c_str(l_target) );
+ FAPI_TRY( i_pDecoder->fine_offset_max_tck(l_timing_ftb),
+ "%s. Failed fine_offset_max_tck()", mss::c_str(l_target) );
+
+ // Calculate timing value
+ l_temp = spd::calc_timing_from_timebase(l_timing_mtb,
+ l_medium_timebase,
+ l_timing_ftb,
+ l_fine_timebase);
+
+ // Sanity check
+ FAPI_ASSERT(l_temp > 0,
+ fapi2::MSS_INVALID_TIMING_VALUE().
+ set_VALUE(l_temp).
+ set_FUNCTION(GET_TCKMAX).
+ set_DIMM_TARGET(l_target),
+ "%s. tCKmax invalid (<= 0) : %d",
+ mss::c_str(l_target),
+ l_temp);
+
+ o_value = l_temp;
+
+ FAPI_INF( "%s. tCKmax (ps): %d",
+ mss::c_str(l_target),
+ o_value);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
namespace spd
{
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.H b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.H
index 281916d0b..88dbd1f03 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/spd/spd_factory.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -257,6 +257,25 @@ fapi_try_exit:
}
}// spd
+
+///
+/// @brief Retrieves SDRAM Minimum Cycle Time (tCKmin) from SPD
+/// @param[in] i_pDecoder the SPD decoder
+/// @param[out] o_value tCKmin value in ps
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode get_tckmin(const std::shared_ptr<mss::spd::decoder>& i_pDecoder,
+ uint64_t& o_value);
+
+///
+/// @brief Retrieves SDRAM Maximum Cycle Time (tCKmax) from SPD
+/// @param[in] i_pDecoder SPD decoder
+/// @param[out] o_value tCKmax value in ps
+/// @return FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode get_tckmax(const std::shared_ptr<mss::spd::decoder>& i_pDecoder,
+ uint64_t& o_value);
+
}// mss
#endif //_MSS_SPD_FACTORY_H_
diff --git a/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C b/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C
index 86ef6f407..ce2bb06e1 100644
--- a/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C
+++ b/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2015,2017 */
+/* Contributors Listed Below - COPYRIGHT 2015,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -78,11 +78,9 @@ extern "C"
// So for now, iterate over all the MCBIST. This isn't great as we do this work
// twice for every MC. However, attribute access is cheap so this will suffice for
// the time being.
-
- std::vector< std::vector<uint64_t> > l_min_dimm_freq(mss::MCS_PER_MC, std::vector<uint64_t> (mss::PORTS_PER_MCS, 0) );
-
-
const auto& l_mcbist = mss::find_target<TARGET_TYPE_MCBIST>(i_target);
+ std::vector< std::vector<uint64_t> > l_min_dimm_freq(mss::MCS_PER_MC, std::vector<uint64_t> (mss::PORTS_PER_MCS, 0) );
+ std::vector<uint32_t> l_supported_freqs;
// If there are no DIMM, we can just get out.
if (mss::count_dimm(l_mcbist) == 0)
@@ -91,6 +89,9 @@ extern "C"
return FAPI2_RC_SUCCESS;
}
+ // Get supported freqs for this MCBIST
+ FAPI_TRY( mss::supported_freqs(l_mcbist, l_supported_freqs) );
+
for (const auto& l_mcs : mss::find_targets<TARGET_TYPE_MCS>(l_mcbist))
{
const auto l_mcs_index = mss::index(l_mcs);
@@ -99,65 +100,59 @@ extern "C"
for (const auto& l_mca : mss::find_targets<TARGET_TYPE_MCA>(l_mcs) )
{
- const auto l_index = mss::index(l_mca);
-
- // Get cached decoder
+ const auto l_mca_index = mss::index(l_mca);
std::vector< std::shared_ptr<mss::spd::decoder> > l_factory_caches;
+ fapi2::ReturnCode l_rc;
+ // Get cached decoder
FAPI_TRY( mss::spd::populate_decoder_caches(l_mca, l_factory_caches),
"%s. Failed to populate decoder cache", mss::c_str(l_mca) );
- {
- // instantiation of class that calculates CL algorithm
- fapi2::ReturnCode l_rc;
- mss::cas_latency l_cas_latency( l_mca, l_factory_caches, l_rc );
-
- FAPI_TRY( l_rc, "%s. Failed to initialize cas_latency ctor", mss::c_str(l_mca) );
+ // Instantiation of class that calculates CL algorithm
+ mss::cas_latency l_cas_latency( l_mca, l_factory_caches, l_supported_freqs, l_rc );
- if(l_cas_latency.iv_dimm_list_empty)
- {
- // Cannot fail out for an empty DIMM configuration, so default values are set
- FAPI_INF("%s. DIMM list is empty! Setting default values for CAS latency and DIMM speed.",
- mss::c_str(l_mca) );
- }
- else
- {
- // We set this to a non-0 so we avoid divide-by-zero errors in the conversions which
- // go from clocks to time (and vice versa.) We have other bugs if there was really
- // no MT/s determined and there really is a DIMM installed, so this is ok.
- // We pick the maximum frequency supported by the system as the default.
- uint64_t l_desired_cl = 0;
+ FAPI_TRY( l_rc, "%s. Failed to initialize cas_latency ctor", mss::c_str(l_mca) );
- l_min_dimm_freq[l_mcs_index][l_index] = fapi2::ENUM_ATTR_MSS_FREQ_MT2666;
+ if(l_cas_latency.iv_dimm_list_empty)
+ {
+ // Cannot fail out for an empty DIMM configuration, so default values are set
+ FAPI_INF("%s. DIMM list is empty! Setting default values for CAS latency and DIMM speed.",
+ mss::c_str(l_mca) );
+ }
- uint64_t l_tCKmin = 0;
+ else
+ {
+ // We set this to a non-0 so we avoid divide-by-zero errors in the conversions which
+ // go from clocks to time (and vice versa.) We have other bugs if there was really
+ // no MT/s determined and there really is a DIMM installed, so this is ok.
+ // We pick the maximum frequency supported by the system as the default.
+ uint64_t l_desired_cl = 0;
- // Find CAS latency using JEDEC algorithm
- FAPI_TRY( l_cas_latency.find_cl(l_desired_cl, l_tCKmin) );
+ l_min_dimm_freq[l_mcs_index][l_mca_index] = fapi2::ENUM_ATTR_MSS_FREQ_MT2666;
- FAPI_INF("%s. Result from CL algorithm, CL (nck): %d, tCK (ps): %d",
- mss::c_str(l_mca), l_desired_cl, l_tCKmin);
+ uint64_t l_tCKmin = 0;
- l_desired_cas_latency.push_back(std::make_pair(l_desired_cl, l_mca) );
+ // Find CAS latency using JEDEC algorithm
+ FAPI_TRY( l_cas_latency.find_cl(l_desired_cl, l_tCKmin) );
- // Find dimm transfer speed from selected tCK
- FAPI_TRY( mss::ps_to_freq(l_tCKmin, l_min_dimm_freq[l_mcs_index][l_index]),
- "%s. Failed ps_to_freq()", mss::c_str(l_mca) );
+ FAPI_INF("%s. Result from CL algorithm, CL (nck): %d, tCK (ps): %d",
+ mss::c_str(l_mca), l_desired_cl, l_tCKmin);
- FAPI_INF("DIMM speed from selected tCK (ps): %d for %s",
- l_min_dimm_freq[l_mcs_index][l_index],
- mss::c_str(l_mca));
+ l_desired_cas_latency.push_back(std::make_pair(l_desired_cl, l_mca) );
- FAPI_TRY(mss::select_supported_freq(l_mca, l_min_dimm_freq[l_mcs_index][l_index]),
- "Failed select_supported_freq() for %s", mss::c_str(l_mca));
+ // Find dimm transfer speed from selected tCK
+ FAPI_TRY( mss::ps_to_freq(l_tCKmin, l_min_dimm_freq[l_mcs_index][l_mca_index]),
+ "%s. Failed ps_to_freq()", mss::c_str(l_mca) );
- FAPI_INF("%s. Selected DIMM speed from supported speeds: %d",
- mss::c_str(l_mca), l_min_dimm_freq[l_mcs_index][l_index]);
+ FAPI_INF("DIMM speed from selected tCK (ps): %d for %s",
+ l_min_dimm_freq[l_mcs_index][l_mca_index],
+ mss::c_str(l_mca));
- }// end else
+ FAPI_INF("%s. Selected DIMM speed from supported speeds: %d",
+ mss::c_str(l_mca), l_min_dimm_freq[l_mcs_index][l_mca_index]);
- } // close scope
- } // End
+ }// end else
+ } // mca
FAPI_TRY(mss::set_CL_attr(l_mcs, l_desired_cas_latency),
"%s. Failed set_CL_attr()", mss::c_str(i_target) );
diff --git a/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H b/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H
index d259105a2..64286aadd 100644
--- a/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H
+++ b/src/import/chips/p9/procedures/hwp/memory/p9_mss_freq.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2015,2017 */
+/* Contributors Listed Below - COPYRIGHT 2015,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -113,6 +113,7 @@ inline fapi2::ReturnCode set_freq_attrs(const fapi2::Target<fapi2::TARGET_TYPE_M
fapi2::ENUM_ATTR_MSS_FREQ_MT2400,
fapi2::ENUM_ATTR_MSS_FREQ_MT2666,
};
+
std::sort( l_supported.begin(), l_supported.end() );
for (const auto l_vec : i_dimm_freq)
@@ -127,11 +128,11 @@ inline fapi2::ReturnCode set_freq_attrs(const fapi2::Target<fapi2::TARGET_TYPE_M
}
// If we saw all 0's, write a 0.
- l_final_freq = l_final_freq == UINT64_MAX ? 0 : l_final_freq;
+ l_final_freq = (l_final_freq == UINT64_MAX) ? 0 : l_final_freq;
// Shouldn't be getting 0 here. There have to be DIMMs installed for this code to be executed
- // The code would have errored out before if a frequency wasn't found.:w
- FAPI_ASSERT( std::binary_search(l_supported.begin(), l_supported.end(), l_final_freq) == true,
+ // The code would have errored out before if a frequency wasn't found.
+ FAPI_ASSERT( std::binary_search(l_supported.begin(), l_supported.end(), l_final_freq),
fapi2::MSS_BAD_FREQ_CALCULATED()
.set_MSS_FREQ(l_final_freq)
.set_MCBIST_TARGET(i_target)
diff --git a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_freq.xml b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_freq.xml
index f1b23a297..9fdb5874f 100644
--- a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_freq.xml
+++ b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_freq.xml
@@ -5,7 +5,7 @@
<!-- -->
<!-- OpenPOWER HostBoot Project -->
<!-- -->
-<!-- Contributors Listed Below - COPYRIGHT 2015,2017 -->
+<!-- Contributors Listed Below - COPYRIGHT 2015,2018 -->
<!-- [+] International Business Machines Corp. -->
<!-- -->
<!-- -->
@@ -81,7 +81,6 @@
<ffdc>TAAMIN</ffdc>
<ffdc>PROPOSED_TCK</ffdc>
<ffdc>IS_3DS</ffdc>
- <ffdc>FREQUENCY</ffdc>
<callout>
<procedure>CODE</procedure>
<priority>HIGH</priority>
@@ -127,22 +126,12 @@
<hwpError>
<rc>RC_MSS_FAILED_TO_FIND_SUPPORTED_CL</rc>
<description>
- Desired frequency from MRW is not supported by the DIMMS installed
- Checked via comparing Cas Latencies supported by DIMM and by CL calculated from MRW FREQ
+ Desired CAS latency isn't supported in the common CAS latency bin retrieved from SPD.
</description>
<ffdc>DESIRED_CAS_LATENCY</ffdc>
<ffdc>COMMON_CLS</ffdc>
<ffdc>TAA</ffdc>
<ffdc>TCK</ffdc>
- <ffdc>MSS_MRW_FREQ_0</ffdc>
- <ffdc>MSS_MRW_FREQ_1</ffdc>
- <ffdc>MSS_MRW_FREQ_2</ffdc>
- <ffdc>MSS_MRW_FREQ_3</ffdc>
- <ffdc>MSS_MAX_FREQ_0</ffdc>
- <ffdc>MSS_MAX_FREQ_1</ffdc>
- <ffdc>MSS_MAX_FREQ_2</ffdc>
- <ffdc>MSS_MAX_FREQ_3</ffdc>
- <ffdc>MSS_MAX_FREQ_4</ffdc>
<callout>
<procedure>CODE</procedure>
<priority>HIGH</priority>
@@ -332,10 +321,10 @@
remaining
If sync mode required, frequencies have to match a nest frequency
</description>
- <ffdc>MSS_MRW_FREQ_0</ffdc>
- <ffdc>MSS_MRW_FREQ_1</ffdc>
- <ffdc>MSS_MRW_FREQ_2</ffdc>
- <ffdc>MSS_MRW_FREQ_3</ffdc>
+ <ffdc>MSS_VPD_FREQ_0</ffdc>
+ <ffdc>MSS_VPD_FREQ_1</ffdc>
+ <ffdc>MSS_VPD_FREQ_2</ffdc>
+ <ffdc>MSS_VPD_FREQ_3</ffdc>
<ffdc>MSS_MAX_FREQ_0</ffdc>
<ffdc>MSS_MAX_FREQ_1</ffdc>
<ffdc>MSS_MAX_FREQ_2</ffdc>
@@ -354,7 +343,7 @@
</callout>
<callout>
<childTargets>
- <parent>MCA_TARGET</parent>
+ <parent>MCBIST_TARGET</parent>
<childType>TARGET_TYPE_DIMM</childType>
</childTargets>
<priority>MEDIUM</priority>
diff --git a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_general_errors.xml b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_general_errors.xml
index 9c94d8bd1..dbd872155 100644
--- a/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_general_errors.xml
+++ b/src/import/chips/p9/procedures/xml/error_info/p9_memory_mss_general_errors.xml
@@ -5,7 +5,7 @@
<!-- -->
<!-- OpenPOWER HostBoot Project -->
<!-- -->
-<!-- Contributors Listed Below - COPYRIGHT 2016,2017 -->
+<!-- Contributors Listed Below - COPYRIGHT 2016,2018 -->
<!-- [+] International Business Machines Corp. -->
<!-- -->
<!-- -->
@@ -35,6 +35,22 @@
<!-- -->
<hwpErrors>
+ <hwpError>
+ <rc>RC_MSS_EMPTY_VECTOR</rc>
+ <description>
+ Empty vector conditional failed.
+ </description>
+ <ffdc>RECEIVED</ffdc>
+ <ffdc>FUNCTION</ffdc>
+ <callout>
+ <target>TARGET</target>
+ <priority>MEDIUM</priority>
+ </callout>
+ <callout>
+ <procedure>CODE</procedure>
+ <priority>LOW</priority>
+ </callout>
+ </hwpError>
<hwpError>
<rc>RC_MSS_INVALID_DIMM_TYPE</rc>
OpenPOWER on IntegriCloud