Skip to content

Commit

Permalink
Adds self time refresh entry and exit helper functions
Browse files Browse the repository at this point in the history
For NVDIMM, self time refresh entry and exit are needed
for the NVDIMM data restore functionality.  This commit
adds in helper functions for SRE/SRX for NVDIMM

Change-Id: I3fb522f0baf6cc6a6cafb41c220be50ce1875ba3
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/54261
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
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: Daniel M. Crowell <dcrowell@us.ibm.com>
  • Loading branch information
Tsung Yeung authored and dcrowell77 committed Feb 25, 2018
1 parent b5c57af commit 1d2a738
Show file tree
Hide file tree
Showing 5 changed files with 265 additions and 4 deletions.
5 changes: 4 additions & 1 deletion src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.C
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
/* Contributors Listed Below - COPYRIGHT 2015,2017 */
/* Contributors Listed Below - COPYRIGHT 2015,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
Expand Down Expand Up @@ -249,6 +249,9 @@ fapi2::ReturnCode execute( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
FAPI_INF("executing ccs instructions (%d:%d, %d) for %s",
i_program.iv_instructions.size(), l_inst_count, i_program.iv_poll.iv_initial_delay, mss::c_str(i_target));

// Sets up the CKE values to be latched for the final CCS command
l_des.arr0.insertFromRight<TT::ARR0_DDR_CKE, TT::ARR0_DDR_CKE_LEN>(i_program.iv_final_cke_value);

// Insert a DES as our last instruction. DES is idle state anyway and having this
// here as an instruction forces the CCS engine to wait the delay specified in
// the last instruction in this array (which it otherwise doesn't do.)
Expand Down
41 changes: 38 additions & 3 deletions src/import/chips/p9/procedures/hwp/memory/lib/ccs/ccs.H
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ static constexpr uint64_t CKE_ARY_SRE[] =
// 0, 1, 2, 3,
0b0111, 0b1011, 0, 0,
// 4, 5, 6, 7
0b0111, 0b1011, 0, 0
0b1101, 0b1110, 0, 0
};

// For self_refresh_exit_command()
Expand All @@ -192,7 +192,7 @@ static constexpr uint64_t CKE_ARY_SRX[] =
// 0, 1, 2, 3,
0b1000, 0b0100, 0, 0,
// 4, 5, 6, 7
0b1000, 0b0100, 0, 0
0b0010, 0b0001, 0, 0
};

namespace ccs
Expand Down Expand Up @@ -346,7 +346,7 @@ class program
public:
// Setup our poll parameters so the CCS executer can see
// whether to use the delays in the instruction stream or not
program(): iv_poll(0, 0)
program(): iv_poll(0, 0), iv_final_cke_value(CKE_HIGH)
{}

// Vector of instructions
Expand All @@ -355,6 +355,35 @@ class program

// Vector of polling probes
std::vector< poll_probe<P> > iv_probes;

// Certain commands require different CKE values at the end of CCS
// These commands need a way to plop in those CKE values to be used with the final NOP
// The following variable allows for a custom CKE value to be passed in
fapi2::buffer<uint8_t> iv_final_cke_value;

///
/// @brief Sets up the final CKE value to be latched by the final command in the instructions vector
///
inline void set_last_cke_value()
{
// If we don't have any instructions, then just bail out
if(iv_instructions.empty())
{
FAPI_INF("An empty instruction was passed in. Last CKE value will be held the same: 0x%02x", iv_final_cke_value);
return;
}

// Get the last valid instruction
const auto& l_last = iv_instructions.back();

// Beautifying traits declaration
typedef ccsTraits<T> TT;

// Pulls out the final command's CKE value and stores it in the associated instance variable
l_last.arr0.template extractToRight<TT::ARR0_DDR_CKE, TT::ARR0_DDR_CKE_LEN>(iv_final_cke_value);

FAPI_DBG("new final CKE value for CCS instructions is 0x%02x", iv_final_cke_value);
}
};

///
Expand Down Expand Up @@ -775,6 +804,9 @@ inline instruction_t<T> self_refresh_entry_command( const fapi2::Target<fapi2::T
// From DDR4 Spec table 17:
// All other bits from the command truth table are 'V', for valid (1 or 0)

// Sets up the default timing for SRE to be the minimum self time refresh time
l_boilerplate_arr1.insertFromRight<TT::ARR1_IDLES, TT::ARR1_IDLES_LEN>( mss::tckeser(i_target) );

return instruction_t<T>(i_target, i_rank, l_boilerplate_arr0, l_boilerplate_arr1);
}

Expand Down Expand Up @@ -809,6 +841,9 @@ inline instruction_t<T> self_refresh_exit_command( const fapi2::Target<fapi2::TA
// From DDR4 Spec table 17:
// All other bits from the command truth table are 'V', for valid (1 or 0)

// Sets up the default timing for SRE to be the minimum self time refresh time
l_boilerplate_arr1.insertFromRight<TT::ARR1_IDLES, TT::ARR1_IDLES_LEN>( mss::txsdll(i_target) );

return instruction_t<T>(i_target, i_rank, l_boilerplate_arr0, l_boilerplate_arr1);
}

Expand Down
132 changes: 132 additions & 0 deletions src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/nvdimm_utils.C
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,135 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */

///
/// @file nvdimm_utils.C
/// @brief Subroutines to support nvdimm backup/restore process
///
// *HWP HWP Owner: Tsung Yeung <tyeung@us.ibm.com>
// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <vector>

#include <lib/dimm/ddr4/nvdimm_utils.H>
#include <lib/ccs/ccs.H>
#include <lib/mc/port.H>
#include <lib/phy/dp16.H>
#include <lib/dimm/rank.H>
#include <lib/dimm/rcd_load.H>
#include <lib/dimm/mrs_load.H>
#include <lib/mss_attribute_accessors.H>
#include <lib/workarounds/ccs_workarounds.H>
#include <lib/dimm/ddr4/pda.H>
#include <lib/dimm/ddr4/zqcal.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_DIMM;

namespace mss
{

namespace nvdimm
{

///
/// @brief Put target into self-refresh
/// Specializaton for TARGET_TYPE_DIMM
/// @param[in] i_target the target associated with this subroutine
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
fapi2::ReturnCode self_refresh_entry( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target )
{
std::vector<uint64_t> l_ranks;
const auto& l_mca = mss::find_target<fapi2::TARGET_TYPE_MCA>(i_target);
const auto& l_mcbist = mss::find_target<fapi2::TARGET_TYPE_MCBIST>(i_target);

mss::ccs::program<TARGET_TYPE_MCBIST> l_program;
// Timings on these guys should be pretty short
l_program.iv_poll.iv_initial_delay = DELAY_100NS;
l_program.iv_poll.iv_initial_sim_delay = DELAY_100NS;

// Get all the ranks in the dimm
FAPI_TRY( mss::rank::ranks(i_target, l_ranks) );

// Prep the instructions to put each rank into self refresh
for ( const auto& l_rank : l_ranks )
{
l_program.iv_instructions.push_back( mss::ccs::self_refresh_entry_command<TARGET_TYPE_MCBIST>(i_target, l_rank) );
}

// Hacks to hold low order ranks CKE low in higher order rank instruction
mss::ccs::workarounds::hold_cke_low(l_program);

// Setup the CKE to latch for the final command with the CKE from our final true command
l_program.set_last_cke_value();

// Sets the CCS address mux register to latch in the CKE state that was on the bus last
// This is needed to keep the DIMM in self-time refresh mode
FAPI_TRY(mss::change_addr_mux_sel(l_mca, mss::states::HIGH));

// Disable refresh
FAPI_TRY( mss::change_refresh_enable(l_mca, states::LOW) );

// Execute CCS
FAPI_TRY( mss::ccs::execute( l_mcbist, l_program, l_mca ) );

fapi_try_exit:
return fapi2::current_err;
}

///
/// @brief Take the target out of self-refresh and restart refresh
/// @tparam T the target type associated with this subroutine
/// @param[in] i_target the target associated with this subroutine
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< >
fapi2::ReturnCode self_refresh_exit( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target )
{

std::vector<uint64_t> l_ranks;
const auto& l_mca = mss::find_target<fapi2::TARGET_TYPE_MCA>(i_target);
const auto& l_mcbist = mss::find_target<fapi2::TARGET_TYPE_MCBIST>(i_target);

mss::ccs::program<TARGET_TYPE_MCBIST> l_program;
l_program.iv_poll.iv_initial_delay = DELAY_100NS;
l_program.iv_poll.iv_initial_sim_delay = DELAY_100NS;

// Get all the ranks in the dimm
mss::rank::ranks(i_target, l_ranks);

// Prep the instructions to take each rank out of self refresh
for ( const auto& l_rank : l_ranks )
{
l_program.iv_instructions.push_back( mss::ccs::self_refresh_exit_command<fapi2::TARGET_TYPE_MCBIST>(i_target, l_rank) );
}

// Hacks to hold CKE high, so we don't put any ranks accidentally into power down mode
mss::ccs::workarounds::hold_cke_high(l_program);

// Setup the CKE to latch for the final command with the CKE from our final true command
l_program.set_last_cke_value();

// Restores the CCS address mux select to its mainline setting
FAPI_TRY(mss::change_addr_mux_sel(l_mca, mss::states::LOW));

// Execute CCS
FAPI_TRY( mss::ccs::execute( l_mcbist, l_program, l_mca ) );

// Enable refresh
FAPI_TRY( mss::change_refresh_enable(l_mca, states::HIGH) );

fapi_try_exit:
return fapi2::current_err;
}

}//ns nvdimm

}//ns mss
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,44 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */

///
/// @file nvdimm_utils.H
/// @brief Subroutines to support nvdimm backup/restore process
///
// *HWP HWP Owner: Tsung Yeung <tyeung@us.ibm.com>
// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <generic/memory/lib/utils/find.H>

namespace mss
{

namespace nvdimm
{

///
/// @brief Disable refresh and put target into self-refresh
/// @tparam T the target type associated with this subroutine
/// @param[in] i_target the target associated with this subroutine
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< fapi2::TargetType T >
fapi2::ReturnCode self_refresh_entry( const fapi2::Target<T>& i_target );

///
/// @brief Take the target out of self-refresh and restart refresh
/// @tparam T the target type associated with this subroutine
/// @param[in] i_target the target associated with this subroutine
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< fapi2::TargetType T >
fapi2::ReturnCode self_refresh_exit( const fapi2::Target<T>& i_target );

}//ns nvdimm

}//ns mss
50 changes: 50 additions & 0 deletions src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.H
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,32 @@ fapi_try_exit:
return fapi2::current_err;
}

///
/// @brief DLL locking time *in clocks*
/// @tparam T the fapi2::TargetType of i_target
/// @param[in] i_target a target for attributes
/// @return txsdll
///
// TK is there some way to handle this better? we want to use the below in CCS command creation
template< fapi2::TargetType T >
inline uint64_t txsdll( const fapi2::Target<T>& i_target )
{
uint64_t l_tdllk = 0;

FAPI_TRY(tdllk(i_target, l_tdllk));
return l_tdllk;

fapi_try_exit:
// We simply can't work if we can't get the frequency or
// if we get an unsupported value that can't be converted to a valid tCK (clock period)
// ...so this should be ok
FAPI_ERR("Failed accessing tDLLK, exiting...");
fapi2::Assert(false);

// Keeps compiler happy
return 0;
}

///
/// @brief Mode Register Set Command Cycle Time
/// @return constexpr value of 8 clocks
Expand Down Expand Up @@ -1278,5 +1304,29 @@ constexpr uint64_t tccd_s()
return 4;
}

///
/// @brief Return the minimum allowable CKE pulse time
/// @tparam T the fapi2::TargetType of a type from which we can get MT/s
/// @param[in] i_target the fapi2 target
/// @return tCKE timing in clocks (nck)
///
template< fapi2::TargetType T >
uint64_t tcke( const fapi2::Target<T>& i_target )
{
return std::max( 3, spd::ns_to_nck(i_target, 5) );
}

///
/// @brief Return the minimum allowable CKE pulse time
/// @tparam T the fapi2::TargetType of a type from which we can get MT/s
/// @param[in] i_target the fapi2 target
/// @return tCKE timing in clocks (nck)
///
template< fapi2::TargetType T >
uint64_t tckeser( const fapi2::Target<T>& i_target )
{
return tcke(i_target) + 1;
}

} // mss
#endif

0 comments on commit 1d2a738

Please sign in to comment.