Skip to content

Commit

Permalink
Fixes b-side bug in MPR write function
Browse files Browse the repository at this point in the history
MPR writes were being disabled due to b-side inversion.
For MPR writes, the updated code now disables inversion.
It is restored to nominal after words.

Change-Id: Ibca550d9e6cadc6176df2a40c339e642f87f7770
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/67744
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: ANDRE A. MARIN <aamarin@us.ibm.com>
Reviewed-by: Jennifer A. Stofer <stofer@us.ibm.com>
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/67753
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
  • Loading branch information
sglancy6 authored and crgeddes committed Oct 29, 2018
1 parent a2f5910 commit 74c643e
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,22 @@ fapi_try_exit:
return fapi2::current_err;
}

///
/// @brief Modifies the supplied CW to be in or out of address inversion mode
/// @param[in,out] io_rc00 the RCW that contains address inversion
/// @param[in] i_inversion_enable true if inversion is enabled
/// @note Passed values should be OFF_N or ON_N
///
inline void set_address_inversion(cw_data& io_rc00, const mss::states i_inversion_enable)
{
// Bit 0 is the inversion enable
// Note: the bits are actually in JEDEC order, so bit 0 is on the far right
constexpr uint64_t INVERSION_BIT = 7;

// Values should be OFF_N or ON_N
io_rc00.iv_data.template writeBit<INVERSION_BIT>(i_inversion_enable);
}

}// mss

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@

#include <lib/phy/mss_lrdimm_training.H>
#include <lib/phy/mss_training.H>
#include <lib/phy/seq.H>
#include <lib/dimm/rank.H>
#include <lib/dimm/ddr4/mrs_load_ddr4.H>
#include <lib/dimm/ddr4/control_word_ddr4.H>
#include <lib/dimm/ddr4/data_buffer_ddr4.H>
#include <lib/workarounds/ccs_workarounds.H>

namespace mss
{
Expand Down Expand Up @@ -100,7 +102,6 @@ fapi2::ReturnCode mpr_pattern_wr_rank(const fapi2::Target<fapi2::TARGET_TYPE_MCA

mss::ccs::program<fapi2::TARGET_TYPE_MCBIST> l_program;
const auto& l_mcbist = mss::find_target<fapi2::TARGET_TYPE_MCBIST>(i_target);
constexpr uint64_t NUM_MPR_PATTERNS = 4;

// The below code expects us to have ranks in terms of the DIMM values, so index 'em
const auto l_rank = mss::index(i_rank);
Expand All @@ -113,57 +114,39 @@ fapi2::ReturnCode mpr_pattern_wr_rank(const fapi2::Target<fapi2::TARGET_TYPE_MCA
// Ok, MPR write
// We need to
// 1) MRS into MPR mode
// 2) Write the patterns in according to the bank address
// 3) MRS out of MPR mode
// 2) Disable address inversion, so we set our values correctly
// We need to disable address inversion so both A-side and B-side get the same pattern written into the MPR registers
// 3) Write the patterns in according to the bank address
// 4) Restore the default address inversion
// 5) MRS out of MPR mode

// 1) MRS into MPR mode
FAPI_TRY( mss::ddr4::mpr_load(l_dimm,
fapi2::ENUM_ATTR_EFF_MPR_MODE_ENABLE,
i_rank,
l_program.iv_instructions) );

// 2) Write the patterns in according to the bank address
{
constexpr uint64_t MPR_WR_BG = 0;
// First, swizzle the pattern
fapi2::buffer<uint32_t> l_swizzled_pattern;
FAPI_TRY(mss::seq::swizzle_mpr_pattern(i_pattern, l_swizzled_pattern),
"%s rank%u failed to swizzle pattern", mss::c_str(i_target), i_rank);

// Now add in writes with the appropriate data involved + the good old swizzle that we do based upon the ranks
// Swizzle is required as we want the expected data for mirrored and non-mirrored ranks to be the same
// For MPR writes the expected data is carried by the addresses, so mirroring matters

// Loop through all MPR patterns and generate writes for 'em
// The MPR number is defined by the bank address
for(uint8_t l_ba = 0; l_ba < NUM_MPR_PATTERNS; ++l_ba)
{
constexpr uint64_t ADDR_START = 54;
constexpr uint64_t PATTERN_LEN = 8;
constexpr uint64_t MPR_WR_SAFE_DELAY = 0xff;
uint64_t l_pattern = 0;
FAPI_TRY(l_swizzled_pattern.extract(l_pattern, l_ba * PATTERN_LEN, PATTERN_LEN, ADDR_START), "%s ba%u",
mss::c_str(l_dimm), l_ba);
{
auto l_wr = mss::ccs::wr_command<fapi2::TARGET_TYPE_MCBIST>( l_dimm,
l_rank,
l_ba,
MPR_WR_BG,
l_pattern);
l_wr.arr1.template insertFromRight<MCBIST_CCS_INST_ARR1_00_IDLES, MCBIST_CCS_INST_ARR1_00_IDLES_LEN>(MPR_WR_SAFE_DELAY);
FAPI_TRY(address_mirror(l_dimm, l_rank, l_wr));
l_program.iv_instructions.push_back(l_wr);
}
}
}
// 2) Disable address inversion
// We need to disable address inversion so both A-side and B-side get the same pattern written into the MPR registers
FAPI_TRY(disable_address_inversion(l_dimm, l_program.iv_instructions));

// 3) Write the patterns in according to the bank address
FAPI_TRY(add_mpr_pattern_writes(l_dimm,
l_rank,
i_pattern,
l_program.iv_instructions));

// 4) Restore the default address inversion
FAPI_TRY(restore_address_inversion(l_dimm, l_program.iv_instructions));

// 3) MRS out of MPR mode
// 5) MRS out of MPR mode
FAPI_TRY( mss::ddr4::mpr_load(l_dimm,
fapi2::ENUM_ATTR_EFF_MPR_MODE_DISABLE,
i_rank,
l_program.iv_instructions) );

// Make sure we leave everything powered on
mss::ccs::workarounds::hold_cke_high(l_program.iv_instructions);

FAPI_TRY( ccs::execute(l_mcbist,
l_program,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@
#define MSS_LRDIMM_TRAINING_H

#include <lib/phy/mss_training.H>
#include <lib/ccs/ccs.H>
#include <lib/dimm/ddr4/mrs_load_ddr4.H>
#include <lib/dimm/ddr4/control_word_ddr4.H>
#include <lib/dimm/ddr4/data_buffer_ddr4.H>
#include <lib/phy/seq.H>
#include <generic/memory/lib/utils/buffer_ops.H>

namespace mss
{
Expand All @@ -60,6 +66,126 @@ fapi2::ReturnCode mpr_pattern_wr_all_ranks(const fapi2::Target<fapi2::TARGET_TYP
const uint64_t i_rp,
const uint32_t i_pattern);

///
/// @brief Adds all write commands for the passed in pattern
/// @tparam fapi2::TargetType T target type for the CCS instruction
/// @param[in] i_target DIMM target on which to operate
/// @param[in] i_rank the DIMM rank to set the MPR on
/// @param[in] i_pattern the pattern to write into the MPRS
/// @param[in,out] io_insts CCS instructions
/// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok
///
template<fapi2::TargetType T>
inline fapi2::ReturnCode add_mpr_pattern_writes(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
const uint64_t i_rank,
const uint64_t i_pattern,
std::vector<mss::ccs::instruction_t<T>>& io_insts)
{

constexpr uint64_t NUM_MPR_PATTERNS = 4;
constexpr uint64_t MPR_WR_BG = 0;
// First, swizzle the pattern
fapi2::buffer<uint32_t> l_swizzled_pattern;
FAPI_TRY(mss::seq::swizzle_mpr_pattern(i_pattern, l_swizzled_pattern),
"%s rank%u failed to swizzle pattern", mss::c_str(i_target), i_rank);

// Now add in writes with the appropriate data involved + the good old swizzle that we do based upon the ranks
// Swizzle is required as we want the expected data for mirrored and non-mirrored ranks to be the same
// For MPR writes the expected data is carried by the addresses, so mirroring matters

// Loop through all MPR patterns and generate writes for 'em
// The MPR number is defined by the bank address
for(uint8_t l_ba = 0; l_ba < NUM_MPR_PATTERNS; ++l_ba)
{
constexpr uint64_t ADDR_START = 54;
constexpr uint64_t PATTERN_LEN = 8;
constexpr uint64_t MPR_WR_SAFE_DELAY = 0xff;
uint64_t l_pattern = 0;
FAPI_TRY(l_swizzled_pattern.extract(l_pattern, l_ba * PATTERN_LEN, PATTERN_LEN, ADDR_START), "%s ba%u",
mss::c_str(i_target), l_ba);
{
auto l_wr = mss::ccs::wr_command<fapi2::TARGET_TYPE_MCBIST>( i_target,
i_rank,
l_ba,
MPR_WR_BG,
l_pattern);
// Swaps the bank addresses so they're a true to the BA we tried to pass in above
swap<BA0, BA1>(l_wr.arr0);

l_wr.arr1.template insertFromRight<MCBIST_CCS_INST_ARR1_00_IDLES, MCBIST_CCS_INST_ARR1_00_IDLES_LEN>(MPR_WR_SAFE_DELAY);
FAPI_TRY(address_mirror(i_target, i_rank, l_wr));
io_insts.push_back(l_wr);
}
}

fapi_try_exit:
return fapi2::current_err;
}


///
/// @brief Helper function to disable address inversion
/// @tparam fapi2::TargetType T target type for the CCS instruction
/// @param[in] i_target DIMM target on which to operate
/// @param[in,out] io_insts CCS instructions
/// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok
///
template<fapi2::TargetType T>
inline fapi2::ReturnCode disable_address_inversion(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
std::vector<mss::ccs::instruction_t<T>>& io_insts)
{
// Declares the default control word that handles address inversion
// Data of 0 as we're going to override it below
constexpr uint64_t CW_INVERSION = 0;
// uint64_t(0) is to avoid compile errors from overloaded functions
cw_data l_cw(FUNC_SPACE_0, CW_INVERSION, static_cast<uint64_t>(0), mss::tmrd());
constexpr uint64_t CKE_HIGH = mss::ON;

uint8_t l_sim = 0;
FAPI_TRY(mss::is_simulation(l_sim));

// Gets default values
FAPI_TRY(eff_dimm_ddr4_rc00(i_target, l_cw.iv_data));

// Modifies inversion
set_address_inversion(l_cw, mss::states::OFF_N);

// Creates the CCS instructions
FAPI_TRY( control_word_engine<RCW_4BIT>(i_target, l_cw, l_sim, io_insts, CKE_HIGH),
"Failed to generate control words for %s", mss::c_str(i_target));

fapi_try_exit:
return fapi2::current_err;
}

///
/// @brief Helper function to restore default address inversion
/// @tparam fapi2::TargetType T target type for the CCS instruction
/// @param[in] i_target DIMM target on which to operate
/// @param[in,out] io_insts CCS instructions
/// @return fapi2::ReturnCode fapi2::FAPI2_RC_SUCCESS iff ok
///
template<fapi2::TargetType T>
inline fapi2::ReturnCode restore_address_inversion(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
std::vector<mss::ccs::instruction_t<T>>& io_insts)
{
// Declares the default control word that handles address inversion
// Data of 0 as we're going to override it below
constexpr uint64_t CW_INVERSION = 0;
cw_data l_cw(FUNC_SPACE_0, CW_INVERSION, eff_dimm_ddr4_rc00, mss::tmrd());
constexpr uint64_t CKE_HIGH = mss::ON;

uint8_t l_sim = 0;
FAPI_TRY(mss::is_simulation(l_sim));

// Creates the CCS instructions
FAPI_TRY( control_word_engine<RCW_4BIT>(i_target, l_cw, l_sim, io_insts, CKE_HIGH),
"Failed to generate control words for %s", mss::c_str(i_target));

fapi_try_exit:
return fapi2::current_err;
}

///
/// @brief Issues initial pattern write a specific rank
/// @param[in] i_target the MCA target on which to operate
Expand Down

0 comments on commit 74c643e

Please sign in to comment.