diff options
author | Louis Stermole <stermole@us.ibm.com> | 2018-12-06 15:48:40 -0600 |
---|---|---|
committer | Christian R. Geddes <crgeddes@us.ibm.com> | 2019-02-10 22:58:10 -0600 |
commit | 142cc29ed9f71730990bb08f8478233183f7e291 (patch) | |
tree | c9fc2d7190df728311e805437e555b9edf6b1769 | |
parent | 99bfd4be9d12b2bb841d89bcab3cbfebb3c6dff0 (diff) | |
download | talos-hostboot-142cc29ed9f71730990bb08f8478233183f7e291.tar.gz talos-hostboot-142cc29ed9f71730990bb08f8478233183f7e291.zip |
Fix 1-rank row repair case in p9c draminit_training and draminit_mc
Change-Id: I91a83bbee82a01c5c065974afaf9e4291fa071f8
CQ:SW450686
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/69536
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Dev-Ready: Louis Stermole <stermole@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: HWSV CI <hwsv-ci+hostboot@us.ibm.com>
Tested-by: Hostboot CI <hostboot-ci+hostboot@us.ibm.com>
Reviewed-by: STEPHEN GLANCY <sglancy@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/69568
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
7 files changed, 312 insertions, 16 deletions
diff --git a/src/import/chips/centaur/procedures/hwp/memory/lib/shared/dimmConsts.H b/src/import/chips/centaur/procedures/hwp/memory/lib/shared/dimmConsts.H index f3a0052f4..03f1b2a51 100644 --- a/src/import/chips/centaur/procedures/hwp/memory/lib/shared/dimmConsts.H +++ b/src/import/chips/centaur/procedures/hwp/memory/lib/shared/dimmConsts.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2018 */ +/* Contributors Listed Below - COPYRIGHT 2016,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -76,7 +76,8 @@ enum consts : size_t LANES_PER_BLOCK = 16, MAX_BLOCKS_PER_RANK = 5, - MAX_BYTES_PER_BLOCK = 2, + MAX_BYTES_PER_BLOCK = LANES_PER_BLOCK / BITS_PER_BYTE, + MAX_NIBBLES_PER_BLOCK = LANES_PER_BLOCK / BITS_PER_NIBBLE, MAX_BYTES_PER_RANK = MAX_BYTES_PER_BLOCK * MAX_BLOCKS_PER_RANK, LANES_PER_PORT = LANES_PER_BLOCK * MAX_BLOCKS_PER_RANK, diff --git a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_draminit_training.C b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_draminit_training.C index abbe5d013..f45a498fd 100755 --- a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_draminit_training.C +++ b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_draminit_training.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2018 */ +/* Contributors Listed Below - COPYRIGHT 2016,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -50,8 +50,10 @@ #include <p9c_mss_unmask_errors.H> #include "p9c_mss_access_delay_reg.H" #include <p9c_mss_mrs6_DDR4.H> +#include <p9c_mss_row_repair.H> #include <p9c_mss_draminit_training.H> #include <generic/memory/lib/utils/c_str.H> +#include <generic/memory/lib/utils/find.H> #include <dimmConsts.H> #include <delayRegs.H> @@ -1994,6 +1996,10 @@ extern "C" { uint8_t l_port = 0; FAPI_INF("%s Running flash->registers(set)", mss::c_str(i_mba_target)); uint8_t l_prank = 0; + uint8_t l_ranks_per_dimm[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; + uint8_t l_ranks_per_port[MAX_PORTS_PER_MBA] = {0}; + // This vector contains a row repair entry for each DIMM rank + std::vector<fapi2::buffer<uint32_t>> l_repairs_per_dimm; std::vector<fapi2::Target<fapi2::TARGET_TYPE_DIMM>> l_mba_dimms; l_mba_dimms = i_mba_target.getChildren<fapi2::TARGET_TYPE_DIMM>(); @@ -2002,6 +2008,7 @@ extern "C" { FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_PRIMARY_RANK_GROUP2, i_mba_target, l_prg[2])); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_PRIMARY_RANK_GROUP3, i_mba_target, l_prg[3])); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DRAM_WIDTH, i_mba_target, l_dram_width)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_NUM_RANKS_PER_DIMM, i_mba_target, l_ranks_per_dimm)); //DECONFIG and FFDC INFO FAPI_ASSERT(l_dram_width == fapi2::ENUM_ATTR_CEN_EFF_DRAM_WIDTH_X4 @@ -2014,6 +2021,9 @@ extern "C" { l_data_buffer.flush<0>(); + // Calculate the number of ranks on each port + count_ranks_per_port(l_ranks_per_dimm, l_ranks_per_port); + for (l_port = 0; l_port < MAX_PORTS_PER_MBA; l_port ++ ) // [0:1] { l_db_reg_rank0.flush<0>(); @@ -2146,6 +2156,20 @@ extern "C" { continue; } + // 1-rank workaround: Read row repair attribute and build table + if (l_ranks_per_port[l_port] == 1) + { + uint8_t l_row_repair_data[MAX_RANKS_PER_DIMM][ROW_REPAIR_BYTES_PER_RANK] = {0}; + + // Get DIMM target from port/index + fapi2::Target<fapi2::TARGET_TYPE_DIMM> l_dimm_target; + FAPI_TRY(find_dimm_from_index(i_mba_target, l_port, l_dimm, l_dimm_target)); + + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_ROW_REPAIR_DATA, l_dimm_target, l_row_repair_data)); + + FAPI_TRY(build_row_repair_table(l_dimm_target, l_dram_width, l_row_repair_data, l_repairs_per_dimm)); + } + for ( uint8_t i = 0; i < DP18_INSTANCES; ++i ) // dp18 [0:4] { uint8_t l_disable1_data = 0; @@ -2173,7 +2197,7 @@ extern "C" { // clear bits 48:63 l_data_buffer.flush<0>(); - for (uint8_t n = 0; n < 4; n++) // check each nibble + for (uint8_t n = 0; n < MAX_NIBBLES_PER_BLOCK; n++) // check each nibble { l_nmask = l_mask >> (4 * n); @@ -2183,6 +2207,7 @@ extern "C" { l_dimm, l_prank, l_rank, l_data); + // Check if nibble is marked bad on all valid ranks if ( ( ((l_nmask & l_data_rank0) == l_nmask) || (l_rank0_invalid) ) && ( ((l_nmask & l_data_rank1) == l_nmask) || (l_rank1_invalid) ) && ( ((l_nmask & l_data_rank2) == l_nmask) || (l_rank2_invalid) ) && @@ -2192,11 +2217,30 @@ extern "C" { ( ((l_nmask & l_data_rank6) == l_nmask) || (l_rank6_invalid) ) && ( ((l_nmask & l_data_rank7) == l_nmask) || (l_rank7_invalid) ) ) { - //Leave it an F. - FAPI_DBG("BYTE DISABLE WORKAROUND All ranks are a F so writing an 0xF to disable regs."); - FAPI_DBG("BYTE DISABLE WORKAROUND data rank 0 =0x%04X rank 1 =0x%04X rank 2 =0x%04X rank 3 =0x%04X rank 4 =0x%04X rank 5 =0x%04X rank 6 =0x%04X rank 7 =0x%04X", - l_data_rank0, l_data_rank1, l_data_rank2, l_data_rank3, l_data_rank4, l_data_rank5, l_data_rank6, l_data_rank7 ); - l_all_F_mask = 1; + // 1-rank workaround: if there's a row repair requested on this DRAM, don't disable it so we can try training it + bool l_workaround_needed = false; + + if (l_ranks_per_port[l_port] == 1) + { + FAPI_TRY(row_repair_workaround_check(i_mba_target, l_port, l_rank, i, n * BITS_PER_NIBBLE, + l_dram_width, l_repairs_per_dimm, l_workaround_needed)); + + if (l_workaround_needed) + { + FAPI_INF("%s Port %d Rank %d DP%d Nibble %d is marked bad, but has a row repair request. Will not disable this nibble", + mss::c_str(i_mba_target), l_port, l_rank, i, n * BITS_PER_NIBBLE); + l_data = l_data & ~(l_nmask); + } + } + + if (!l_workaround_needed) + { + //Leave it an F. + FAPI_DBG("BYTE DISABLE WORKAROUND All ranks are a F so writing an 0xF to disable regs."); + FAPI_DBG("BYTE DISABLE WORKAROUND data rank 0 =0x%04X rank 1 =0x%04X rank 2 =0x%04X rank 3 =0x%04X rank 4 =0x%04X rank 5 =0x%04X rank 6 =0x%04X rank 7 =0x%04X", + l_data_rank0, l_data_rank1, l_data_rank2, l_data_rank3, l_data_rank4, l_data_rank5, l_data_rank6, l_data_rank7 ); + l_all_F_mask = 1; + } } else { @@ -2439,6 +2483,8 @@ extern "C" { uint8_t l_is_clean = 1; uint8_t l_port = 0; uint8_t l_prank = 0; + uint8_t l_ranks_per_dimm[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0}; + uint8_t l_ranks_per_port[MAX_PORTS_PER_MBA] = {0}; //Storing all the errors across rank/eff dimm fapi2::variable_buffer l_db_reg_dimm0_rank0(LANES_PER_PORT); fapi2::variable_buffer l_db_reg_dimm0_rank1(LANES_PER_PORT); @@ -2448,6 +2494,8 @@ extern "C" { fapi2::variable_buffer l_db_reg_dimm1_rank1(LANES_PER_PORT); fapi2::variable_buffer l_db_reg_dimm1_rank2(LANES_PER_PORT); fapi2::variable_buffer l_db_reg_dimm1_rank3(LANES_PER_PORT); + // This vector contains a row repair entry for each DIMM rank + std::vector<fapi2::buffer<uint32_t>> l_repairs_per_dimm; FAPI_INF("%s Running (get)registers->flash", mss::c_str(i_mba_target)); @@ -2461,6 +2509,7 @@ extern "C" { FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_PRIMARY_RANK_GROUP2, i_mba_target, l_prg[2])); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_PRIMARY_RANK_GROUP3, i_mba_target, l_prg[3])); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DRAM_WIDTH, i_mba_target, l_dram_width)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_NUM_RANKS_PER_DIMM, i_mba_target, l_ranks_per_dimm)); FAPI_ASSERT(l_dram_width == fapi2::ENUM_ATTR_CEN_EFF_DRAM_WIDTH_X4 || l_dram_width == fapi2::ENUM_ATTR_CEN_EFF_DRAM_WIDTH_X8, @@ -2471,6 +2520,9 @@ extern "C" { l_data_buffer.flush<0>(); + // Calculate the number of ranks on each port + count_ranks_per_port(l_ranks_per_dimm, l_ranks_per_port); + for (l_port = 0; l_port < MAX_PORTS_PER_MBA; l_port ++ ) // [0:1] { // Initialize all the stored errors to 0. @@ -2643,6 +2695,19 @@ extern "C" { FAPI_DBG("%s Port%i, dimm=%i, prg%i rank=%i", mss::c_str(i_mba_target), l_port, l_dimm, l_prank, l_rank); + uint8_t l_row_repair_data[MAX_RANKS_PER_DIMM][ROW_REPAIR_BYTES_PER_RANK] = {0}; + // Get DIMM target from port/index + fapi2::Target<fapi2::TARGET_TYPE_DIMM> l_dimm_target; + FAPI_TRY(find_dimm_from_index(i_mba_target, l_port, l_dimm, l_dimm_target)); + + // 1-rank workaround: Read row repair requests for this DIMM + if (l_ranks_per_port[l_port] == 1) + { + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_ROW_REPAIR_DATA, l_dimm_target, l_row_repair_data)); + + FAPI_TRY(build_row_repair_table(l_dimm_target, l_dram_width, l_row_repair_data, l_repairs_per_dimm)); + } + for ( uint8_t i = 0; i < DP18_INSTANCES; ++i ) // dp18 [0:4] { FAPI_TRY(l_db_reg_dimm0_rank0.extract(l_data_rank0, i * 16, 16)); @@ -2696,10 +2761,11 @@ extern "C" { FAPI_TRY(getC4dq2reg(i_mba_target, l_port, l_dimm, l_rank, l_db_reg_vpd, l_is_clean)); FAPI_TRY(l_db_reg_vpd.extract(l_data_curr_vpd, i * 16, 16)); - for (uint8_t n = 0; n < 4; n++) // check each nibble + for (uint8_t n = 0; n < MAX_NIBBLES_PER_BLOCK; n++) // check each nibble { l_nmask = l_mask >> (4 * n); + // Nibble marked bad in bad bits if ((l_nmask & l_data_curr_vpd) == l_nmask) { FAPI_DBG("BYTE DISABLE WORKAROUND: %s Found a 0XF on nibble=%i Port%i, dimm=%i, prg%i rank=%i data= 0x%04X", @@ -2720,6 +2786,7 @@ extern "C" { } else { + // Nibble marked bad in bad bits in all valid ranks if ( ( ((l_nmask & l_data_rank0) == l_nmask) || (l_rank0_invalid) ) && ( ((l_nmask & l_data_rank1) == l_nmask) || (l_rank1_invalid) ) && ( ((l_nmask & l_data_rank2) == l_nmask) || (l_rank2_invalid) ) && @@ -2729,8 +2796,43 @@ extern "C" { ( ((l_nmask & l_data_rank6) == l_nmask) || (l_rank6_invalid) ) && ( ((l_nmask & l_data_rank7) == l_nmask) || (l_rank7_invalid) ) ) { - FAPI_DBG("BYTE DISABLE WORKAROUND: %s All ranks were F's and training was not successful. Uncool.", - mss::c_str(i_mba_target)); + // 1-rank workaround: if training failed on DRAM with row repair request, then clear the request + // and trigger a reconfig loop to re-run training + bool l_workaround_needed = false; + + if (l_ranks_per_port[l_port] == 1) + { + FAPI_TRY(row_repair_workaround_check(i_mba_target, l_port, l_rank, i, n * BITS_PER_NIBBLE, + l_dram_width, l_repairs_per_dimm, l_workaround_needed)); + + if (l_workaround_needed) + { + FAPI_INF("%s Port %d Rank %d DP%d Nibble %d failed training, but has a row repair request. Clearing row repair request", + mss::c_str(i_mba_target), l_port, l_rank, i, n * BITS_PER_NIBBLE); + FAPI_TRY(clear_row_repair_entry(l_rank, l_row_repair_data)); + FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_ROW_REPAIR_DATA, l_dimm_target, l_row_repair_data)); + + FAPI_INF("%s Triggering a reconfig loop due to 1-rank row repair workaround...", + mss::c_str(i_mba_target)); + fapi2::ATTR_RECONFIGURE_LOOP_Type l_reconfigAttr = 0; + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_RECONFIGURE_LOOP, + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_reconfigAttr)); + + // This value makes it look like new bad bits were found during training. + // It is how the PRD code triggers a reconfig when it sets new bad bits in the VPD. + // 'OR' values in case of multiple reasons for reconfigure + l_reconfigAttr |= fapi2::ENUM_ATTR_RECONFIGURE_LOOP_BAD_DQ_BIT_SET; + FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_RECONFIGURE_LOOP, + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_reconfigAttr)); + } + } + + if (!l_workaround_needed) + { + FAPI_DBG("BYTE DISABLE WORKAROUND: %s All ranks were F's and training was not successful. Uncool.", + mss::c_str(i_mba_target)); + } + continue; } else @@ -3308,6 +3410,105 @@ extern "C" { } /// +/// @brief Check row repair requests for a bad nibble and decide whether it affects training +/// @param[in] i_target mba target +/// @param[in] i_port port index +/// @param[in] i_rank rank index +/// @param[in] i_dp DP18 index of nibble in question +/// @param[in] i_lane DP18 lane of nibble in question +/// @param[in] i_dram_width DRAM width +/// @param[in] i_repairs_per_dimm table of row repair requests, from build_row_repair_table +/// @param[out] o_workaround_needed true if the workaround applies (we should train the nibble or clear the row repair request), false if not +/// @return FAPI2_RC_SUCCESS iff successful +/// + bool row_repair_workaround_check(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target, + const uint8_t i_port, + const uint8_t i_rank, + const uint8_t i_dp, + const uint8_t i_lane, + const uint8_t i_dram_width, + const std::vector<fapi2::buffer<uint32_t>> i_repairs_per_dimm, + bool& o_workaround_needed) + { + uint8_t l_dram = 0; + uint8_t l_srank = 0; + uint8_t l_bg = 0; + uint8_t l_bank = 0; + uint32_t l_row = 0; + + o_workaround_needed = false; + + if (valid_row_repair_entry(i_repairs_per_dimm[i_rank], l_dram, l_srank, l_bg, l_bank, l_row)) + { + uint8_t l_phy_lane = 0; + uint8_t l_phy_block = 0; + const auto l_row_repair_nibble = (i_dram_width == fapi2::ENUM_ATTR_EFF_DRAM_WIDTH_X8) ? + l_dram * 2 : + l_dram; + // This guy can't be const because it's not in the mss_c4_phy API + uint8_t l_row_repair_index = l_row_repair_nibble * BITS_PER_NIBBLE; + + // Training works on a phy-perspective, and the row repair attribute is on a Centaur perspective + // so we need to convert the row repair's DRAM into PHY block/lane + FAPI_TRY(mss_c4_phy(i_target, i_port, 0, RD_DQ, l_row_repair_index, 0, l_phy_lane, l_phy_block, 0)); + + // Then normalize the lane to get the 0th bit on the nibble + l_phy_lane = (l_phy_lane / BITS_PER_NIBBLE) * BITS_PER_NIBBLE; + + if ((l_phy_block == i_dp) && (l_phy_lane == i_lane)) + { + o_workaround_needed = true; + } + } + + fapi_try_exit: + return fapi2::current_err; + } + +/// +/// @brief Find a DIMM target on an MBA target, from a port and DIMM index +/// @param[in] i_target mba target +/// @param[in] i_port_index port index +/// @param[in] i_dimm_index DIMM index +/// @param[out] o_dimm DIMM target +/// @return FAPI2_RC_SUCCESS iff successful +/// + fapi2::ReturnCode find_dimm_from_index(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target, + const uint8_t i_port_index, + const uint8_t i_dimm_index, + fapi2::Target<fapi2::TARGET_TYPE_DIMM>& o_dimm) + { + bool l_found_dimm = false; + + // Find DIMM target with this port and dimm index + for (const auto l_dimm_target : mss::find_targets<fapi2::TARGET_TYPE_DIMM>(i_target)) + { + uint8_t l_this_port = 0; + uint8_t l_this_dimm = 0; + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MBA_PORT, l_dimm_target, l_this_port)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MBA_DIMM, l_dimm_target, l_this_dimm)); + + if ((l_this_port == i_port_index) && (l_this_dimm == i_dimm_index)) + { + l_found_dimm = true; + o_dimm = l_dimm_target; + break; // Break out of for loop since we found the DIMM target for this i_port and i_dimm + } + } + + FAPI_ASSERT(l_found_dimm, + fapi2::CEN_DIMM_NOT_FOUND_FROM_INDEX(). + set_MBA(i_target). + set_PORT_INDEX(i_port_index). + set_DIMM_INDEX(i_dimm_index), + "Did not find DIMM for %s, port index:%d dimm index:%d", + mss::c_str(i_target), i_port_index, i_dimm_index); + + fapi_try_exit: + return fapi2::current_err; + } + +/// /// @brief Set non calibrating ranks to wr lvl mode on and qoff disabled during wr lvling /// @param[in] i_target mba target being calibrated /// @param[in] i_port port being calibrated diff --git a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_draminit_training.H b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_draminit_training.H index 3f52b2413..f9cd88555 100755 --- a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_draminit_training.H +++ b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_draminit_training.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2012,2018 */ +/* Contributors Listed Below - COPYRIGHT 2012,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -222,6 +222,39 @@ extern "C" const uint8_t i_state, uint32_t& io_ccs_inst_cnt); +/// +/// @brief Check row repair requests for a bad nibble and decide whether it affects training +/// @param[in] i_target mba target +/// @param[in] i_port port index +/// @param[in] i_rank rank index +/// @param[in] i_dp DP18 index of nibble in question +/// @param[in] i_lane DP18 lane of nibble in question +/// @param[in] i_dram_width DRAM width +/// @param[in] i_repairs_per_dimm table of row repair requests, from build_row_repair_table +/// @param[out] o_workaround_needed true if the workaround applies (we should train the nibble or clear the row repair request), false if not +/// @return FAPI2_RC_SUCCESS iff successful +/// + bool row_repair_workaround_check(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target, + const uint8_t i_port, + const uint8_t i_rank, + const uint8_t i_dp, + const uint8_t i_lane, + const uint8_t i_dram_width, + const std::vector<fapi2::buffer<uint32_t>> i_repairs_per_dimm, + bool& o_workaround_needed); + +/// +/// @brief Find a DIMM target on an MBA target, from a port and DIMM index +/// @param[in] i_target mba target +/// @param[in] i_port_index port index +/// @param[in] i_dimm_index DIMM index +/// @param[out] o_dimm DIMM target +/// @return FAPI2_RC_SUCCESS iff successful +/// + fapi2::ReturnCode find_dimm_from_index(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_target, + const uint8_t i_port_index, + const uint8_t i_dimm_index, + fapi2::Target<fapi2::TARGET_TYPE_DIMM>& o_dimm); } // extern "C" #endif // mss_draminit_training_H_ diff --git a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_draminit_training.mk b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_draminit_training.mk index 40f210764..ea992ee04 100755 --- a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_draminit_training.mk +++ b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_draminit_training.mk @@ -5,7 +5,7 @@ # # OpenPOWER HostBoot Project # -# Contributors Listed Below - COPYRIGHT 2016,2017 +# Contributors Listed Below - COPYRIGHT 2016,2019 # [+] International Business Machines Corp. # # @@ -32,5 +32,7 @@ lib${PROCEDURE}_DEPLIBS+=p9c_mss_mrs6_DDR4 lib${PROCEDURE}_DEPLIBS+=p9c_mss_ddr4_funcs lib${PROCEDURE}_DEPLIBS+=p9c_mss_access_delay_reg lib${PROCEDURE}_DEPLIBS+=p9c_mss_unmask_errors +lib${PROCEDURE}_DEPLIBS+=p9c_mss_rowRepairFuncs +lib${PROCEDURE}_DEPLIBS+=p9c_mss_row_repair $(eval $(call ADD_MEMORY_INCDIRS,$(PROCEDURE))) $(call BUILD_PROCEDURE) diff --git a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_row_repair.C b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_row_repair.C index 823699902..19485c13b 100644 --- a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_row_repair.C +++ b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_row_repair.C @@ -378,17 +378,32 @@ extern "C" /// @param[in] i_dram_width the DRAM width /// @param[in] i_dram the DRAM index /// @param[in] i_rankpair_table table of rank to rank pairs for this port + /// @param[in] i_ranks_on_port number of ranks on this port /// @param[in] i_bad_bits array bad bits data from VPD for all ranks on the port /// @param[out] o_uncalibrated true if DRAM was marked bad in all ranks, false otherwise /// @return FAPI2_RC_SUCCESS iff successful fapi2::ReturnCode check_for_uncalibrated_dram(const uint8_t i_dram_width, const uint8_t i_dram, const uint8_t (&i_rankpair_table)[MAX_RANKS_PER_PORT], + const uint8_t i_ranks_on_port, const uint8_t (&i_bad_bits)[MAX_RANKS_PER_PORT][DIMM_DQ_RANK_BITMAP_SIZE], bool& o_uncalibrated) { constexpr uint8_t NO_RP = 255; + // On a port with only 1 rank configured, we can't tell if a DRAM is uncalibrated or if it just + // failed calibration. + // This is handled in draminit_training by calibrating any DRAM with a row repair request + // (regardless of whether it had bad bits set), and clearing the row repair request if the + // DRAM fails training. So by the time we get here, if we're 1-rank and a row repair + // request exists, we know the DRAM has been calibrated. + if (i_ranks_on_port == 1) + { + FAPI_INF("DRAM index %d was calibrated since it's on a single-rank port", i_dram); + o_uncalibrated = false; + return fapi2::FAPI2_RC_SUCCESS; + } + // The DRAM index in ATTR_ROW_REPAIR_DATA is relative to Centaur perspective. // The bad_bits attribute is as well, so we can just index into the bad bits array // using the DRAM index @@ -566,6 +581,23 @@ extern "C" return fapi2::current_err; } + /// @brief Count the number of ranks per port + /// @param[in] i_target_mba mba target + /// @return FAPI2_RC_SUCCESS iff successful + void count_ranks_per_port(const uint8_t (&i_ranks_per_dimm)[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT], + uint8_t (&o_ranks_per_port)[MAX_PORTS_PER_MBA]) + { + for (uint8_t l_port = 0; l_port < MAX_PORTS_PER_MBA; ++l_port) + { + o_ranks_per_port[l_port] = 0; + + for (uint8_t l_dimm = 0; l_dimm < MAX_DIMM_PER_PORT; ++l_dimm) + { + o_ranks_per_port[l_port] += i_ranks_per_dimm[l_port][l_dimm]; + } + } + } + /// @brief Deploy PPR row repairs, if supported, according to VPD attributes /// @param[in] i_target_mba mba target /// @return FAPI2_RC_SUCCESS iff successful @@ -576,6 +608,8 @@ extern "C" bool l_sppr_supported = true; uint64_t l_mnfg_flags = 0; uint8_t l_dram_width = 0; + uint8_t l_ranks_per_dimm[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT]; + uint8_t l_ranks_per_port[MAX_PORTS_PER_MBA]; uint8_t l_dram = 0; uint8_t l_srank = 0; uint8_t l_bg = 0; @@ -587,6 +621,10 @@ extern "C" FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MNFG_FLAGS, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_mnfg_flags)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DRAM_WIDTH, i_target_mba, l_dram_width)); + FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_NUM_RANKS_PER_DIMM, i_target_mba, l_ranks_per_dimm)); + + // Calculate the number of ranks on each port + count_ranks_per_port(l_ranks_per_dimm, l_ranks_per_port); // If row repairs are not supported, we're done for (const auto& l_dimm : mss::find_targets<fapi2::TARGET_TYPE_DIMM>(i_target_mba)) @@ -681,7 +719,8 @@ extern "C" // If a DRAM position is marked bad in VPD for all valid ranks, skip row repair and clear row repair entry from VPD // as this means the DRAM position has not been calibrated during draminit_training (Centaur workaround) - FAPI_TRY(check_for_uncalibrated_dram(l_dram_width, l_dram, l_rankpair_table, l_bad_bits, l_uncalibrated)); + FAPI_TRY(check_for_uncalibrated_dram(l_dram_width, l_dram, l_rankpair_table, l_ranks_per_port[l_port], + l_bad_bits, l_uncalibrated)); if (l_uncalibrated) { diff --git a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_row_repair.H b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_row_repair.H index 4269f8ba1..233dc92f3 100644 --- a/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_row_repair.H +++ b/src/import/chips/centaur/procedures/hwp/memory/p9c_mss_row_repair.H @@ -88,12 +88,14 @@ extern "C" /// @param[in] i_dram_width the DRAM width /// @param[in] i_dram the DRAM index /// @param[in] i_rankpair_table table of rank to rank pairs for this port + /// @param[in] i_ranks_on_port number of ranks on this port /// @param[in] i_bad_bits array bad bits data from VPD for all ranks on the port /// @param[out] o_uncalibrated true if DRAM was marked bad in all ranks, false otherwise /// @return FAPI2_RC_SUCCESS iff successful fapi2::ReturnCode check_for_uncalibrated_dram(const uint8_t i_dram_width, const uint8_t i_dram, const uint8_t (&i_rankpair_table)[MAX_RANKS_PER_PORT], + const uint8_t i_ranks_on_port, const uint8_t (&i_bad_bits)[MAX_RANKS_PER_PORT][DIMM_DQ_RANK_BITMAP_SIZE], bool& o_uncalibrated); @@ -143,6 +145,12 @@ extern "C" const uint8_t i_dram_width, const uint8_t i_row_repair_data[MAX_RANKS_PER_DIMM][ROW_REPAIR_BYTES_PER_RANK], std::vector<fapi2::buffer<uint32_t>>& o_repairs_per_dimm); + + /// @brief Count the number of ranks per port + /// @param[in] i_target_mba mba target + /// @return FAPI2_RC_SUCCESS iff successful + void count_ranks_per_port(const uint8_t (&i_ranks_per_dimm)[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT], + uint8_t (&o_ranks_per_port)[MAX_PORTS_PER_MBA]); } #endif diff --git a/src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_draminit_training_errors.xml b/src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_draminit_training_errors.xml index cbed4cf8c..306deb5d7 100644 --- a/src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_draminit_training_errors.xml +++ b/src/import/chips/centaur/procedures/xml/error_info/p9c_memory_mss_draminit_training_errors.xml @@ -5,7 +5,7 @@ <!-- --> <!-- OpenPOWER HostBoot Project --> <!-- --> -<!-- Contributors Listed Below - COPYRIGHT 2016,2018 --> +<!-- Contributors Listed Below - COPYRIGHT 2016,2019 --> <!-- [+] International Business Machines Corp. --> <!-- --> <!-- --> @@ -370,4 +370,16 @@ </callout> </hwpError> +<hwpError> + <rc>RC_CEN_DIMM_NOT_FOUND_FROM_INDEX</rc> + <description>A DIMM target could not be found for the given port and DIMM index.</description> + <ffdc>MBA</ffdc> + <ffdc>PORT_INDEX</ffdc> + <ffdc>DIMM_INDEX</ffdc> + <callout> + <procedure>CODE</procedure> + <priority>HIGH</priority> + </callout> +</hwpError> + </hwpErrors> |