summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C')
-rw-r--r--src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C330
1 files changed, 263 insertions, 67 deletions
diff --git a/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C b/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C
index ac2f4353a..1472d5426 100644
--- a/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C
+++ b/src/import/chips/p9/procedures/hwp/memory/lib/phy/dp16.C
@@ -50,6 +50,7 @@
#include <lib/utils/pos.H>
#include <lib/utils/c_str.H>
+using fapi2::TARGET_TYPE_MCS;
using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_DIMM;
using fapi2::TARGET_TYPE_MCBIST;
@@ -410,6 +411,39 @@ const std::vector<uint64_t> dp16Traits<TARGET_TYPE_MCA>::READ_DELAY_OFFSET_REG =
MCA_DDRPHY_DP16_READ_DELAY_OFFSET1_RANK_PAIR3_P0_4,
};
+// Definition of the DISABLE registers, per dp per rank pair
+const std::vector< std::vector<std::pair<uint64_t, uint64_t>> > dp16Traits<TARGET_TYPE_MCA>::BIT_DISABLE_REG =
+{
+ {
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP0_P0_0, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP0_P0_0 },
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP0_P0_1, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP0_P0_1 },
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP0_P0_2, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP0_P0_2 },
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP0_P0_3, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP0_P0_3 },
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP0_P0_4, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP0_P0_4 },
+ },
+ {
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP1_P0_0, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP1_P0_0 },
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP1_P0_1, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP1_P0_1 },
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP1_P0_2, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP1_P0_2 },
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP1_P0_3, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP1_P0_3 },
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP1_P0_4, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP1_P0_4 },
+ },
+ {
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP2_P0_0, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP2_P0_0 },
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP2_P0_1, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP2_P0_1 },
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP2_P0_2, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP2_P0_2 },
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP2_P0_3, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP2_P0_3 },
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP2_P0_4, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP2_P0_4 },
+ },
+ {
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP3_P0_0, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP3_P0_0 },
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP3_P0_1, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP3_P0_1 },
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP3_P0_2, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP3_P0_2 },
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP3_P0_3, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP3_P0_3 },
+ { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP3_P0_4, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP3_P0_4 },
+ },
+};
+
///
/// @brief Given a RD_VREF value, create a PHY 'standard' bit field for that percentage.
/// @tparam T fapi2 Target Type - derived
@@ -1765,6 +1799,8 @@ fapi2::ReturnCode process_bad_bits( const fapi2::Target<TARGET_TYPE_MCA>& i_targ
const fapi2::Target<TARGET_TYPE_DIMM>& i_dimm,
const uint64_t l_rp )
{
+ typedef dp16Traits<TARGET_TYPE_MCA> TT;
+
// In a x4 configuration, all bits in the disable registers are used.
// Named like a local variable so it matches the x8 vector <shrug>
constexpr uint8_t l_x4_mask = 0b11111111;
@@ -1856,8 +1892,6 @@ fapi2::ReturnCode process_bad_bits( const fapi2::Target<TARGET_TYPE_MCA>& i_targ
};
// The field in the disable bit register address which specifies which rp the register is for.
- constexpr uint64_t RP_START_BIT = 22;
- constexpr uint64_t RP_LEN = 2;
constexpr uint64_t RP_OFFSET = 60;
// The DQS bits (disable 1) are left aligned in a 16 bit register and we have a
@@ -1883,32 +1917,23 @@ fapi2::ReturnCode process_bad_bits( const fapi2::Target<TARGET_TYPE_MCA>& i_targ
fapi2::buffer<uint64_t> l_rpb(l_rp);
std::vector< std::pair<fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> > > l_read;
- // A tasty vector of the disable bits for RP0. We'll add in the RP bits before we scom.
- std::vector<std::pair<uint64_t, uint64_t>> l_addr =
- {
- { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP0_P0_0, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP0_P0_0 },
- { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP0_P0_1, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP0_P0_1 },
- { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP0_P0_2, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP0_P0_2 },
- { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP0_P0_3, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP0_P0_3 },
- { MCA_DDRPHY_DP16_DATA_BIT_DISABLE0_RP0_P0_4, MCA_DDRPHY_DP16_DATA_BIT_DISABLE1_RP0_P0_4 },
- };
-
while (l_rpb != 0)
{
// We increment l_which_dp as soon as we enter the loop below
uint64_t l_which_dp = ~0;
+ // A map of the indexes of the bad nibbles. We do bad nibble checking in two phases;
+ // the DQS and the DQ. Since bad bits in the DQ/DQS of the nibble are the same nibble,
+ // we use a map to consolodate the findings. In the end all we care about is whether there
+ // is more than one entry in this map.
+ std::map<uint64_t, uint64_t> l_bad_nibbles;
+ uint64_t l_bad_bits = 0;
+
// Find the first bit set in the rank pairs - this will tell us which rank pair has a fail
const auto l_fbs = mss::first_bit_set(uint64_t(l_rpb)) - RP_OFFSET;
- // Fix up the vector so it grabs registers for this rank pair
- for (auto& r : l_addr)
- {
- r.first = fapi2::buffer<uint64_t>(r.first ).insertFromRight<RP_START_BIT, RP_LEN>(l_fbs);
- r.second = fapi2::buffer<uint64_t>(r.second).insertFromRight<RP_START_BIT, RP_LEN>(l_fbs);
-
- FAPI_INF("checking bad bits for RP%d (0x%016lX, 0x%016lX)", l_fbs, r.first, r.second);
- }
+ const auto l_addr = TT::BIT_DISABLE_REG[l_fbs];
+ FAPI_INF("checking bad bits for RP%d", l_fbs);
FAPI_TRY( mss::scom_suckah(i_target, l_addr, l_read) );
@@ -1920,14 +1945,8 @@ fapi2::ReturnCode process_bad_bits( const fapi2::Target<TARGET_TYPE_MCA>& i_targ
uint64_t l_dq_bad_bit_count = 0;
uint64_t l_dqs_bad_bit_count = 0;
- // A map of the indexes of the bad nibbles. We do bad nibble checking in two phases;
- // the DQS and the DQ. Since bad bits in the DQ/DQS of the nibble are the same nibble,
- // we use a map to consolodate the findings. In the end all we care about is whether there
- // is more than one entry in this map.
- std::map<uint64_t, uint64_t> l_bad_nibbles;
- uint64_t l_bad_bits = 0;
-
l_which_dp += 1;
+ const uint64_t l_which_nibble = l_which_dp * BITS_PER_NIBBLE;
FAPI_INF("read disable0 0x%016lx disable1 0x%016lx", v.first, v.second);
@@ -1942,7 +1961,8 @@ fapi2::ReturnCode process_bad_bits( const fapi2::Target<TARGET_TYPE_MCA>& i_targ
//
// Check for a simple fail. In all cases if we see 6 or more bits set in the
- // disable 0, we have a dead nibble + more than one bit.
+ // disable 0, we have a dead nibble + more than one bit. We don't need to worry about
+ // disable bits because this port will be deconfigured all together.
//
l_dq_bad_bit_count = mss::bit_count(uint64_t(v.first));
FAPI_INF("bad DQ count for port %d DP%d %d", l_which_port, l_which_dp, l_dq_bad_bit_count);
@@ -1950,7 +1970,6 @@ fapi2::ReturnCode process_bad_bits( const fapi2::Target<TARGET_TYPE_MCA>& i_targ
fapi2::MSS_DISABLED_BITS().set_TARGET_IN_ERROR(i_target),
"port %d DP%d too many bad DQ bits 0x%016lx", l_which_port, l_which_dp, v.first);
-
//
// Find the DQS mask for this DP.
//
@@ -1988,13 +2007,13 @@ fapi2::ReturnCode process_bad_bits( const fapi2::Target<TARGET_TYPE_MCA>& i_targ
// We shift it over to mask off the nibble we're checking
const uint16_t l_dqs_nibble_mask = 0b1100000000000000 >> (n * BITS_PER_DQS);
- FAPI_INF("port %d DP%d nibble %d mask: 0x%x dqs: 0x%x",
- l_which_port, l_which_dp, n, l_dqs_nibble_mask, v.second);
+ FAPI_INF("port %d DP%d nibble %d (%d) mask: 0x%x dqs: 0x%x",
+ l_which_port, l_which_dp, n, n + l_which_nibble, l_dqs_nibble_mask, v.second);
if ((l_dqs_nibble_mask & v.second) != 0)
{
FAPI_INF("dqs check indicating %d as a bad nibble", n);
- l_bad_nibbles[n] = 1;
+ l_bad_nibbles[n + l_which_nibble] = 1;
}
}
@@ -2003,7 +2022,7 @@ fapi2::ReturnCode process_bad_bits( const fapi2::Target<TARGET_TYPE_MCA>& i_targ
// we're done.
FAPI_ASSERT(l_bad_nibbles.size() <= MAX_BAD_NIBBLES,
fapi2::MSS_DISABLED_BITS().set_TARGET_IN_ERROR(i_target),
- "port %d DP%d too many bad nibbles %d", l_which_port, l_which_dp, l_bad_nibbles.size());
+ "port %d DP%d too many bad nibbles %d", l_which_port, l_which_nibble, l_bad_nibbles.size());
}
//
@@ -2024,8 +2043,8 @@ fapi2::ReturnCode process_bad_bits( const fapi2::Target<TARGET_TYPE_MCA>& i_targ
// we add this bit to the total of bad singleton bits.
const uint64_t l_bit_count = mss::bit_count(l_dq_nibble_mask & v.first);
- FAPI_INF("port %d DP%d nibble %d mask: 0x%x dq: 0x%x c: %d",
- l_which_port, l_which_dp, n, l_dq_nibble_mask, v.first, l_bit_count);
+ FAPI_INF("port %d DP%d nibble %d (%d) mask: 0x%x dq: 0x%x c: %d",
+ l_which_port, l_which_dp, n, n + l_which_nibble, l_dq_nibble_mask, v.first, l_bit_count);
// If we don't have any set bits, we're good to go. If we have more than the max bad bits,
@@ -2035,47 +2054,47 @@ fapi2::ReturnCode process_bad_bits( const fapi2::Target<TARGET_TYPE_MCA>& i_targ
{
if (l_bit_count > MAX_BAD_BITS)
{
- FAPI_INF("dq check indicating %d as a bad nibble", n);
- l_bad_nibbles[n] = 1;
+ FAPI_INF("dq check indicating %d (%d) as a bad nibble", n, n + l_which_nibble);
+ l_bad_nibbles[n + l_which_nibble] = 1;
}
else
{
- FAPI_INF("dq check indicating nibble %d has a bad bit", n);
+ FAPI_INF("dq check indicating nibble %d (%d) has a bad bit", n, n + l_which_nibble);
l_bad_bits += l_bit_count;
}
}
}
+ }
+ }
- //
- // Ok, so now we know how many bad bits we have and how many bad nibbles. If we have more than
- // one bad nibble, we're cooked. If we have one bad nibble and one bad bit, we're ok. Also, if
- // we have no bad nibbles and two bad bits (a sly bad nibble) we are ok - one of those bad bits
- // counts as a bad nibble.
- //
- FAPI_ASSERT(l_bad_nibbles.size() <= MAX_BAD_NIBBLES,
- fapi2::MSS_DISABLED_BITS().set_TARGET_IN_ERROR(i_target),
- "port %d DP%d too many bad nibbles %d",
- l_which_port, l_which_dp, l_bad_nibbles.size());
-
- // If we have one bad nibble, assert that we have one or fewer bad bits
- if (l_bad_nibbles.size() == MAX_BAD_NIBBLES)
- {
- FAPI_ASSERT(l_bad_bits <= MAX_BAD_BITS,
- fapi2::MSS_DISABLED_BITS().set_TARGET_IN_ERROR(i_target),
- "port %d DP%d bad nibbles %d + %d bad bits",
- l_which_port, l_which_dp, l_bad_nibbles.size(), l_bad_bits);
- }
+ //
+ // Ok, so now we know how many bad bits we have and how many bad nibbles. If we have more than
+ // one bad nibble, we're cooked. If we have one bad nibble and one bad bit, we're ok. Also, if
+ // we have no bad nibbles and two bad bits (a sly bad nibble) we are ok - one of those bad bits
+ // counts as a bad nibble.
+ //
+ FAPI_ASSERT(l_bad_nibbles.size() <= MAX_BAD_NIBBLES,
+ fapi2::MSS_DISABLED_BITS().set_TARGET_IN_ERROR(i_target),
+ "port %d DP%d too many bad nibbles %d",
+ l_which_port, l_which_dp, l_bad_nibbles.size());
+
+ // If we have one bad nibble, assert that we have one or fewer bad bits
+ if (l_bad_nibbles.size() == MAX_BAD_NIBBLES)
+ {
+ FAPI_ASSERT(l_bad_bits <= MAX_BAD_BITS,
+ fapi2::MSS_DISABLED_BITS().set_TARGET_IN_ERROR(i_target),
+ "port %d DP%d bad nibbles %d + %d bad bits",
+ l_which_port, l_which_dp, l_bad_nibbles.size(), l_bad_bits);
+ }
- // If we have no bad nibbles, assert we have 2 or fewer bad bits. This is a sly bad nibble
- // scenario; one of the bits is represents a bad nibble
- if (l_bad_nibbles.size() == 0)
- {
- FAPI_ASSERT(l_bad_bits <= SLY_BAD_BITS,
- fapi2::MSS_DISABLED_BITS().set_TARGET_IN_ERROR(i_target),
- "port %d DP%d %d bad bits",
- l_which_port, l_which_dp, l_bad_bits);
- }
- }
+ // If we have no bad nibbles, assert we have 2 or fewer bad bits. This is a sly bad nibble
+ // scenario; one of the bits is represents a bad nibble
+ if (l_bad_nibbles.size() == 0)
+ {
+ FAPI_ASSERT(l_bad_bits <= SLY_BAD_BITS,
+ fapi2::MSS_DISABLED_BITS().set_TARGET_IN_ERROR(i_target),
+ "port %d DP%d %d bad bits",
+ l_which_port, l_which_dp, l_bad_bits);
}
// We're all done. Clear the bit
@@ -2086,5 +2105,182 @@ fapi_try_exit:
return fapi2::current_err;
}
+///
+/// @brief Reset the bad-bits masks for a port
+/// @note Read the bad bits from the f/w attributes and stuff them in the
+/// appropriate registers.
+/// @param[in] i_target the fapi2 target of the port
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if bad bits can be repaired
+///
+fapi2::ReturnCode reset_bad_bits( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+{
+ // The magic 10 is because there are 80 bits represented in this attribute, and each element is 8 bits.
+ // So to get to 80, we need 10 bytes.
+ uint8_t l_bad_dq[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM][10] = { 0 };
+ FAPI_TRY( mss::bad_dq_bitmap(i_target, &(l_bad_dq[0][0][0])) );
+
+ return reset_bad_bits_helper(i_target, l_bad_dq);
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Reset the bad-bits masks for a port - helper for ease of testing
+/// @note Read the bad bits from the f/w attributes and stuff them in the
+/// appropriate registers.
+/// @note The magic 10 is because there are 80 bits represented in this attribute, and each element is 8 bits.
+/// So to get to 80, we need 10 bytes.
+/// @param[in] i_target the fapi2 target of the port
+/// @param[in] i_bad_dq array representing the data from the bad dq bitmap
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if bad bits can be repaired
+///
+fapi2::ReturnCode reset_bad_bits_helper( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ const uint8_t i_bad_dq[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM][10] )
+{
+ typedef dp16Traits<TARGET_TYPE_MCA> TT;
+
+ std::vector<uint64_t> l_ranks;
+
+ // Loop over the ranks, makes things simpler than looping over the DIMM (surprisingly)
+ FAPI_TRY( rank::ranks(i_target, l_ranks) );
+
+ for (const auto& r : l_ranks)
+ {
+ uint64_t l_rp = 0;
+ uint64_t l_dimm_index = rank::get_dimm_from_rank(r);
+ FAPI_TRY( mss::rank::get_pair_from_rank(i_target, r, l_rp) );
+
+ FAPI_INF("processing bad bits for DIMM%d rank %d (%d) rp %d", l_dimm_index, mss::index(r), r, l_rp);
+
+ // We loop over the disable registers for this rank pair, and shift the bits from the attribute
+ // array in to the disable registers
+ {
+ // This is the set of registers for this rank pair. It is indexed by DP. We know the bad bits
+ // [0] and [1] are the 16 bits for DP0, [2],[3] are the 16 for DP1, etc.
+ const auto& l_addrs = TT::BIT_DISABLE_REG[l_rp];
+
+ // This is the section of the attribute we need to use. The result is an array of 10 bytes.
+ const uint8_t* l_bad_bits = &(i_bad_dq[l_dimm_index][mss::index(r)][0]);
+
+ // Where in the array we are, incremented by two for every DP
+ size_t l_byte_index = 0;
+
+ for (const auto& a : l_addrs)
+ {
+ uint64_t l_register_value = (l_bad_bits[l_byte_index] << 8) | l_bad_bits[l_byte_index + 1];
+
+ FAPI_INF("writing %s 0x%0lX value 0x%0lX from 0x%X, 0x%X",
+ mss::c_str(i_target), a.first, l_register_value,
+ l_bad_bits[l_byte_index], l_bad_bits[l_byte_index + 1]);
+
+ // TODO RTC: 163674 Only wriiting the DISABLE0 register - not sure what happened to the DQS?
+ FAPI_TRY( mss::putScom(i_target, a.first, l_register_value) );
+ l_byte_index += 2;
+ }
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Write disable bits
+/// @note This is different than a register write as it writes attributes which
+/// cause firmware to act on the disabled bits.
+/// @param[in] i_target the fapi2 target of the port
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if bad bits can be repaired
+///
+fapi2::ReturnCode record_bad_bits( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
+{
+ const auto& l_mcs = mss::find_target<TARGET_TYPE_MCS>(i_target);
+ uint8_t l_value[PORTS_PER_MCS][MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM][10] = { 0 };
+
+ // Process the bad bits into an array. We copy these in to their own array
+ // as it allows the compiler to check indexes where a passed pointer wouldn't
+ // otherwise do.
+ uint8_t l_data[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM][10] = { 0 };
+ FAPI_TRY( mss::dp16::record_bad_bits_helper(i_target, l_data) );
+
+ // Read the attribute
+ FAPI_TRY( mss::bad_dq_bitmap(l_mcs, &(l_value[0][0][0][0])) );
+
+ // Modify
+ memcpy( &(l_value[mss::index(i_target)][0][0][0]), &(l_data[0][0][0]),
+ MAX_DIMM_PER_PORT * MAX_RANK_PER_DIMM * 10 );
+
+ // Write
+ FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_BAD_DQ_BITMAP, l_mcs, l_value) );
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
+///
+/// @brief Write disable bits - helper for testing
+/// @note This is different than a register write as it writes attributes which
+/// cause firmware to act on the disabled bits.
+/// @param[in] i_target the fapi2 target of the port
+/// @param[out] o_bad_dq an array of [MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM][10] containing the attribute information
+/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if bad bits can be repaired
+///
+fapi2::ReturnCode record_bad_bits_helper( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
+ uint8_t (&o_bad_dq)[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM][10] )
+{
+ typedef dp16Traits<TARGET_TYPE_MCA> TT;
+
+ std::vector<uint64_t> l_ranks;
+
+ // Loop over the ranks, makes things simpler than looping over the DIMM (surprisingly)
+ FAPI_TRY( rank::ranks(i_target, l_ranks) );
+
+ for (const auto& r : l_ranks)
+ {
+ uint64_t l_rp = 0;
+ uint64_t l_dimm_index = rank::get_dimm_from_rank(r);
+ FAPI_TRY( mss::rank::get_pair_from_rank(i_target, r, l_rp) );
+
+ FAPI_INF("recording bad bits for DIMM%d rank %d (%d) rp %d", l_dimm_index, mss::index(r), r, l_rp);
+
+ // We loop over the disable registers for this rank pair, and shift the bits from the attribute
+ // array in to the disable registers
+ {
+ // Grab a pointer to our argument simply to make the code a little easier to read
+ uint8_t* l_bad_bits = &(o_bad_dq[l_dimm_index][mss::index(r)][0]);
+
+ // The values we'll pull from the registers in the scom suckah below. We only read the registers for
+ // our current rank pair.
+ std::vector< std::pair< fapi2::buffer<uint64_t>, fapi2::buffer<uint64_t> > > l_register_value;
+
+ FAPI_TRY( mss::scom_suckah(i_target, TT::BIT_DISABLE_REG[l_rp], l_register_value) );
+
+ // Where in the array we are, incremented by two for every DP
+ size_t l_byte_index = 0;
+
+ for (const auto& v : l_register_value)
+ {
+ // Grab the left and right bytes from the bad bits register and stick them in the
+ // nth and nth + 1 bytes of the array
+ l_bad_bits[l_byte_index] = (v.first & 0xFF00) >> 8;
+ l_bad_bits[l_byte_index + 1] = v.first & 0x00FF;
+
+ FAPI_DBG("writing %s value 0x%0lX to 0x%X, 0x%X from 0x%016lx",
+ mss::c_str(i_target),
+ v.first,
+ l_bad_bits[l_byte_index],
+ l_bad_bits[l_byte_index + 1],
+ v.first);
+
+ // TODO RTC: 163674 Only writing the DISABLE0 register - not sure what happened to the DQS?
+ l_byte_index += 2;
+ }
+ }
+ }
+
+fapi_try_exit:
+ return fapi2::current_err;
+}
+
} // close namespace dp16
} // close namespace mss
OpenPOWER on IntegriCloud