/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/import/chips/p9/procedures/hwp/memory/lib/mc/port.C $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2016,2020 */ /* [+] 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 port.C /// @brief Subroutines to manipulate ports (phy + mc for certain operations) /// // *HWP HWP Owner: Stephen Glancy // *HWP HWP Backup: Andre Marin // *HWP Team: Memory // *HWP Level: 3 // *HWP Consumed by: FSP:HB #include #include #include #include #include #include #include #include namespace mss { // Bit position settings for ATTR_MSS_MRW_PERIODIC_MEMCAL_MODE_OPTIONS // For each bit: OFF = 0, ON = 1 // Byte 0: constexpr uint64_t BIT_ZCAL = 0; // 0: ZCAL constexpr uint64_t BIT_SYSCLK_ALIGN = 1; // 1: SYSCK_ALIGN constexpr uint64_t BIT_RDCENTERING = 2; // 2: RDCENTERING constexpr uint64_t BIT_RDLCK_ALIGN = 3; // 3: RDLCK_ALIGN constexpr uint64_t BIT_DQS_ALIGN = 4; // 4: DQS_ALIGN constexpr uint64_t BIT_RDCLK_UPDATE = 5; // 5: RDCLK_UPDATE constexpr uint64_t BIT_PER_DUTYCYCLE = 6; // 6: PER_DUTYCYCLE constexpr uint64_t BIT_PERCAL_PWR_DIS = 7; // 7: PERCAL_PWR_DIS // Byte 1: constexpr uint64_t BIT_PERCAL_REPEAT_0 = 8; // 0: PERCAL_REPEAT constexpr uint64_t BIT_PERCAL_REPEAT_1 = 9; // 1: PERCAL_REPEAT constexpr uint64_t BIT_PERCAL_REPEAT = 10; // 2: PERCAL_REPEAT constexpr uint64_t BIT_SINGLE_BIT_MPR = 11; // 3: SINGLE_BIT_MPR constexpr uint64_t BIT_MBA_CFG_0 = 12; // 4: MBA_CFG_0 constexpr uint64_t BIT_MBA_CFG_1 = 13; // 5: MBA_CFG_1 constexpr uint64_t BIT_SPARE_6 = 14; // 6: SPARE constexpr uint64_t BIT_SPARE_7 = 15; // 7: SPARE /// /// @brief Enable the MC Periodic calibration functionality - MCA specialization /// @param[in] i_target the target /// @return FAPI2_RC_SUCCESS if and only if ok /// template<> fapi2::ReturnCode enable_periodic_cal( const fapi2::Target& i_target ) { typedef portTraits TT; uint32_t l_memcal_interval = 0; uint32_t l_zqcal_interval = 0; fapi2::buffer l_per_memcal_mode_options = 0; fapi2::buffer l_per_zqcal_mode_options = 0; fapi2::buffer l_periodic_cal_config; std::vector l_pairs; FAPI_INF("Enable periodic cal"); uint8_t l_sim = 0; FAPI_TRY( mss::is_simulation(l_sim) ); // Even if we're in sim, do these so that we do the attribute work (even though the values aren't used.) FAPI_TRY( mss::eff_memcal_interval(i_target, l_memcal_interval) ); FAPI_TRY( mss::eff_zqcal_interval(i_target, l_zqcal_interval) ); // TODO RTC: 166433 Leave periodics off (0's) by default for the time being #ifdef TODO_166433_PERIODICS FAPI_TRY( mss::mrw_periodic_memcal_mode_options(l_per_memcal_mode_options) ); FAPI_INF("mrw_periodic_memcal_mode_options: 0x%02x", l_per_memcal_mode_options); FAPI_TRY( mss::mrw_periodic_zqcal_mode_options(l_per_zqcal_mode_options) ); FAPI_INF("mrw_periodic_zqcal_mode_options: 0x%02x", l_per_memcal_mode_options); #endif FAPI_INF("memcal interval %dck, zqcal interval %dck", l_memcal_interval, l_zqcal_interval); { // From Steve Powell, 4/16 // 0xFFFFFFFFFFFFFFF0 fapi2::buffer l_data; l_data.insertFromRight(0b11); l_data.insertFromRight(0b11111111); l_data.insertFromRight(0b11); l_data.insertFromRight(0b11111111); l_data.insertFromRight(0b11); l_data.insertFromRight(0b11111111); l_data.insertFromRight(0b11); l_data.insertFromRight(0b11111111); l_data.insertFromRight(0b11); l_data.insertFromRight(0b11111111); l_data.insertFromRight(0b11); l_data.insertFromRight(0b11111111); l_data.clearBit(); FAPI_TRY( mss::putScom(i_target, TT::CAL3Q_REG, l_data) ); } // ZQCAL if (l_per_zqcal_mode_options != 0) { // // Configure the controller // { // Sim settings from Steve Powell, 4/16 // 11 1111 1111 2222 2222 2233 3333 3333 4444 4444 4455 5555 5555 6666 // 0123 4567 8901 2345 6789 0123 4567 8901 2345 6789 0123 4567 8901 2345 6789 0123 // A 8 0 A 4 0 0 0 0 0 8 0 2 0 0 0 // 1010 1000 0000 1010 0100 0000 0000 0000 0000 0000 1000 0000 0010 0000 0000 0000 fapi2::buffer l_data; // Don't enable zcal in sim as we don't enable it in the PHY l_data.writeBit(l_sim ? 0 : 1); l_data.insertFromRight(0b01); l_data.insertFromRight(0b010000000); l_data.setBit(); l_data.insertFromRight(0b0100); l_data.setBit(); l_data.insertFromRight(0b01000000); l_data.setBit(); FAPI_TRY( mss::putScom(i_target, TT::CAL0Q_REG, l_data) ); FAPI_INF("Periodic ZQ cal: 0x%016lx", l_data); } // // Configure the PHY // // Setup PER_ZCAL_CONFIG based on the number of ranks on the DIMM in either slot. FAPI_TRY( reset_zqcal_config(i_target) ); // No ZQCAL in sim l_periodic_cal_config.writeBit(l_sim ? 0 : 1); // Write the ZQCAL timer reload register // # DPHY01_DDRPHY_PC_ZCAL_TIMER_RELOAD_VALUE_P0 0x00A 0x8000c0090301143f // # PHYW.PHYX.SYNTHX.D3SIDEA.PCX.REG09_L2 // scom 0x8000c0090301143f { // bits , scom_data , expr ; # must be >= 2... // # 0:47 , 0x000000000000, any ; # reserved // 48:63 , ((ATTR_EFF_ZQCAL_INTERVAL/196605)+1), (def_FAST_SIM_PC==0) ; # FAST_SIM_PER_CNTR=0 // 48:63 , ((ATTR_EFF_ZQCAL_INTERVAL/765)+1) , (def_FAST_SIM_PC==1) ; # FAST_SIM_PER_CNTR=1 // # 48:63 , 0x002E , any ; # 46 = 11ms @ 1600MHz { // TODO: 154170 // There is something fishy going on here. The l_zcal_timer_reload math yields 17 bits, however the // insert (seen in the initfile snippet above) truncates it to 16 bits. We do the same here, and // have the story above opened to investigate fapi2::buffer l_zcal_timer_reload; l_zcal_timer_reload.insertFromRight( l_sim ? (l_zqcal_interval / TT::MAGIC_NUMBER_SIM) + 1 : (l_zqcal_interval / TT::MAGIC_NUMBER_NOT_SIM) + 1); FAPI_INF("zcal timer reload: 0x%016lx", l_zcal_timer_reload); FAPI_TRY( mss::putScom(i_target, TT::PHY_ZCAL_TIMER_RELOAD_REG, l_zcal_timer_reload) ); } } // MEMCAL if (l_per_memcal_mode_options != 0) { // Setup the periodic enable rank pair field in the phy cal config and the mc. This used to be shared // between the MC and the PHY in Centaur but no longer is - so we write the same data in two registers. // Note: Why is this vastly different from the rank setup in the zqcal config and why do we // need to do it twice for the PHY? BRS fapi2::buffer l_rank_config; FAPI_TRY( mss::rank::get_rank_pairs(i_target, l_pairs) ); for (const auto pair : l_pairs) { l_rank_config.setBit(pair); } FAPI_INF("periodic ranks: 0x%016lx", l_rank_config); // // Configure the controller // { // From Steve Powell, 4/16 // 11 1111 1111 2222 2222 2233 3333 3333 4444 4444 4455 5555 5555 6666 // 0123 4567 8901 2345 6789 0123 4567 8901 2345 6789 0123 4567 8901 2345 6789 0123 // A 4 0 9 C 0 0 0 0 0 0 0 0 0 0 0 // 1010 0100 0000 1001 1100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 fapi2::buffer l_data; l_data.setBit(); l_data.insertFromRight(0b01); l_data.insertFromRight(0b001000000); l_data.setBit(); l_data.insertFromRight(0b0011); l_data.setBit(); l_data.insert(l_rank_config); FAPI_TRY( mss::putScom(i_target, TT::CAL1Q_REG, l_data) ); FAPI_INF("Periodic memcal enabled 0x%016lx", l_data); } { // From Steve Powell, 4/16. Notice bits are reserved in the scomdef, so re-reviewed // with Steve: "Sorry... ignore those. They seem to have been getting set as part of a gfw scratch // space as they are reserved." SoCAL2Q is 0's // 11 1111 1111 2222 2222 2233 3333 3333 4444 4444 4455 5555 5555 6666 // 0123 4567 8901 2345 6789 0123 4567 8901 2345 6789 0123 4567 8901 2345 6789 0123 // 0 0 0 0 0 0 0 0 0 0 0 1 8 0 0 0 // 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 1000 0000 0000 0000 fapi2::buffer l_data; FAPI_TRY( mss::putScom(i_target, TT::CAL2Q_REG, l_data) ); } // // Configure the PHY // // Centaur init file // # DPHY01_DDRPHY_PC_CAL_TIMER_RELOAD_VALUE_P0 0x008 0x8000c0080301143f // # PHYE.PHYX.SYNTHX.D3SIDEA.PCX.REG08_L2 // scom 0x800(0,1)c0080301143f { # _P[0:1] // bits , scom_data, expr; # must be >= 2... // # 0:47 , 0x000000000000, any ;# reserved // # 48:63 , 0x0000, (def_l_sim) ;# match dials // 48:63 , ((ATTR_EFF_MEMCAL_INTERVAL/196605)+1), (def_FAST_SIM_PC==0) ;# FAST_SIM_PER_CNTR=0 // 48:63 , ((ATTR_EFF_MEMCAL_INTERVAL/765)+1), (def_FAST_SIM_PC==1) ;# FAST_SIM_PER_CNTR=1 // # 48:63 , 0x01D1, any ; # 464 = 114ms @ 1600MHz // Add the ranks to the phy config if (l_per_memcal_mode_options.getBit()) { l_periodic_cal_config.insert(l_rank_config); } // If we're in sim, enable the fast-sim mode l_periodic_cal_config.writeBit(l_sim); l_periodic_cal_config.writeBit( l_per_memcal_mode_options.getBit() ); // Per John Bialas 5/16: "... periodic read centering does not work ... We are re-evaluating fixing it for DD2" #ifdef PERIODIC_READ_CENTERING_FIX l_periodic_cal_config.writeBit( l_per_memcal_mode_options.getBit() ); #endif l_periodic_cal_config.writeBit(l_per_memcal_mode_options.getBit() ); l_periodic_cal_config.writeBit( l_per_memcal_mode_options.getBit() ); // Per John Bialas 5/16: "DD2_FIX_DIS should not be asserted, ie. we do want to use the centaur DD2 fixes" // Write the periodic cal config FAPI_TRY( mss::putScom(i_target, TT::PHY_PERIODIC_CAL_CONFIG_REG, l_periodic_cal_config) ); // Write the periodic cal reload value FAPI_TRY( mss::putScom(i_target, TT::PHY_PERIODIC_CAL_RELOAD_REG, TT::PHY_PERIODIC_CAL_RELOAD_VALUE) ); // Write the cal timer reload // 48:63 , ((ATTR_EFF_MEMCAL_INTERVAL/196605)+1) , (def_FAST_SIM_PC==0) ; # FAST_SIM_PER_CNTR=0 // 48:63 , ((ATTR_EFF_MEMCAL_INTERVAL/765)+1) , (def_FAST_SIM_PC==1) ; # FAST_SIM_PER_CNTR=1 { // TODO: 154170 // There is something fishy going on here. The l_zcal_timer_reload math yields 17 bits, however the // insert (seen in the initfile snippet above) truncates it to 16 bits. We do the same here, and // have the story above opened to investigate fapi2::buffer l_cal_timer_reload; l_cal_timer_reload.insertFromRight( l_sim ? (l_memcal_interval / TT::MAGIC_NUMBER_SIM) + 1 : (l_memcal_interval / TT::MAGIC_NUMBER_NOT_SIM) + 1); FAPI_INF("phy cal timer reload: 0x%016lx", l_cal_timer_reload); FAPI_TRY( mss::putScom(i_target, TT::PHY_CAL_TIMER_RELOAD_REG, l_cal_timer_reload ) ); } } fapi_try_exit: return fapi2::current_err; } /// /// @brief Set up memory controller specific settings for ECC registers (at the end of draminit_mc) /// @param[in] i_target the target /// @param[in,out] io_data contents of RECR register /// @return FAPI2_RC_SUCCESS if and only if ok /// @note mc_type::NIMBUS specialization /// template<> fapi2::ReturnCode ecc_reg_settings_draminit_mc( const fapi2::Target& i_target, fapi2::buffer& io_data ) { return fapi2::FAPI2_RC_SUCCESS; } /// /// @brief Perform a repair for a single bad DQ bit in a nibble /// Specialization for TARGET_TYPE_DIMM /// @param[in,out] io_machine the repair state machine /// @param[in] i_target the DIMM target /// @param[in] i_rank the rank /// @param[in] i_dq the DQ bit index /// @param[in,out] io_repairs_applied 8-bit mask, where a bit set means that rank had repairs applied /// @param[in,out] io_repairs_exceeded 2-bit mask, where a bit set means that DIMM had more bad bits than could be repaired /// @return FAPI2_RC_SUCCESS if and only if ok /// template<> fapi2::ReturnCode no_fails::one_bad_dq(repair_state_machine& io_machine, const fapi2::Target& i_target, const uint64_t i_rank, const uint64_t i_dq, fapi2::buffer& io_repairs_applied, fapi2::buffer& io_repairs_exceeded) { // place a symbol mark FAPI_TRY( place_symbol_mark(i_target, i_rank, i_dq) ); io_repairs_applied.setBit(i_rank); { const auto new_state = std::make_shared>(); set_state(io_machine, new_state); } fapi_try_exit: return fapi2::current_err; } /// /// @brief Perform a repair for multiple bad DQ bits in a nibble /// Specialization for TARGET_TYPE_DIMM /// @param[in,out] io_machine the repair state machine /// @param[in] i_target the DIMM target /// @param[in] i_rank the rank /// @param[in] i_dq one of the bad DQ bit indexes /// @param[in,out] io_repairs_applied 8-bit mask, where a bit set means that rank had repairs applied /// @param[in,out] io_repairs_exceeded 2-bit mask, where a bit set means that DIMM had more bad bits than could be repaired /// @return FAPI2_RC_SUCCESS if and only if ok /// template<> fapi2::ReturnCode no_fails::multiple_bad_dq(repair_state_machine& io_machine, const fapi2::Target& i_target, const uint64_t i_rank, const uint64_t i_dq, fapi2::buffer& io_repairs_applied, fapi2::buffer& io_repairs_exceeded) { // place a chip mark FAPI_TRY( place_chip_mark(i_target, i_rank, i_dq) ); io_repairs_applied.setBit(i_rank); { const auto new_state = std::make_shared>(); set_state(io_machine, new_state); } fapi_try_exit: return fapi2::current_err; } /// /// @brief Perform a repair for a single bad DQ bit in a nibble /// Specialization for TARGET_TYPE_DIMM /// @param[in,out] io_machine the repair state machine /// @param[in] i_target the DIMM target /// @param[in] i_rank the rank /// @param[in] i_dq the DQ bit index /// @param[in,out] io_repairs_applied 8-bit mask, where a bit set means that rank had repairs applied /// @param[in,out] io_repairs_exceeded 2-bit mask, where a bit set means that DIMM had more bad bits than could be repaired /// @return FAPI2_RC_SUCCESS if and only if ok /// template<> fapi2::ReturnCode symbol_mark_only::one_bad_dq(repair_state_machine& io_machine, const fapi2::Target& i_target, const uint64_t i_rank, const uint64_t i_dq, fapi2::buffer& io_repairs_applied, fapi2::buffer& io_repairs_exceeded) { // leave an unrepaired DQ const auto new_state = std::make_shared>(); set_state(io_machine, new_state); return fapi2::FAPI2_RC_SUCCESS; } /// /// @brief Perform a repair for multiple bad DQ bits in a nibble /// Specialization for TARGET_TYPE_DIMM /// @param[in,out] io_machine the repair state machine /// @param[in] i_target the DIMM target /// @param[in] i_rank the rank /// @param[in] i_dq one of the bad DQ bit indexes /// @param[in,out] io_repairs_applied 8-bit mask, where a bit set means that rank had repairs applied /// @param[in,out] io_repairs_exceeded 2-bit mask, where a bit set means that DIMM had more bad bits than could be repaired /// @return FAPI2_RC_SUCCESS if and only if ok /// template<> fapi2::ReturnCode symbol_mark_only::multiple_bad_dq( repair_state_machine& io_machine, const fapi2::Target& i_target, const uint64_t i_rank, const uint64_t i_dq, fapi2::buffer& io_repairs_applied, fapi2::buffer& io_repairs_exceeded) { // place a chip mark FAPI_TRY( place_chip_mark(i_target, i_rank, i_dq) ); io_repairs_applied.setBit(i_rank); { const auto new_state = std::make_shared>(); set_state(io_machine, new_state); } fapi_try_exit: return fapi2::current_err; } /// /// @brief Perform a repair for a single bad DQ bit in a nibble /// Specialization for TARGET_TYPE_DIMM /// @param[in,out] io_machine the repair state machine /// @param[in] i_target the DIMM target /// @param[in] i_rank the rank /// @param[in] i_dq the DQ bit index /// @param[in,out] io_repairs_applied 8-bit mask, where a bit set means that rank had repairs applied /// @param[in,out] io_repairs_exceeded 2-bit mask, where a bit set means that DIMM had more bad bits than could be repaired /// @return FAPI2_RC_SUCCESS if and only if ok /// template<> fapi2::ReturnCode symbol_mark_plus_unrepaired_dq::one_bad_dq( repair_state_machine& io_machine, const fapi2::Target& i_target, const uint64_t i_rank, const uint64_t i_dq, fapi2::buffer& io_repairs_applied, fapi2::buffer& io_repairs_exceeded) { // repairs exceeded FAPI_INF("%s Repairs exceeded (symbol mark and unrepaired DQ exist, plus bad DQ) on rank:%d DQ:%d", mss::c_str(i_target), i_rank, i_dq); io_repairs_exceeded.setBit(mss::index(i_target)); return fapi2::FAPI2_RC_SUCCESS; } /// /// @brief Perform a repair for multiple bad DQ bits in a nibble /// Specialization for TARGET_TYPE_DIMM /// @param[in,out] io_machine the repair state machine /// @param[in] i_target the DIMM target /// @param[in] i_rank the rank /// @param[in] i_dq one of the bad DQ bit indexes /// @param[in,out] io_repairs_applied 8-bit mask, where a bit set means that rank had repairs applied /// @param[in,out] io_repairs_exceeded 2-bit mask, where a bit set means that DIMM had more bad bits than could be repaired /// @return FAPI2_RC_SUCCESS if and only if ok /// template<> fapi2::ReturnCode symbol_mark_plus_unrepaired_dq::multiple_bad_dq( repair_state_machine& io_machine, const fapi2::Target& i_target, const uint64_t i_rank, const uint64_t i_dq, fapi2::buffer& io_repairs_applied, fapi2::buffer& io_repairs_exceeded) { // place a chip mark, but also repairs exceeded FAPI_TRY( place_chip_mark(i_target, i_rank, i_dq) ); io_repairs_applied.setBit(i_rank); io_repairs_exceeded.setBit(mss::index(i_target)); FAPI_INF("%s Repairs exceeded (symbol mark and unrepaired DQ exist, plus bad nibble) on rank:%d DQ:%d", mss::c_str(i_target), i_rank, i_dq); { const auto new_state = std::make_shared>(); set_state(io_machine, new_state); } fapi_try_exit: return fapi2::current_err; } /// /// @brief Perform a repair for a single bad DQ bit in a nibble /// Specialization for TARGET_TYPE_DIMM /// @param[in,out] io_machine the repair state machine /// @param[in] i_target the DIMM target /// @param[in] i_rank the rank /// @param[in] i_dq the DQ bit index /// @param[in,out] io_repairs_applied 8-bit mask, where a bit set means that rank had repairs applied /// @param[in,out] io_repairs_exceeded 2-bit mask, where a bit set means that DIMM had more bad bits than could be repaired /// @return FAPI2_RC_SUCCESS if and only if ok /// template<> fapi2::ReturnCode chip_mark_only::one_bad_dq( repair_state_machine& io_machine, const fapi2::Target& i_target, const uint64_t i_rank, const uint64_t i_dq, fapi2::buffer& io_repairs_applied, fapi2::buffer& io_repairs_exceeded) { // place a symbol mark FAPI_TRY( place_symbol_mark(i_target, i_rank, i_dq) ); io_repairs_applied.setBit(i_rank); { const auto new_state = std::make_shared>(); set_state(io_machine, new_state); } fapi_try_exit: return fapi2::current_err; } /// /// @brief Perform a repair for multiple bad DQ bits in a nibble /// Specialization for TARGET_TYPE_DIMM /// @param[in,out] io_machine the repair state machine /// @param[in] i_target the DIMM target /// @param[in] i_rank the rank /// @param[in] i_dq one of the bad DQ bit indexes /// @param[in,out] io_repairs_applied 8-bit mask, where a bit set means that rank had repairs applied /// @param[in,out] io_repairs_exceeded 2-bit mask, where a bit set means that DIMM had more bad bits than could be repaired /// @return FAPI2_RC_SUCCESS if and only if ok /// template<> fapi2::ReturnCode chip_mark_only::multiple_bad_dq( repair_state_machine& io_machine, const fapi2::Target& i_target, const uint64_t i_rank, const uint64_t i_dq, fapi2::buffer& io_repairs_applied, fapi2::buffer& io_repairs_exceeded) { // repairs exceeded io_repairs_exceeded.setBit(mss::index(i_target)); FAPI_INF("%s Repairs exceeded (chip mark exists, plus bad nibble) on rank:%d DQ:%d", mss::c_str(i_target), i_rank, i_dq); return fapi2::FAPI2_RC_SUCCESS; } /// /// @brief Perform a repair for a single bad DQ bit in a nibble /// Specialization for TARGET_TYPE_DIMM /// @param[in,out] io_machine the repair state machine /// @param[in] i_target the DIMM target /// @param[in] i_rank the rank /// @param[in] i_dq the DQ bit index /// @param[in,out] io_repairs_applied 8-bit mask, where a bit set means that rank had repairs applied /// @param[in,out] io_repairs_exceeded 2-bit mask, where a bit set means that DIMM had more bad bits than could be repaired /// @return FAPI2_RC_SUCCESS if and only if ok /// template<> fapi2::ReturnCode chip_and_symbol_mark::one_bad_dq( repair_state_machine& io_machine, const fapi2::Target& i_target, const uint64_t i_rank, const uint64_t i_dq, fapi2::buffer& io_repairs_applied, fapi2::buffer& io_repairs_exceeded) { // repairs exceeded io_repairs_exceeded.setBit(mss::index(i_target)); FAPI_INF("%s Repairs exceeded (chip mark and symbol mark exist, plus one bad DQ) on rank:%d DQ:%d", mss::c_str(i_target), i_rank, i_dq); return fapi2::FAPI2_RC_SUCCESS; } /// /// @brief Perform a repair for multiple bad DQ bits in a nibble /// Specialization for TARGET_TYPE_DIMM /// @param[in,out] io_machine the repair state machine /// @param[in] i_target the DIMM target /// @param[in] i_rank the rank /// @param[in] i_dq one of the bad DQ bit indexes /// @param[in,out] io_repairs_applied 8-bit mask, where a bit set means that rank had repairs applied /// @param[in,out] io_repairs_exceeded 2-bit mask, where a bit set means that DIMM had more bad bits than could be repaired /// @return FAPI2_RC_SUCCESS if and only if ok /// template<> fapi2::ReturnCode chip_and_symbol_mark::multiple_bad_dq( repair_state_machine& io_machine, const fapi2::Target& i_target, const uint64_t i_rank, const uint64_t i_dq, fapi2::buffer& io_repairs_applied, fapi2::buffer& io_repairs_exceeded) { // repairs exceeded io_repairs_exceeded.setBit(mss::index(i_target)); FAPI_INF("%s Repairs exceeded (chip mark and symbol mark exist, plus one bad nibble) on rank:%d DQ:%d", mss::c_str(i_target), i_rank, i_dq); return fapi2::FAPI2_RC_SUCCESS; } } // ns mss