summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory
diff options
context:
space:
mode:
authorAndre Marin <aamarin@us.ibm.com>2016-12-25 01:59:26 -0600
committerChristian R. Geddes <crgeddes@us.ibm.com>2017-01-06 15:34:06 -0500
commit84e573c5ac3b02a30e8feb41061466fd1788b061 (patch)
tree88fd5a51d74580dbd68d25422deec51496003f59 /src/import/chips/p9/procedures/hwp/memory
parentd0b4499de44240f199e54a71b58ea72fa2c4523d (diff)
downloadtalos-hostboot-84e573c5ac3b02a30e8feb41061466fd1788b061.tar.gz
talos-hostboot-84e573c5ac3b02a30e8feb41061466fd1788b061.zip
Add state machine for mrep and dwl training and unit tests
Change-Id: I1eda19cdc70813570551785e5bfcace3de55b501 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/34245 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> 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: Christian R. Geddes <crgeddes@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9/procedures/hwp/memory')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/state_machine.C236
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/state_machine.H180
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H1
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/utils/checker.H49
4 files changed, 465 insertions, 1 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/state_machine.C b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/state_machine.C
new file mode 100644
index 000000000..271513b20
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/state_machine.C
@@ -0,0 +1,236 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/state_machine.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file state_machine.C
+/// @brief Implementation of the state_machine
+///
+// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
+// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#include <fapi2.H>
+#include <lib/utils/c_str.H>
+#include <lib/dimm/ddr4/state_machine.H>
+
+namespace mss
+{
+
+///
+/// @brief non-target c_str general declaration
+/// @tparam T - type you want the const char * for
+/// @param[in] i_input a variable_buffer (expects a 72 bit buffer)
+/// @return const char *
+///
+template< >
+const char* c_str( const fapi2::variable_buffer& i_input )
+{
+ if( i_input.getBitLength() != MAX_DQ_BITS )
+ {
+ // User passed in a variable_buffer of invalid size
+ FAPI_ERR("Expecting a %d bit variable buffer, %d bit buffer received.",
+ MAX_DQ_BITS,
+ i_input.getBitLength());
+
+ fapi2::Assert(false);
+ }
+
+ constexpr uint64_t AADR_START = 0;
+ constexpr uint64_t AADR_LEN = 64;
+
+ constexpr uint64_t AAER_START = 64;
+ constexpr uint64_t AAER_LEN = 8;
+
+ uint64_t l_aaer = 0; // ecc
+ uint64_t l_aadr = 0; // data
+
+ FAPI_TRY( i_input.extractToRight(l_aadr, AADR_START, AADR_LEN),
+ "Failed to extract AADR data, start: %d, len: %d", AADR_START, AADR_LEN);
+
+ FAPI_TRY( i_input.extractToRight(l_aaer, AAER_START, AAER_LEN),
+ "Failed to extract AAER data, start: %d, len: %d", AAER_START, AAER_LEN);
+
+ // We are just printing out 18 nibbles worth of data
+ sprintf(c_str_storage, "0x%016lx%02lx", l_aadr, l_aaer);
+ return c_str_storage;
+
+fapi_try_exit:
+ // Best we can do? If we extracting data from the buffer fails,
+ // we don't fail-out but we get a string that states "badness" - AAM
+ FAPI_ERR("Failed to extract data from variable_buffer");
+ sprintf(c_str_storage, "ERROR");
+ return c_str_storage;
+}
+
+///
+/// @brief Helper function for trace boilerplate
+/// @param[in] i_data DRAM DQ data
+/// @param[in] i_nibble current nibble
+/// @param[in] i_phase_timing current phase step
+///
+inline void state_machine::print_debug( const fapi2::variable_buffer& i_data,
+ const uint64_t i_nibble,
+ const uint64_t i_phase_timing )
+{
+ // Can't use 2 mss::c_str functions inside a trace
+ // because of sharing issues with c_str_storage
+ // so we use a c_str buffer specifically for this class
+ strcpy(iv_str_buffer, mss::c_str(i_data));
+
+ FAPI_DBG( "%s phase timing: %d tck, nibble: %d, data: %s",
+ mss::c_str(iv_target), i_phase_timing, i_nibble, iv_str_buffer);
+}
+
+///
+/// @brief Helper function to set uninitialized state transition
+/// @param[in] i_data DRAM DQ data
+/// @param[in] i_nibble current nibble
+/// @param[in] i_phase_timing current phase step
+///
+void state_machine::uninitialized( const fapi2::variable_buffer& i_data,
+ const uint64_t i_nibble,
+ const uint64_t i_phase_timing )
+{
+ print_debug(i_data, i_nibble, i_phase_timing);
+
+ if( i_data.isBitSet(i_nibble * NIBBLE_OFFSET, BITS_PER_NIBBLE) )
+ {
+ FAPI_INF( "%s Going from UNINITIALIZED state to HIGH state", mss::c_str(iv_target) );
+ iv_state = fsm_state::HIGH;
+ }
+
+ else
+ {
+ FAPI_INF( "%s Going from UNINITIALIZED state to LOW state", mss::c_str(iv_target) );
+ iv_state = fsm_state::LOW;
+ }
+
+}
+
+///
+/// @brief Helper function to set high state transition
+/// @param[in] i_data DRAM DQ data
+/// @param[in] i_nibble current nibble
+/// @param[in] i_phase_timing current phase step
+///
+template< >
+void state_machine::high<transition::FALLING_EDGE>( const fapi2::variable_buffer& i_data,
+ const uint64_t i_nibble,
+ const uint64_t i_phase_timing )
+{
+ print_debug(i_data, i_nibble, i_phase_timing);
+
+ if( i_data.isBitClear(i_nibble * NIBBLE_OFFSET, BITS_PER_NIBBLE) )
+ {
+ FAPI_INF( "%s Found first HIGH to LOW state transition. Setting state to DONE",
+ mss::c_str(iv_target) );
+
+ iv_state = fsm_state::DONE;
+ iv_delay = i_phase_timing;
+ return;
+ }
+
+ // If we get here, do nothing, no state change
+ FAPI_INF( "%s No state change. Already in HIGH state.", mss::c_str(iv_target) );
+}
+
+///
+/// @brief Helper function to set high state transition
+/// @param[in] i_data DRAM DQ data
+/// @param[in] i_nibble current nibble
+/// @param[in] i_phase_timing current phase step
+///
+template< >
+void state_machine::high<transition::RISING_EDGE>( const fapi2::variable_buffer& i_data,
+ const uint64_t i_nibble,
+ const uint64_t i_phase_timing )
+{
+ print_debug(i_data, i_nibble, i_phase_timing);
+
+ if( i_data.isBitClear(i_nibble * NIBBLE_OFFSET, BITS_PER_NIBBLE) )
+ {
+ FAPI_INF( "%s Going from HIGH state to LOW state", mss::c_str(iv_target) );
+ iv_state = fsm_state::LOW;
+ return;
+ }
+
+ // If we get here, do nothing, no state change
+ FAPI_INF( "%s No state change. Already in HIGH state.", mss::c_str(iv_target) );
+}
+
+///
+/// @brief Helper function to set low state transition
+/// @param[in] i_data DRAM DQ data
+/// @param[in] i_nibble current nibble
+/// @param[in] i_phase_timing current phase step
+///
+template< >
+void state_machine::low<transition::FALLING_EDGE>( const fapi2::variable_buffer& i_data,
+ const uint64_t i_nibble,
+ const uint64_t i_phase_timing )
+{
+ print_debug(i_data, i_nibble, i_phase_timing);
+
+ if( i_data.isBitSet(i_nibble * NIBBLE_OFFSET, BITS_PER_NIBBLE) )
+ {
+ FAPI_INF( "%s Going from LOW state to HIGH state", mss::c_str(iv_target) );
+ iv_state = fsm_state::HIGH;
+ return;
+ }
+
+ // If we get here, do nothing, no state change
+ FAPI_INF( "%s No state change. Already in LOW state.", mss::c_str(iv_target) );
+}
+
+///
+/// @brief Helper function to set low state transition
+/// @param[in] i_data DRAM DQ data
+/// @param[in] i_nibble current nibble
+/// @param[in] i_phase_timing current phase step
+///
+template< >
+void state_machine::low<transition::RISING_EDGE>( const fapi2::variable_buffer& i_data,
+ const uint64_t i_nibble,
+ const uint64_t i_phase_timing )
+{
+ print_debug(i_data, i_nibble, i_phase_timing);
+
+ if( i_data.isBitSet(i_nibble * NIBBLE_OFFSET, BITS_PER_NIBBLE) )
+ {
+ FAPI_INF( "%s Found first LOW to HIGH state transition. Setting state to DONE",
+ mss::c_str(iv_target) );
+
+ iv_state = fsm_state::DONE;
+ iv_delay = i_phase_timing;
+ return;
+ }
+
+ // If we get here, do nothing, no state change
+ FAPI_INF( "%s No state change. Already in LOW state.", mss::c_str(iv_target) );
+}
+
+}// mss
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/state_machine.H b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/state_machine.H
new file mode 100644
index 000000000..60fa5d9db
--- /dev/null
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/state_machine.H
@@ -0,0 +1,180 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/state_machine.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file state_machine.H
+/// @brief state_machine delcaration
+///
+// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
+// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com>
+// *HWP Team: Memory
+// *HWP Level: 2
+// *HWP Consumed by: HB:FSP
+
+#ifndef _MSS_STATE_MACHINE_H_
+#define _MSS_STATE_MACHINE_H_
+
+#include <fapi2.H>
+#include <lib/utils/c_str.H>
+#include <lib/utils/checker.H>
+
+namespace mss
+{
+
+enum class transition
+{
+ RISING_EDGE, ///< Looking for 1st Low to High transition
+ FALLING_EDGE, ///< Looking for 1st High to Low transition
+};
+
+enum class fsm_state
+{
+ UNINITIALIZED, ///< Initial state
+ HIGH, ///< High state (logical 1)
+ LOW, ///< Low state (logical 0)
+ DONE, ///< Final state (First 1->0 or 0->1 transition)
+};
+
+///
+/// @class state_machine
+/// @brief State machine for LRDIMM training
+///
+class state_machine
+{
+ public:
+ fsm_state iv_state;
+ uint64_t iv_delay;
+
+ ///
+ /// @brief Default ctor
+ /// @param[in] i_target DIMM target
+ ///
+ state_machine(const fapi2::Target< fapi2::TARGET_TYPE_DIMM >& i_target):
+ iv_state(fsm_state::UNINITIALIZED),
+ iv_delay(0),
+ iv_target(i_target)
+ {}
+
+ ///
+ /// @brief Default dctor
+ ///
+ ~state_machine() = default;
+
+ ///
+ /// @brief Sets current state
+ /// @tparam T first transition we are looking for
+ /// @param[in] i_data DRAM DQ data
+ /// @param[in] i_nibble current nibble
+ /// @param[in] i_phase_timing current phase step
+ ///
+ template< transition T >
+ fapi2::ReturnCode next_transition( const fapi2::variable_buffer& i_data,
+ const uint64_t i_nibble,
+ const uint64_t i_phase_timing)
+ {
+ switch(iv_state)
+ {
+ case fsm_state::UNINITIALIZED:
+ uninitialized(i_data, i_nibble, i_phase_timing);
+ break;
+
+ case fsm_state::HIGH:
+ high<T>(i_data, i_nibble, i_phase_timing);
+ break;
+
+ case fsm_state::LOW:
+ low<T>(i_data, i_nibble, i_phase_timing);
+ break;
+
+ case fsm_state::DONE:
+ FAPI_INF("%s No state change. Already in DONE state.", mss::c_str(iv_target) );
+ break;
+
+ default:
+ // By default we are unitialized, we switch state based on
+ // AADR & AAER register data that represents DRAM DQ data.
+ // If we got here something bad happened, iv_state was corrupted somehow.
+ // Lets tell someone with FFDC
+ FAPI_TRY( check::invalid_dq_data(iv_target, false, i_data, i_phase_timing, i_nibble) );
+ break;
+ }// switch
+
+ fapi_try_exit:
+ return fapi2::current_err;
+ }
+
+ private:
+ static constexpr size_t NIBBLE_OFFSET = 4;
+ const fapi2::Target< fapi2::TARGET_TYPE_DIMM > iv_target;
+ char iv_str_buffer[fapi2::MAX_ECMD_STRING_LEN];
+
+ ///
+ /// @brief Helper function to set uninitialized state transition
+ /// @param[in] i_data DRAM DQ data
+ /// @param[in] i_nibble current nibble
+ /// @param[in] i_phase_timing current phase step
+ ///
+ void uninitialized( const fapi2::variable_buffer& i_data,
+ const uint64_t i_nibble,
+ const uint64_t i_phase_timing );
+
+ ///
+ /// @brief Helper function to set high state transition
+ /// @tparam T first transition we are looking for
+ /// @param[in] i_data DRAM DQ data
+ /// @param[in] i_nibble current nibble
+ /// @param[in] i_phase_timing current phase step
+ ///
+ template< transition T >
+ void high( const fapi2::variable_buffer& i_data,
+ const uint64_t i_nibble,
+ const uint64_t i_phase_timing );
+
+ ///
+ /// @brief Helper function to set low state transition
+ /// @tparam T first transition we are looking for
+ /// @param[in] i_data DRAM DQ data
+ /// @param[in] i_nibble current nibble
+ /// @param[in] i_phase_timing current phase step
+ ///
+ template< transition T >
+ void low( const fapi2::variable_buffer& i_data,
+ const uint64_t i_nibble,
+ const uint64_t i_phase_timing );
+
+ ///
+ /// @brief Helper function for trace boilerplate
+ /// @param[in] i_data DRAM DQ data
+ /// @param[in] i_nibble current nibble
+ /// @param[in] i_phase_timing current phase step
+ ///
+ void print_debug( const fapi2::variable_buffer& i_data,
+ const uint64_t i_nibble,
+ const uint64_t i_phase_timing );
+};
+
+}// 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 908687495..e37d07576 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
@@ -62,6 +62,7 @@ enum sizes
MAX_NUM_IMP = 4, ///< number of impedances valid per slew type
MAX_NUM_CAL_SLEW_RATES = 4, ///< 3V/ns, 4V/ns, 5V/ns, 6V/n
MAX_DQ_BITS = 72, /// TODO RTC:157753 This is Nimbus specific. Should be attribute/trait of processor.
+ MAX_DQ_NIBBLES_X4 = MAX_DQ_BITS / BITS_PER_NIBBLE, ///< For x4's there are 18 DQ nibbles for DQ 72 bits
MARK_STORE_COUNT = 8, ///< Elements in a VPD mark/store array
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/utils/checker.H b/src/import/chips/p9/procedures/hwp/memory/lib/utils/checker.H
index 8e255f7c9..b679aace0 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/utils/checker.H
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/utils/checker.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2015,2016 */
+/* Contributors Listed Below - COPYRIGHT 2015,2017 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -44,6 +44,53 @@ namespace mss
{
namespace check
{
+///
+/// @brief checks for invalid DQ data captured by from read FIFO
+/// used for LRDIMM training appliations
+/// @param[in] i_target the dimm target
+/// @param[in] i_conditional conditional that we are testing against
+/// @param[in] i_data DQ data from DRAM
+/// @param[in] i_phase_timing phase timing we are iterating through
+/// @param[in] i_nibble nibble we are iterating through
+/// @return fapi2::FAPI2_RC_SUCCESS iff okay
+///
+inline fapi2::ReturnCode invalid_dq_data( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
+ bool i_conditional,
+ const fapi2::variable_buffer& i_data,
+ const uint64_t i_phase_timing,
+ const uint64_t i_nibble )
+{
+ constexpr uint64_t AADR_START = 0;
+ constexpr uint64_t AADR_LEN = 64;
+
+ constexpr uint64_t AAER_START = 64;
+ constexpr uint64_t AAER_LEN = 8;
+
+ uint64_t l_aaer = 0; // ecc
+ uint64_t l_aadr = 0; // data
+
+ // Can't printout the variable buffer directly. Extracting
+ // data of interest for debugging purposes
+ FAPI_TRY( i_data.extractToRight(l_aadr, AADR_START, AADR_LEN),
+ "Failed to extract AADR data, start: %d, len: %d", AADR_START, AADR_LEN);
+
+ FAPI_TRY( i_data.extractToRight(l_aaer, AAER_START, AAER_LEN),
+ "Failed to extract AAER data, start: %d, len: %d", AAER_START, AAER_LEN);
+
+ FAPI_ASSERT(i_conditional,
+ fapi2::MSS_INVALID_DQ_DATA().
+ set_PHASE_TIMING(i_phase_timing).
+ set_NIBBLE(i_nibble).
+ set_DIMM_TARGET(i_target).
+ set_AADR(l_aadr).
+ set_AAER(l_aaer),
+ "%s. Invalid data received for phase: %d, nibble: %d, AADR: %d, AAER: %d.",
+ mss::c_str(i_target), i_phase_timing,
+ i_nibble, l_aadr, l_aaer );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
///
/// @brief Checks homogenous DDR4 dimm configuration (e.g. DDR4)
OpenPOWER on IntegriCloud