summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory
diff options
context:
space:
mode:
authorStephen Glancy <sglancy@us.ibm.com>2018-11-01 12:48:46 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2018-11-09 15:25:20 -0600
commita690866298f5d360a6512351ce15cce67e2c7fd3 (patch)
tree1010dc6a90a263ec42f0e384d64eb1c50aa434bf /src/import/chips/p9/procedures/hwp/memory
parent0faf0e05fd41bf1530131c90bf8eb38efdfd5bbb (diff)
downloadtalos-hostboot-a690866298f5d360a6512351ce15cce67e2c7fd3.tar.gz
talos-hostboot-a690866298f5d360a6512351ce15cce67e2c7fd3.zip
Updates LRDIMM code to utilize board swizzling
Change-Id: Icf88be43338526e94384bd2df1d9f478d88260c9 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/68284 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com> Reviewed-by: Louis Stermole <stermole@us.ibm.com> Reviewed-by: Devon A. Baughen <devon.baughen1@ibm.com> Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com> Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/68341 Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9/procedures/hwp/memory')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_lrdimm_training.C164
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_lrdimm_training.H105
2 files changed, 240 insertions, 29 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_lrdimm_training.C b/src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_lrdimm_training.C
index 0707bf696..5e127efcb 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_lrdimm_training.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_lrdimm_training.C
@@ -47,6 +47,7 @@
#include <lib/workarounds/ccs_workarounds.H>
#include <lib/ccs/ccs.H>
#include <lib/mc/port.H>
+#include <lib/rosetta_map/rosetta_map.H>
namespace mss
{
@@ -58,6 +59,87 @@ namespace lrdimm
{
///
+/// @brief Swizzles a DQ from the MC perspective to the DIMM perspective
+/// @param[in] i_target the MCA target on which to operate
+/// @param[in] i_mc_dq the DQ on the MC perspective to swizzle to the buffer's perspective
+/// @param[out] o_buffer_dq the DQ number from the buffer's perspective
+/// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode mc_to_dimm_dq(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_mc_dq,
+ uint64_t& o_buffer_dq)
+{
+ uint64_t l_c4_dq = 0;
+ uint8_t* l_dimm_dq_ptr = nullptr;
+ uint8_t l_dimm_to_c4[MAX_DQ_BITS] = {};
+
+ // First get the c4 DQ
+ FAPI_TRY(rosetta_map::mc_to_c4<rosetta_type::DQ>( i_target, i_mc_dq, l_c4_dq ));
+
+ // Now get the DIMM DQ
+ FAPI_TRY(vpd_dq_map(i_target, &l_dimm_to_c4[0]));
+ l_dimm_dq_ptr = std::find(l_dimm_to_c4, l_dimm_to_c4 + MAX_DQ_BITS, l_c4_dq);
+
+ // Check that we got a good value
+ FAPI_ASSERT(l_dimm_dq_ptr != l_dimm_to_c4 + MAX_DQ_BITS,
+ fapi2::MSS_LOOKUP_FAILED()
+ .set_KEY(l_c4_dq)
+ .set_DATA(i_mc_dq)
+ .set_TARGET(i_target));
+
+ // Now return that value
+ o_buffer_dq = *l_dimm_dq_ptr;
+
+fapi_try_exit :
+ return fapi2::current_err;
+}
+
+///
+/// @brief Swizzles a DQ from the DRAM perspective to the buffer's perspective
+/// @param[in] i_target the MCA target on which to operate
+/// @param[in] i_mc_dq the DQ on the MC perspective to swizzle to the buffer's perspective
+/// @param[out] o_buffer_dq the DQ number from the buffer's perspective
+/// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode mc_to_buffer(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_mc_dq,
+ uint64_t& o_buffer_dq)
+{
+ FAPI_TRY(mc_to_dimm_dq(i_target, i_mc_dq, o_buffer_dq));
+
+ // Each buffer is a byte and we want the bit from the buffer's perspective
+ o_buffer_dq = o_buffer_dq % BITS_PER_BYTE;
+
+fapi_try_exit :
+ return fapi2::current_err;
+}
+
+///
+/// @brief Checks if a buffer's nibbles are swizzled
+/// @param[in] i_target the MCA target on which to operate
+/// @param[in] i_buffer the buffer on which to see if the nibbles are swizzled
+/// @param[out] o_are_swizzled true if the buffer's nibbles are swizzled
+/// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode are_buffers_nibbles_swizzled(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_buffer,
+ bool& o_are_swizzled)
+{
+ const auto l_mc_dq = i_buffer * BITS_PER_BYTE;
+ uint64_t l_buffer_dq = 0;
+ FAPI_TRY(mc_to_buffer(i_target, l_mc_dq, l_buffer_dq));
+
+ // Now, checks if the nibble is swizzled
+ // We're swizzled if the 0'th DQ from the MC perspective is on buffer's nibble 1
+ o_are_swizzled = (1 == (l_buffer_dq / BITS_PER_NIBBLE));
+ FAPI_DBG("%s buffer:%u %s swizzled mc_dq:%u buffer_dq:%u",
+ mss::c_str(i_target), i_buffer, o_are_swizzled ? "are" : "not", l_mc_dq, l_buffer_dq);
+
+fapi_try_exit :
+ return fapi2::current_err;
+}
+
+///
/// @brief Issues initial pattern write to all ranks in the rank pair
/// @param[in] i_target the MCA target on which to operate
/// @parma[in] i_rp the rank pair on which to operate
@@ -246,38 +328,54 @@ fapi2::ReturnCode mrep::write_result_to_buffers_helper( const fapi2::Target<fapi
// Clears out the PBA container to ensure we don't issue undesired commands
o_container.clear();
+ // Get's the MCA
+ const auto& l_mca = mss::find_target<fapi2::TARGET_TYPE_MCA>(i_target);
+
// Looops through and generates the PBA commands
for(const auto& l_recorder : i_mrep_result)
{
- const auto l_result_nibble0 = l_recorder.first.iv_final_delay;
- const auto l_result_nibble1 = l_recorder.second.iv_final_delay;
-
- // Function space is derived from the rank
- // 2 is for Nibble 0, 3 is for Nibble 1
- // Data corresponds to the final setting we have
- // Delay is for PBA, bumping it way out so we don't have issues
- constexpr uint64_t PBA_DELAY = 255;
- constexpr uint64_t BCW_NIBBLE0 = 0x02;
- constexpr uint64_t BCW_NIBBLE1 = 0x03;
-
- const mss::cw_info MREP_FINAL_SET_BCW_N0( i_rank,
- BCW_NIBBLE0,
- l_result_nibble0,
- PBA_DELAY,
- mss::CW8_DATA_LEN,
- mss::cw_info::BCW);
- const mss::cw_info MREP_FINAL_SET_BCW_N1( i_rank,
- BCW_NIBBLE1,
- l_result_nibble1,
- PBA_DELAY,
- mss::CW8_DATA_LEN,
- mss::cw_info::BCW);
-
- // Each buffer contains two nibbles
- // Each nibble corresponds to one BCW
- // Add in the buffer control words
- FAPI_TRY(o_container.add_command(i_target, l_buffer, MREP_FINAL_SET_BCW_N0));
- FAPI_TRY(o_container.add_command(i_target, l_buffer, MREP_FINAL_SET_BCW_N1));
+ bool l_are_nibbles_swapped = false;
+ FAPI_TRY(are_buffers_nibbles_swizzled(l_mca, l_buffer, l_are_nibbles_swapped));
+
+ {
+ const auto l_result_nibble0 = l_are_nibbles_swapped ?
+ l_recorder.second.iv_final_delay :
+ l_recorder.first.iv_final_delay;
+ const auto l_result_nibble1 = l_are_nibbles_swapped ?
+ l_recorder.first.iv_final_delay :
+ l_recorder.second.iv_final_delay;
+
+ FAPI_DBG("%s MREP rank%u buffer:%u final values (0x%02x,0x%02x) %s swapped BC2x:0x%02x BC3x:0x%02x",
+ mss::c_str(l_mca), i_rank, l_buffer, l_recorder.first.iv_final_delay, l_recorder.second.iv_final_delay,
+ l_are_nibbles_swapped ? "are" : "not", l_result_nibble0, l_result_nibble1);
+
+ // Function space is derived from the rank
+ // 2 is for Nibble 0, 3 is for Nibble 1
+ // Data corresponds to the final setting we have
+ // Delay is for PBA, bumping it way out so we don't have issues
+ constexpr uint64_t PBA_DELAY = 255;
+ constexpr uint64_t BCW_NIBBLE0 = 0x02;
+ constexpr uint64_t BCW_NIBBLE1 = 0x03;
+
+ const mss::cw_info MREP_FINAL_SET_BCW_N0( i_rank,
+ BCW_NIBBLE0,
+ l_result_nibble0,
+ PBA_DELAY,
+ mss::CW8_DATA_LEN,
+ mss::cw_info::BCW);
+ const mss::cw_info MREP_FINAL_SET_BCW_N1( i_rank,
+ BCW_NIBBLE1,
+ l_result_nibble1,
+ PBA_DELAY,
+ mss::CW8_DATA_LEN,
+ mss::cw_info::BCW);
+
+ // Each buffer contains two nibbles
+ // Each nibble corresponds to one BCW
+ // Add in the buffer control words
+ FAPI_TRY(o_container.add_command(i_target, l_buffer, MREP_FINAL_SET_BCW_N0));
+ FAPI_TRY(o_container.add_command(i_target, l_buffer, MREP_FINAL_SET_BCW_N1));
+ }
++l_buffer;
}
@@ -517,6 +615,14 @@ fapi2::ReturnCode mrep::run( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_targ
FAPI_DBG("%s RP%u rank index number %u has rank %u", mss::c_str(i_target), i_rp, l_rank_index, l_rank);
const auto& l_dimm = l_dimms[mss::rank::get_dimm_from_rank(l_rank)];
+ // Added in for cronus debug - not needed for hostboot
+#ifndef __HOSTBOOT_MODULE
+ // Prints the header
+ FAPI_DBG("%s CARD AAAAAAAAAA RCD BBBBBBBB", mss::c_str(i_target));
+ FAPI_DBG("%s CARD 0000000000 RCD 11111111", mss::c_str(i_target));
+ FAPI_DBG("%s CARD 0516273849 RCD 04152637", mss::c_str(i_target));
+#endif
+
// Vector represents the number of LRDIMM buffers
// The pair represents the two nibbles that we need to calibrate within the buffer
std::vector<std::pair<recorder, recorder>> l_results_recorder(MAX_LRDIMM_BUFFERS);
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_lrdimm_training.H b/src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_lrdimm_training.H
index 0e940af3e..7805a95d5 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_lrdimm_training.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/mss_lrdimm_training.H
@@ -49,6 +49,7 @@
#include <lib/mcbist/mcbist.H>
#include <lib/dimm/ddr4/pba.H>
#include <lib/workarounds/ccs_workarounds.H>
+#include <lib/rosetta_map/rosetta_map.H>
namespace mss
{
@@ -201,6 +202,40 @@ fapi2::ReturnCode mpr_pattern_wr_rank(const fapi2::Target<fapi2::TARGET_TYPE_MCA
const uint64_t i_rank,
const uint32_t i_pattern);
+///
+/// @brief Swizzles a DQ from the MC perspective to the DIMM perspective
+/// @param[in] i_target the MCA target on which to operate
+/// @param[in] i_mc_dq the DQ on the MC perspective to swizzle to the buffer's perspective
+/// @param[out] o_buffer_dq the DQ number from the buffer's perspective
+/// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode mc_to_dimm_dq(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_mc_dq,
+ uint64_t& o_buffer_dq);
+
+///
+/// @brief Swizzles a DQ from the MC perspective to the buffer's perspective
+/// @param[in] i_target the MCA target on which to operate
+/// @param[in] i_mc_dq the DQ on the MC perspective to swizzle to the buffer's perspective
+/// @param[out] o_buffer_dq the DQ number from the buffer's perspective
+/// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode mc_to_buffer(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_mc_dq,
+ uint64_t& o_buffer_dq);
+
+///
+/// @brief Checks if a buffer's nibbles are swizzled
+/// @param[in] i_target the MCA target on which to operate
+/// @param[in] i_buffer the buffer on which to see if the nibbles are swizzled
+/// @param[out] o_are_swizzled true if the buffer's nibbles are swizzled
+/// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok
+///
+fapi2::ReturnCode are_buffers_nibbles_swizzled(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint64_t i_buffer,
+ bool& o_are_swizzled);
+
+///
/// @class data_response
/// @brief A structure that stores the results from the CCS on a per-buffer per-beat level
///
@@ -246,9 +281,79 @@ struct data_response
l_data.extractToRight<0, BITS_PER_BYTE>(iv_buffer_beat[8][l_beat]);
}
+ // Added in for cronus debug - not needed for hostboot
+#ifndef __HOSTBOOT_MODULE
+ FAPI_TRY(buffer_print(i_target));
+#endif
+
fapi_try_exit:
return fapi2::current_err;
}
+
+ // Added in for cronus debug - not needed for hostboot
+#ifndef __HOSTBOOT_MODULE
+ ///
+ /// @brief Prints out the response data for LRDIMM's in terms of the DRAM position
+ /// @param[in] i_target MCA target on which to operate
+ /// @return fapi2::ReturnCode SUCCESS iff code exectutes successfully
+ /// @note Should be for an RC B2 - swizzle might not be good for non-RC B2
+ ///
+ fapi2::ReturnCode buffer_print(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
+ {
+ // The below list is taken from rawcard B's JEDEC specification
+ // Assuming it remains the same for other raw card's, but this is just for debug prints for cronus anways
+ static constexpr uint8_t NIBBLE_TO_DRAM[MAX_DRAMS_X4] =
+ {
+ 0,
+ 5,
+ 1,
+ 6,
+ 7,
+ 2,
+ 8,
+ 3,
+ 10,
+ 14,
+ 11,
+ 15,
+ 12,
+ 16,
+ 17,
+ 13,
+ 9,
+ 4,
+ };
+ uint8_t l_results[MAX_DRAMS_X4] = {};
+
+ // Loops through all buffers
+ for(uint8_t l_buffer = 0; l_buffer < MAX_LRDIMM_BUFFERS; ++l_buffer)
+ {
+ uint64_t l_buffer_nibble0_dq = 0;
+ uint64_t l_buffer_nibble1_dq = 0;
+ uint64_t l_dram_0 = 0;
+ uint64_t l_dram_1 = 0;
+ FAPI_TRY(mc_to_dimm_dq(i_target, l_buffer * BITS_PER_BYTE, l_buffer_nibble0_dq));
+ FAPI_TRY(mc_to_dimm_dq(i_target, l_buffer * BITS_PER_BYTE + BITS_PER_NIBBLE, l_buffer_nibble1_dq));
+
+ l_dram_0 = NIBBLE_TO_DRAM[l_buffer_nibble0_dq / BITS_PER_NIBBLE];
+ l_dram_1 = NIBBLE_TO_DRAM[l_buffer_nibble1_dq / BITS_PER_NIBBLE];
+
+ l_results[l_dram_0] = iv_buffer_beat[l_buffer][0] & 0x0f;
+ l_results[l_dram_1] = (iv_buffer_beat[l_buffer][0] & 0xf0) >> BITS_PER_NIBBLE;
+ }
+
+ FAPI_DBG("%s CARDU %x%x%x%x%x RCD %x%x%x%x", mss::c_str(i_target),
+ l_results[0], l_results[1], l_results[2], l_results[3], l_results[4], l_results[10], l_results[11], l_results[12],
+ l_results[13]);
+
+ FAPI_DBG("%s CARDL %x%x%x%x%x RCD %x%x%x%x", mss::c_str(i_target),
+ l_results[5], l_results[6], l_results[7], l_results[8], l_results[9], l_results[14], l_results[15], l_results[16],
+ l_results[17]);
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+#endif
};
// TK:LRDIMM Do we need separate coarse vs fine steps?
OpenPOWER on IntegriCloud