/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/import/generic/memory/lib/utils/mc/gen_mss_port.H $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2018,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 gen_mss_port.H /// @brief Code to support ports /// // *HWP HWP Owner: Stephen Glancy // *HWP HWP Backup: Andre Marin // *HWP Team: Memory // *HWP Level: 3 // *HWP Consumed by: HB:FSP #ifndef _GEN_MSS_PORT_H_ #define _GEN_MSS_PORT_H_ #include #include #include #include #include #include #include #include #include namespace mss { /// /// @brief Reads the farb0q register /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @param[out] o_data data read from the register /// @return FAPI2_RC_SUCCESS if and only if ok /// @note Disable Port Fail after recurring RCD errors. /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode read_farb0q( const fapi2::Target& i_target, fapi2::buffer& o_data ) { FAPI_TRY( mss::getScom(i_target, TT::FARB0Q_REG, o_data) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Writes the farb0q register /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @param[in] i_data data read from the register /// @return FAPI2_RC_SUCCESS if and only if ok /// @note Disable Port Fail after recurring RCD errors. /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode write_farb0q( const fapi2::Target& i_target, const fapi2::buffer& i_data ) { FAPI_TRY( mss::putScom(i_target, TT::FARB0Q_REG, i_data) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Reads the farb6q register /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @param[out] o_data data read from the register /// @return FAPI2_RC_SUCCESS if and only if ok /// @note Disable Port Fail after recurring RCD errors. /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode read_farb6q( const fapi2::Target& i_target, fapi2::buffer& o_data ) { FAPI_TRY( mss::getScom(i_target, TT::FARB6Q_REG, o_data) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Writes the farb6q register /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @param[in] i_data data read from the register /// @return FAPI2_RC_SUCCESS if and only if ok /// @note Disable Port Fail after recurring RCD errors. /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode write_farb6q( const fapi2::Target& i_target, const fapi2::buffer& i_data ) { FAPI_TRY( mss::putScom(i_target, TT::FARB6Q_REG, i_data) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Gets the bandwidth window data /// @tparam MC the memory controller type /// @tparam TT the class traits for the port /// @param[in] i_data data read from the register /// @param[out] o_bw_window /// @return FAPI2_RC_SUCCESS if and only if ok /// @note Disable Port Fail after recurring RCD errors. /// template< mss::mc_type MC = DEFAULT_MC_TYPE, typename TT = portTraits > void get_bw_window( const fapi2::buffer& i_data, uint64_t& o_bw_window ) { o_bw_window = 0; i_data.extractToRight(o_bw_window); } /// /// @brief Gets the bandwidth snapshot /// @tparam MC the memory controller type /// @tparam TT the class traits for the port /// @param[in] i_data data read from the register /// @param[out] o_bw_snapshot /// @return FAPI2_RC_SUCCESS if and only if ok /// @note Disable Port Fail after recurring RCD errors. /// template< mss::mc_type MC = DEFAULT_MC_TYPE, typename TT = portTraits > void get_bw_snapshot( const fapi2::buffer& i_data, uint64_t& o_bw_snapshot ) { o_bw_snapshot = 0; i_data.extractToRight(o_bw_snapshot); } /// /// @brief ATTR_MSS_MVPD_FWMS getter declare /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @param[in] const ref to the fapi2::Target /// @param[out] uint32_t* memory to store the value /// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK /// @note Mark store records from MPVD Lx keyword /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T> fapi2::ReturnCode mvpd_fwms(const fapi2::Target< T>& i_target, uint32_t (&o_array)[MARK_STORE_COUNT]); /// /// @brief Enable power management /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @return FAPI2_RC_SUCCESS if and only if ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode enable_power_management( const fapi2::Target& i_target ) { //Enable Power management based off of mrw_power_control_requested FAPI_INF("%s Enable Power min max domains", mss::c_str(i_target)); bool is_pwr_cntrl = true; fapi2::buffer l_data; uint8_t l_pwr_cntrl = 0; // Get the value from attribute and write it to scom register FAPI_TRY(fapi2::getScom(i_target, TT::MBARPC0Q_REG, l_data)); FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_POWER_CONTROL_REQUESTED, fapi2::Target(), l_pwr_cntrl)); is_pwr_cntrl = ((l_pwr_cntrl == fapi2::ENUM_ATTR_MSS_MRW_POWER_CONTROL_REQUESTED_POWER_DOWN) || (l_pwr_cntrl == fapi2::ENUM_ATTR_MSS_MRW_IDLE_POWER_CONTROL_REQUESTED_PD_AND_STR) || (l_pwr_cntrl == fapi2::ENUM_ATTR_MSS_MRW_IDLE_POWER_CONTROL_REQUESTED_PD_AND_STR_CLK_STOP)); l_data.writeBit< TT::CFG_MIN_MAX_DOMAINS_ENABLE>(is_pwr_cntrl); FAPI_TRY( fapi2::putScom(i_target, TT::MBARPC0Q_REG, l_data) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Set the IML init complete bit /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @param[in] i_state the state /// @return FAPI2_RC_SUCCESS if and only if ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode change_iml_complete( const fapi2::Target& i_target, states i_state ) { fapi2::buffer l_data; FAPI_DBG("Change the IML init complete bit to high for %s %s", (i_state == HIGH ? "high" : "low"), mss::c_str(i_target)); FAPI_TRY( mss::getScom(i_target, TT::PMU8Q_REG, l_data) ); l_data.writeBit(i_state); FAPI_TRY( mss::putScom(i_target, TT::PMU8Q_REG, l_data) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Read the read ECC Control register /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @param[out] o_buffer the buffer to write the register data into /// @return FAPI2_RC_SUCCESS if and only if ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode read_recr_register( const fapi2::Target& i_target, fapi2::buffer& o_buffer ) { FAPI_TRY( mss::getScom(i_target, TT::ECC_REG, o_buffer) ); FAPI_INF( "Read ECC Control register is 0x%016lx for %s", uint64_t(o_buffer), mss::c_str(i_target) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Write to RECR register /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @param[in] i_buffer the buffer that holds the register data to write /// @return FAPI2_RC_SUCCESS if and only if ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode write_recr_register( const fapi2::Target& i_target, const fapi2::buffer& i_buffer ) { FAPI_INF( "Change Read ECC Control register to 0x%016lx for %s", i_buffer, mss::c_str(i_target) ); FAPI_TRY( mss::putScom(i_target, TT::ECC_REG, i_buffer) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Get the tce correction enable value from RECR /// @tparam MC the memory controller type /// @tparam TT the class traits for the port /// @param[in] i_data the data buffer containing the RECR register /// @param[out] o_value TCE_CORRECTION_ENABLE value (on or off) /// template< mss::mc_type MC = DEFAULT_MC_TYPE, typename TT = portTraits > void get_tce_correction( const fapi2::buffer& i_data, mss::states& o_value ) { o_value = i_data.template getBit() ? mss::states::ON : mss::states::OFF; FAPI_INF( "TCE_CORRECTION_ENABLE: %lu", o_value ); } /// /// @brief Sets tce correction enable in buffer /// @tparam MC the memory controller type /// @tparam TT the class traits for the port /// @param[in,out] io_data the target data buffer /// @param[in] i_value TCE_CORRECTION_ENABLE value (on or off) to set /// template< mss::mc_type MC = DEFAULT_MC_TYPE, typename TT = portTraits > void set_tce_correction( fapi2::buffer& io_data, const mss::states i_value ) { FAPI_INF( "Set TCE_CORRECTION_ENABLE to %lu", i_value); io_data.template writeBit(i_value); } /// /// @brief Setup TCE correction /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @return FAPI2_RC_SUCCESS if and only if ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode setup_tce_correction (const fapi2::Target& i_target) { constexpr uint64_t MNFG_REPAIRS_DISABLED_ATTR = 56; fapi2::buffer l_data; fapi2::buffer l_mnfg_buffer; mss::states l_state = mss::OFF; FAPI_TRY( mss::read_recr_register(i_target, l_data ), "%s: Failed read_recr_register", mss::c_str(i_target)); // Check for manufacturing disable dram repair flag to disable TCE correction FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_MNFG_FLAGS, fapi2::Target(), l_mnfg_buffer), "%s: Failed mnfg_flags check", mss::c_str(i_target) ); l_state = ( l_mnfg_buffer.getBit() ) ? mss::OFF : mss::ON; mss::set_tce_correction(l_data, l_state); FAPI_TRY( mss::write_recr_register(i_target, l_data), "%s: Failed write_recr_register", mss::c_str(i_target)); fapi_try_exit: return fapi2::current_err; } /// /// @brief Change the state of the port_fail_disable bit /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @param[in] i_state the state /// @return FAPI2_RC_SUCCESS if and only if ok /// @note Disable Port Fail after recurring RCD errors. /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode change_port_fail_disable( const fapi2::Target& i_target, states i_state ) { fapi2::buffer l_data; FAPI_DBG("Change port fail disable to %s %s", (i_state == HIGH ? "high" : "low"), mss::c_str(i_target)); FAPI_TRY( mss::getScom(i_target, TT::FARB0Q_REG, l_data) ); l_data.writeBit(i_state); FAPI_TRY( mss::putScom(i_target, TT::FARB0Q_REG, l_data) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Change the state of the dfi init start bit /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @param[in] i_state the state /// @return FAPI2_RC_SUCCESS if and only if ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode change_dfi_init_start( const fapi2::Target& i_target, states i_state ) { fapi2::buffer l_data; FAPI_DBG("Change rcd recovery disable to %s %s", (i_state == HIGH ? "high" : "low"), mss::c_str(i_target)); FAPI_TRY( mss::getScom(i_target, TT::FARB0Q_REG, l_data) ); l_data.writeBit(i_state); FAPI_TRY( mss::putScom(i_target, TT::FARB0Q_REG, l_data) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Change the state of the addr_mux_sel bit /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @param[in] i_state the state /// @return FAPI2_RC_SUCCESS if and only if ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode change_addr_mux_sel( const fapi2::Target& i_target, states i_state ) { fapi2::buffer l_data; FAPI_DBG("Change addr_mux_sel to %s %s", (i_state == HIGH ? "high" : "low"), mss::c_str(i_target)); FAPI_TRY( mss::getScom(i_target, TT::FARB5Q_REG, l_data) ); l_data.writeBit(i_state); FAPI_TRY( mss::putScom(i_target, TT::FARB5Q_REG, l_data) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Change the state of the force_str bit /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @param[in] i_state the state /// @return FAPI2_RC_SUCCESS if and only if ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode change_force_str( const fapi2::Target& i_target, const states i_state ); /// /// @brief Change the state of the MC Refresh enable bit /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @param[in] i_state the state /// @return FAPI2_RC_SUCCESS if and only if ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode change_refresh_enable( const fapi2::Target& i_target, states i_state ) { fapi2::buffer l_data; FAPI_DBG("Change refresh enable to %s %s", (i_state == HIGH ? "high" : "low"), mss::c_str(i_target)); FAPI_TRY( mss::getScom(i_target, TT::REFRESH_REG, l_data) ); l_data.writeBit(i_state); FAPI_TRY( mss::putScom(i_target, TT::REFRESH_REG, l_data) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Enable periodic zq cal /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @return FAPI2_RC_SUCCESS if and only if ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode enable_zq_cal( const fapi2::Target& i_target ) { fapi2::buffer l_data; FAPI_DBG("Enable periodic zq cal for %s", mss::c_str(i_target)); FAPI_TRY( mss::getScom(i_target, TT::FARB9Q_REG, l_data) ); l_data.writeBit(mss::HIGH); FAPI_TRY( mss::putScom(i_target, TT::FARB9Q_REG, l_data) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Set up memory controller specific settings for ECC registers (at the end of draminit_mc) /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @param[in,out] io_data contents of RECR register /// @return FAPI2_RC_SUCCESS if and only if ok /// template< mss::mc_type MC, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode ecc_reg_settings_draminit_mc( const fapi2::Target& i_target, fapi2::buffer& io_data ); /// /// @brief Enable Read ECC checking /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the target /// @return FAPI2_RC_SUCCESS if and only if ok /// template< mss::mc_type MC, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode enable_read_ecc( const fapi2::Target& i_target ) { constexpr uint8_t RECR_MBSECCQ_DATA_INVERSION_NO_INVERSION = 0b00; constexpr uint8_t RECR_MBSECCQ_DATA_INVERSION_INVERT_DATA_TOGGLE_CHECKS = 0b11; fapi2::buffer l_data; uint8_t l_sim = 0; FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target(), l_sim) ); FAPI_DBG("Enable Read ECC %s", mss::c_str(i_target)); FAPI_TRY( mss::getScom(i_target, TT::ECC_REG, l_data) ); l_data.clearBit(); l_data.clearBit(); // VBU tests assume good ECC and we don't have good ECC (since we're not writing everything) // so we can't run with address checking. Disable address checking in sim. l_data.writeBit(l_sim ? mss::states::LOW : mss::states::HIGH); // The preferred operating mode is 11 (INVERT_DATA_TOGGLE_CHECKS) which stores data complemented // (because most bits are '0', and the dram bus pulls up, so transmitting 1s is least power) but // still flips the inversion of check bits to aid RAS. Per Brad Michael 12/15 // Leave un-inverted for sim. This allows the DIMM loader to write 0's and effect good ECC l_data.insertFromRight(l_sim ? RECR_MBSECCQ_DATA_INVERSION_NO_INVERSION : RECR_MBSECCQ_DATA_INVERSION_INVERT_DATA_TOGGLE_CHECKS); FAPI_TRY( ecc_reg_settings_draminit_mc(i_target, l_data) ); // bits: 60 MBSTRQ_CFG_MAINT_RCE_WITH_CE // cfg_maint_rce_with_ce - not implemented. Need to investigate if needed for nimbus. FAPI_TRY( mss::putScom(i_target, TT::ECC_REG, l_data) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Apply mark store bits from module VPD /// @tparam MC the memory controller type /// @tparam T, the fapi2 target type of the target /// @tparam TT, the class traits for the port /// @param[in] i_target A target representing a port /// @return FAPI2_RC_SUCCESS if and only if ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > fapi2::ReturnCode apply_mark_store( const fapi2::Target& i_target ) { FAPI_INF("Enable marks from MVPD %s", mss::c_str(i_target)); uint32_t l_fwms[MARK_STORE_COUNT]; FAPI_TRY( mss::mvpd_fwms(i_target, l_fwms) ); for (size_t l_mark = 0; l_mark < MARK_STORE_COUNT; ++l_mark) { if (l_fwms[l_mark] != 0) { fapi2::buffer l_fwms_data; // This assumes the attribute contents are in the same format as the register fields, // ending just before the EXIT_1 bit l_fwms_data.insertFromRight < TT::FWMS0_MARK, TT::FWMS0_EXIT_1 - TT::FWMS0_MARK + 1 > (l_fwms[l_mark]); FAPI_TRY( mss::putScom(i_target, TT::FWMS_REG + l_mark, l_fwms_data) ); } } fapi_try_exit: return fapi2::current_err; } /// /// @brief Configures the write reorder queue bit /// @tparam MC the memory controller type /// @tparam T, the mc /// @tparam TT, the class traits for the port /// @param[in] i_target the target to effect /// @param[in] i_state to set the bit too /// @return FAPI2_RC_SUCCSS iff ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > inline fapi2::ReturnCode configure_wrq(const fapi2::Target& i_target, const mss::states i_state) { // Loops through all port targets, hitting all the registers for( const auto& l_port : mss::find_targets(i_target) ) { fapi2::buffer l_data; // Gets the reg FAPI_TRY(mss::getScom(l_port, TT::WRQ_REG, l_data), "%s failed to getScom from WRQ0Q", mss::c_str(l_port)); // Sets the bit l_data.writeBit(i_state == mss::states::ON); // Sets the regs FAPI_TRY(mss::putScom(l_port, TT::WRQ_REG, l_data), "%s failed to putScom to WRQ0Q", mss::c_str(l_port)); } // In case we don't have any port's return fapi2::FAPI2_RC_SUCCESS; fapi_try_exit: return fapi2::current_err; } /// /// @brief Configures the read reorder queue bit /// @tparam MC the memory controller type /// @tparam T, the mc /// @tparam TT, the class traits for the port /// @param[in] i_target the target to effect /// @param[in] i_state to set the bit too /// @return FAPI2_RC_SUCCSS iff ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > inline fapi2::ReturnCode configure_rrq(const fapi2::Target& i_target, const mss::states i_state) { // Loops through all port targets, hitting all the registers for( const auto& l_port : mss::find_targets(i_target) ) { fapi2::buffer l_data; // Gets the reg FAPI_TRY(mss::getScom(l_port, TT::RRQ_REG, l_data), "%s failed to getScom from RRQ0Q", mss::c_str(l_port)); // Sets the bit l_data.writeBit(i_state == mss::states::ON); // Sets the regs FAPI_TRY(mss::putScom(l_port, TT::RRQ_REG, l_data), "%s failed to putScom to RRQ0Q", mss::c_str(l_port)); } // In case we don't have any port's return fapi2::FAPI2_RC_SUCCESS; fapi_try_exit: return fapi2::current_err; } /// /// @brief Place a symbol mark in a Firmware Mark Store register /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the DIMM target /// @param[in] i_rank the rank /// @param[in] i_dq the bad DQ bit /// @return FAPI2_RC_SUCCESS if and only if ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > inline fapi2::ReturnCode place_symbol_mark(const fapi2::Target& i_target, const uint64_t i_rank, const uint64_t i_dq) { const auto& l_port = mss::find_target(i_target); const auto l_dimm_idx = mss::index(i_target); const auto l_rank_idx = mss::index(i_rank); uint8_t l_galois = 0; mss::mcbist::address l_addr; // For symbol marks, we set the appropriate Firmware Mark Store reg, with the symbol's // Galois code, mark_type=SYMBOL, mark_region=MRANK, and the address of the DIMM+MRANK // TODO RTC:165133 Remove static_cast once Galois API is updated to accept uint64_t input FAPI_TRY( mss::ecc::dq_to_galois(static_cast(i_dq), l_galois) ); l_addr.set_dimm(l_dimm_idx).set_master_rank(l_rank_idx); FAPI_INF("%s Setting firmware symbol mark on rank:%d dq:%d galois:0x%02x", mss::c_str(i_target), i_rank, i_dq, l_galois); FAPI_TRY( mss::ecc::set_fwms(l_port, i_rank, l_galois, mss::ecc::fwms::mark_type::SYMBOL, mss::ecc::fwms::mark_region::MRANK, l_addr) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Place a chip mark in a Hardware Mark Store register /// @tparam MC the memory controller type /// @tparam T the fapi2 target type of the target /// @tparam TT the class traits for the port /// @param[in] i_target the DIMM target /// @param[in] i_rank the rank /// @param[in] i_dq one of the bad DQ bits in the bad nibble /// @return FAPI2_RC_SUCCESS if and only if ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > inline fapi2::ReturnCode place_chip_mark(const fapi2::Target& i_target, const uint64_t i_rank, const uint64_t i_dq) { const auto& l_port = mss::find_target(i_target); uint8_t l_galois = 0; uint8_t l_symbol = 0; // For chip marks, we set the appropriate Hardware Mark Store reg, with the Galois code // of the first (smallest) symbol in the bad nibble, and both confirmed and exit1 bits set FAPI_TRY( mss::ecc::dq_to_symbol(static_cast(i_dq), l_symbol) ); // Round down to the nearest "nibble" to get the correct symbol, then get the Galois code for it l_symbol = (l_symbol / BITS_PER_NIBBLE) * BITS_PER_NIBBLE; FAPI_TRY( mss::ecc::symbol_to_galois(l_symbol, l_galois) ); FAPI_INF("%s Setting hardware (chip) mark on rank:%d galois:0x%02x", mss::c_str(i_target), i_rank, l_galois); FAPI_TRY( mss::ecc::set_hwms(l_port, i_rank, l_galois) ); fapi_try_exit: return fapi2::current_err; } // Forward declaration for use in repair_state classes template< fapi2::TargetType T > class repair_state_machine; /// /// @class mss::repair_state /// @brief A class for keeping track of bad bit repair states in a repair_state_machine /// @tparam T, the fapi2 target type of the DIMM /// @note this is a base class /// template< fapi2::TargetType T > class repair_state { public: /// @brief default contructor repair_state() = default; /// @brief default destructor virtual ~repair_state() = default; /// /// @brief Perform a repair for a single bad DQ bit in a nibble /// @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 /// virtual fapi2::ReturnCode 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) = 0; /// /// @brief Perform a repair for multiple bad DQ bits in a nibble /// @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 /// virtual fapi2::ReturnCode 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) = 0; protected: /// /// @brief Set a new state in the repair state machine /// @param[in,out] io_machine the repair state machine /// @param[in] i_state pointer to the new state to set /// inline void set_state(repair_state_machine& io_machine, std::shared_ptr> i_state) { io_machine.update_state(i_state); } }; /// /// @class mss::chip_and_symbol_mark /// @brief repair_state class for when both a chip mark and a symbol mark have been used /// @tparam T, the fapi2 target type of the DIMM /// template< fapi2::TargetType T > class chip_and_symbol_mark : public repair_state { public: /// @brief default contructor chip_and_symbol_mark() = default; /// @brief default destructor ~chip_and_symbol_mark() = default; /// /// @brief Perform a repair for a single bad DQ bit in a nibble /// @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 /// fapi2::ReturnCode 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_TRY( 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; fapi_try_exit: return fapi2::current_err; } /// /// @brief Perform a repair for multiple bad DQ bits in a nibble /// @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 /// fapi2::ReturnCode 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 FAPI_TRY( 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; fapi_try_exit: return fapi2::current_err; } }; /// /// @class mss::symbol_mark_plus_unrepaired_dq /// @brief repair_state class for when only a symbol mark has been used, and one DQ bit remains unrepaired /// @tparam T, the fapi2 target type of the DIMM /// template< fapi2::TargetType T > class symbol_mark_plus_unrepaired_dq : public repair_state { public: /// @brief default contructor symbol_mark_plus_unrepaired_dq() = default; /// @brief default destructor ~symbol_mark_plus_unrepaired_dq() = default; /// /// @brief Perform a repair for a single bad DQ bit in a nibble /// @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 /// fapi2::ReturnCode 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); FAPI_TRY( io_repairs_exceeded.setBit(mss::index(i_target)) ); return fapi2::FAPI2_RC_SUCCESS; fapi_try_exit: return fapi2::current_err; } /// /// @brief Perform a repair for multiple bad DQ bits in a nibble /// @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 /// fapi2::ReturnCode 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) ); FAPI_TRY( io_repairs_applied.setBit(i_rank) ); FAPI_TRY( 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>(); mss::repair_state::set_state(io_machine, new_state); } fapi_try_exit: return fapi2::current_err; } }; /// /// @class mss::symbol_mark_only /// @brief repair_state class for when only a symbol mark has been used /// @tparam T, the fapi2 target type of the DIMM /// template< fapi2::TargetType T > class symbol_mark_only : public repair_state { public: /// @brief default contructor symbol_mark_only() = default; /// @brief default destructor ~symbol_mark_only() = default; /// /// @brief Perform a repair for a single bad DQ bit in a nibble /// @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 /// fapi2::ReturnCode 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< symbol_mark_plus_unrepaired_dq >(); mss::repair_state::set_state(io_machine, new_state); return fapi2::FAPI2_RC_SUCCESS; } /// /// @brief Perform a repair for multiple bad DQ bits in a nibble /// @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 /// fapi2::ReturnCode 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) ); FAPI_TRY( io_repairs_applied.setBit(i_rank) ); { const auto new_state = std::make_shared< chip_and_symbol_mark >(); mss::repair_state::set_state(io_machine, new_state); } fapi_try_exit: return fapi2::current_err; } }; /// /// @class mss::chip_mark_only /// @brief repair_state class for when only a chip mark has been used /// @tparam T, the fapi2 target type of the DIMM /// template< fapi2::TargetType T > class chip_mark_only : public repair_state { public: /// @brief default contructor chip_mark_only() = default; /// @brief default destructor ~chip_mark_only() = default; /// /// @brief Perform a repair for a single bad DQ bit in a nibble /// @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 /// fapi2::ReturnCode 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) ); FAPI_TRY( io_repairs_applied.setBit(i_rank) ); { const auto new_state = std::make_shared>(); mss::repair_state::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 /// @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 /// fapi2::ReturnCode 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 FAPI_TRY( 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; fapi_try_exit: return fapi2::current_err; } }; /// /// @class mss::no_fails /// @brief repair_state class for no fails (no marks applied) /// @tparam T, the fapi2 target type of the DIMM /// template< fapi2::TargetType T > class no_fails : public repair_state { public: /// @brief default contructor no_fails() = default; /// @brief default destructor ~no_fails() = default; /// /// @brief Perform a repair for a single bad DQ bit in a nibble /// @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 /// fapi2::ReturnCode 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) ); FAPI_TRY( io_repairs_applied.setBit(i_rank) ); { const auto new_state = std::make_shared>(); mss::repair_state::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 /// @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 /// fapi2::ReturnCode 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) ); FAPI_TRY( io_repairs_applied.setBit(i_rank) ); { const auto new_state = std::make_shared>(); mss::repair_state::set_state(io_machine, new_state); } fapi_try_exit: return fapi2::current_err; } }; /// /// @class mss::repair_state_machine /// @brief state machine class used in restore_repairs_helper /// @tparam T, the fapi2 target type of the DIMM /// template< fapi2::TargetType T > class repair_state_machine { public: /// @brief constructor repair_state_machine() : iv_repair_state(std::make_shared>()) {} /// @brief default destructor ~repair_state_machine() = default; /// /// @brief Perform a repair for a single bad DQ bit in a nibble /// @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_repai:rs_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 /// fapi2::ReturnCode one_bad_dq(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) { FAPI_TRY( iv_repair_state->one_bad_dq(*this, i_target, i_rank, i_dq, io_repairs_applied, io_repairs_exceeded) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Perform a repair for multiple bad DQ bits in a nibble /// @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 /// fapi2::ReturnCode multiple_bad_dq(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) { FAPI_TRY( iv_repair_state->multiple_bad_dq(*this, i_target, i_rank, i_dq, io_repairs_applied, io_repairs_exceeded) ); fapi_try_exit: return fapi2::current_err; } /// /// @brief Update the state of the state machine /// @param[in] i_state shared pointer to the new state /// void update_state(std::shared_ptr> i_state) { iv_repair_state = i_state; } private: std::shared_ptr> iv_repair_state; }; /// @brief Get the attributes for the reorder queue setting /// @tparam MC the memory controller type /// @tparam T, the fapi2 target type of the target /// @param[in] const ref to the mc target /// @param[out] uint8_t& reference to store the value /// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK /// @note Contains the settings for write/read reorder queue /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T > fapi2::ReturnCode reorder_queue_setting(const fapi2::Target& i_target, uint8_t& o_value); /// /// @brief Resets the write/read reorder queue values - needs to be called after MCBIST execution /// @tparam MC the memory controller type /// @tparam T, the mc /// @tparam TT, the class traits for the port /// @param[in] i_target the target to effect /// @return FAPI2_RC_SUCCSS iff ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, typename TT = portTraits > inline fapi2::ReturnCode reset_reorder_queue_settings(const fapi2::Target& i_target) { uint8_t l_reorder_queue = 0; FAPI_TRY(reorder_queue_setting(i_target, l_reorder_queue)); // Changes the reorder queue settings { // Two settings are FIFO and REORDER. FIFO is a 1 in the registers, while reorder is a 0 state const mss::states l_state = ((l_reorder_queue == fapi2::ENUM_ATTR_MEM_REORDER_QUEUE_SETTING_FIFO) ? mss::states::ON : mss::states::OFF); FAPI_TRY(configure_rrq(i_target, l_state), "%s failed to reset read reorder queue settings", mss::c_str(i_target)); FAPI_TRY(configure_wrq(i_target, l_state), "%s failed to reset read reorder queue settings", mss::c_str(i_target)); } fapi_try_exit: return fapi2::current_err; } /// /// @brief Convert a bitmap from the BAD_DQ_BITMAP attribute to a vector of bad DQ indexes /// @param[in] i_bad_bits an 8-bit bitmap of bad bits /// @param[in] i_nibble which nibble of the bitmap to convert /// @return std::vector of DQ bits marked as bad in the bitmap /// inline std::vector bad_bit_helper(const uint8_t i_bad_bits, const size_t i_nibble) { std::vector l_output; fapi2::buffer l_bit_buffer(i_bad_bits); const size_t l_start = (i_nibble == 0) ? 0 : mss::conversions::BITS_PER_NIBBLE; for (size_t l_offset = 0; l_offset < mss::conversions::BITS_PER_NIBBLE; ++l_offset) { const size_t l_position_tmp = l_start + l_offset; if (l_bit_buffer.getBit(l_position_tmp)) { l_output.push_back(l_position_tmp); } } return l_output; } // TODO: RTC: 157753 tparam R can be pulled from an PORT trait once we have it // /// @brief Restore symbol and chip marks according to BAD_DQ_BITMAP attribute, helper function for unit testing /// @tparam MC the memory controller type /// @tparam T, the fapi2 target type of the DIMM (derived) /// @tparam R the maximum rank per DIMM /// @tparam B the number of bytes per rank in the bad_dq_bitmap attribute /// @param[in] i_target A target representing a DIMM /// @param[in] i_bad_bits the bad bits values from the VPD, for the specified DIMM /// @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< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T, uint64_t R, uint64_t B > inline fapi2::ReturnCode restore_repairs_helper( const fapi2::Target& i_target, const uint8_t i_bad_bits[R][B], fapi2::buffer& io_repairs_applied, fapi2::buffer& io_repairs_exceeded) { FAPI_INF("%s Restore repair marks from bad DQ data", mss::c_str(i_target)); using MCT = mss::mcbistMCTraits; using MT = mss::mcbistTraits; std::vector l_ranks; const auto l_dimm_idx = index(i_target); // gets all of the ranks to loop over FAPI_TRY( mss::rank::ranks_on_dimm_helper(i_target, l_ranks) ); // loop through ranks for (const auto l_rank : l_ranks) { const auto l_rank_idx = index(l_rank); repair_state_machine l_machine; for (uint64_t l_byte = 0; l_byte < (MT::MAX_DQ_NIBBLES / mss::conversions::NIBBLES_PER_BYTE); ++l_byte) { for (size_t l_nibble = 0; l_nibble < mss::conversions::NIBBLES_PER_BYTE; ++l_nibble) { const auto l_bad_dq_vector = bad_bit_helper(i_bad_bits[l_rank_idx][l_byte], l_nibble); FAPI_DBG("Total bad bits on DIMM:%d rank:%d nibble%d: %d", l_dimm_idx, l_rank, (l_byte * NIBBLES_PER_BYTE) + l_nibble, l_bad_dq_vector.size()); // apply repairs and update repair machine state // if there are no bad bits (l_bad_dq_vector.size() == 0) no action is necessary if (l_bad_dq_vector.size() == 1) { // l_bad_dq_vector is per byte, so multiply up to get the bad dq's index const uint64_t l_dq = l_bad_dq_vector[0] + (l_byte * BITS_PER_BYTE); FAPI_TRY( l_machine.one_bad_dq(i_target, l_rank, l_dq, io_repairs_applied, io_repairs_exceeded) ); } else if (l_bad_dq_vector.size() > 1) { // l_bad_dq_vector is per byte, so multiply up to get the bad dq's index const uint64_t l_dq = l_bad_dq_vector[0] + (l_byte * BITS_PER_BYTE); FAPI_TRY( l_machine.multiple_bad_dq(i_target, l_rank, l_dq, io_repairs_applied, io_repairs_exceeded) ); } // if repairs have been exceeded, we're done if (io_repairs_exceeded.getBit(l_dimm_idx)) { FAPI_INF("Repairs exceeded on DIMM %s", c_str(i_target)); return fapi2::FAPI2_RC_SUCCESS; } } // end loop through nibbles } // end loop through bytes } // end loop through ranks fapi_try_exit: return fapi2::current_err; } /// /// @brief Restore symbol and chip marks according to BAD_DQ_BITMAP attribute /// @tparam MC, the memory controller type /// @tparam T, the fapi2 target type of the port (derived) /// @param[in] i_target A target representing a port /// @param[in,out] io_repairs_applied bit mask, where a bit set means a rank had repairs applied (bit0 = rank0, etc) /// @param[in,out] io_repairs_exceeded bit mask, where a bit set means a DIMM had more bad bits than could be repaired (bit0 = DIMM0 etc) /// @return FAPI2_RC_SUCCESS if and only if ok /// template< mss::mc_type MC = DEFAULT_MC_TYPE, fapi2::TargetType T > inline fapi2::ReturnCode restore_repairs( const fapi2::Target& i_target, fapi2::buffer& io_repairs_applied, fapi2::buffer& io_repairs_exceeded) { uint8_t l_bad_bits[BAD_BITS_RANKS][BAD_DQ_BYTE_COUNT] = {}; io_repairs_applied = 0; io_repairs_exceeded = 0; for (const auto& l_dimm : mss::find_targets(i_target)) { FAPI_TRY( mss::get_bad_dq_bitmap(l_dimm, l_bad_bits) ); FAPI_TRY( (restore_repairs_helper( l_dimm, l_bad_bits, io_repairs_applied, io_repairs_exceeded)) ); } fapi_try_exit: return fapi2::current_err; } }// ns mss #endif