///
    /// @brief Utility function to check parameters and find a DIMM target
    /// @param[in] i_mba mba target
    /// @param[in] i_port Port number
    /// @param[in] i_dimm Dimm number
    /// @param[in] i_rank Rank number
    /// @param[out] o_dimm Dimm target
    /// @return FAPI2_RC_SUCCESS iff okay
    ///
    fapi2::ReturnCode dimmBadDqCheckParamFindDimm(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_mba,
            const uint8_t i_port,
            const uint8_t i_dimm,
            const uint8_t i_rank,
            fapi2::Target<fapi2::TARGET_TYPE_DIMM>& o_dimm)
    {
        uint8_t l_port = 0;
        uint8_t l_dimm = 0;
        std::vector<fapi2::Target<fapi2::TARGET_TYPE_DIMM>> l_dimms;
        std::vector<fapi2::Target<fapi2::TARGET_TYPE_DIMM>>::const_iterator dimmIter;

        FAPI_ASSERT((i_port < MAX_PORTS_PER_MBA) &&
                    (i_dimm < MAX_DIMM_PER_PORT) &&
                    (i_rank < MAX_RANKS_PER_DIMM),
                    fapi2::CEN_BAD_DQ_DIMM_BAD_PARAM().
                    set_MBA(i_mba).
                    set_FFDC_PORT(i_port).
                    set_FFDC_DIMM(i_dimm).
                    set_FFDC_RANK(i_rank),
                    "dimmBadDqCheckParamFindDimm: %s Bad parameter. %d:%d:%d",
                    mss::c_str(i_mba), i_port, i_dimm, i_rank);

        // Get the functional DIMMs associated with the MBA chiplet
        l_dimms = i_mba.getChildren<fapi2::TARGET_TYPE_DIMM>();
        // Find the DIMM with the correct MBA port/dimm

        for (dimmIter = l_dimms.begin(); dimmIter != l_dimms.end(); ++dimmIter)
        {
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MBA_PORT, *dimmIter, l_port));

            if (l_port == i_port)
            {
                FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MBA_DIMM, *dimmIter, l_dimm));

                if (l_dimm == i_dimm)
                {
                    o_dimm = *dimmIter;
                    break;
                }
            }
        }

        FAPI_ASSERT(dimmIter != l_dimms.end(),
                    fapi2::CEN_BAD_DQ_DIMM_NOT_FOUND().
                    set_MBA(i_mba).
                    set_FFDC_PORT(i_port).
                    set_FFDC_DIMM(i_dimm),
                    "dimmBadDqCheckParamFindDimm: "
                    "Did not find DIMM for %s:%d:%d",
                    mss::c_str(i_mba), i_port, i_dimm);

    fapi_try_exit:
        return fapi2::current_err;
    }
Пример #2
0
fapi2::ReturnCode ppe_pollHaltState(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
    const uint64_t i_base_address)
{
    fapi2::buffer<uint64_t> l_data64;

    // Halt state entry should be very fast on PPEs (eg nanoseconds)
    // Try only using the SCOM access time to delay.
    static const uint32_t HALT_TRIES = 10;

    uint32_t l_timeout_count = HALT_TRIES;

    do
    {
        FAPI_TRY(getScom(i_target, i_base_address + PPE_XIRAMDBG, l_data64), "Error in GETSCOM");
    }
    while (! l_data64.getBit<0>() &&
           --l_timeout_count != 0);


    FAPI_ASSERT(l_data64.getBit<0>(), fapi2::P9_PPE_STATE_HALT_TIMEOUT_ERR(),
                "PPE Halt Timeout");


fapi_try_exit:
    return fapi2::current_err;
}
Пример #3
0
///
/// @brief Checks to make sure ATTR_MSS_MRW_TEMP_REFRESH_MODE and ATTR_MSS_MRW_FINE_REFRESH_MODE are set correctly
/// @return fapi2::FAPI2_RC_SUCCESS if okay
/// @note from DDR4 DRAM Spec (79-4B) 4.9.4 page 48
///
fapi2::ReturnCode temp_refresh_mode()
{
    uint8_t l_temp_refresh = 0;
    uint8_t l_refresh_mode = 0;

    FAPI_TRY( mrw_fine_refresh_mode (l_refresh_mode));
    FAPI_TRY( mrw_temp_refresh_mode (l_temp_refresh));

    // If the temperature refresh mode is enabled, only the normal mode (Fixed 1x mode; MRS4 A8:A7:A6= 000) is allowed for the fine refresh mode
    // Per JEDEC DDR4 DRAM spec from 07-2016 page 48 section 4.9.4
    if ( l_temp_refresh == fapi2::ENUM_ATTR_MSS_MRW_TEMP_REFRESH_MODE_ENABLE)
    {
        FAPI_ASSERT( (l_refresh_mode == fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_NORMAL),
                     fapi2::MSS_INVALID_FINE_REFRESH_MODE_WITH_TEMP_REFRESH_MODE_ENABLED()
                     .set_FINE_REF_MODE(l_refresh_mode)
                     .set_TEMP_REF_MODE(l_temp_refresh),
                     "Incorrect setting for ATTR_MSS_MRW_FINE_REFRESH_MODE (%d) if ATTR_MSS_MRW_TEMP_REFRESH_MODE is enabled",
                     l_refresh_mode);
    }

    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    return fapi2::current_err;
};
Пример #4
0
// -----------------------------------------------------------------------------
// Function definition
// -----------------------------------------------------------------------------
fapi2::ReturnCode p9_pm_pba_init(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
    const p9pm::PM_FLOW_MODE i_mode)
{
    FAPI_IMP("> p9_pm_pba_init");

    if (i_mode == p9pm::PM_INIT)
    {
        FAPI_TRY(pba_init(i_target), " pba_init() failed.");
    }
    else if (i_mode == p9pm::PM_RESET)
    {
        FAPI_TRY(pba_reset(i_target), " pba_reset() failed.");
    }
    else
    {
        FAPI_ASSERT(false,
                    fapi2::P9_PMPROC_PBA_INIT_INCORRECT_MODE()
                    .set_PM_MODE(i_mode),
                    "Unknown mode 0x%08llx passed to p9_pm_pba_init.",
                    i_mode);
    }

fapi_try_exit:
    FAPI_IMP("< p9_pm_pba_init");
    return fapi2::current_err;
}
Пример #5
0
fapi2::ReturnCode p9_pm_cme_firinit(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
    const p9pm::PM_FLOW_MODE i_mode)
{
    FAPI_IMP("p9_pm_cme_firinit start");

    if(i_mode == p9pm::PM_RESET)
    {
        FAPI_TRY(pm_cme_fir_reset(i_target),
                 "ERROR: Failed to reset the CME FIRs");
    }
    else if(i_mode == p9pm::PM_INIT)
    {
        FAPI_TRY(pm_cme_fir_init(i_target),
                 "ERROR: Failed to initialize the CME FIRs");
    }
    else
    {
        FAPI_ASSERT(false, fapi2::PM_CME_FIRINIT_BAD_MODE().set_BADMODE(i_mode),
                    "ERROR; Unknown mode passed to p9_pm_cme_firinit. Mode %x",
                    i_mode);
    }

fapi_try_exit:
    FAPI_INF("p9_pm_cme_firinit end");
    return fapi2::current_err;
}
Пример #6
0
///
/// @brief Checks that the starting port/dimm address is in range for broadcast mode - helper for testing
/// @param[in] i_targets a vector of MCA targets
/// @param[in] i_start_addr the starting port_dimm select address
/// @return FAPI2_RC_SUCCESS iff okay
///
fapi2::ReturnCode broadcast_mode_start_address_check_helper(
    const std::vector< fapi2::Target<fapi2::TARGET_TYPE_MCA> >& i_targets,
    const uint64_t i_start_addr)
{
    if( i_targets.size() == 0 )
    {
        // Programming bug, multi_port_init check assures we shouldn't get here
        FAPI_INF("No ports passed in");
        fapi2::Assert(false);
    }

    // The check makes for bugs of not hitting the first port or hitting the middle dimm's multiple times
    // since multi_port_init loops through all valid DIMM's and plops the addresses in
    const auto l_first_configured_mca = i_targets[0];
    const auto l_dimms = mss::find_targets<fapi2::TARGET_TYPE_DIMM>(l_first_configured_mca);
    const auto l_mcbist = mss::find_target<fapi2::TARGET_TYPE_MCBIST>(l_first_configured_mca);
    const size_t l_dimms_under_mca = mss::count_dimm(l_first_configured_mca);

    if( l_dimms.size() == 0)
    {
        FAPI_INF("No DIMMs under %s", mss::c_str(l_first_configured_mca));
        return fapi2::FAPI2_RC_SUCCESS;
    }

    FAPI_INF("%d DIMMs under %s", l_dimms_under_mca, mss::c_str(l_first_configured_mca));

    // Bomb out if we have incorrect addresses
    // The following assert catches the error incorrect address error earlier
    // It also keeps the error meaningful with an invalid address callout rather than a generic MCBIST error callout

    // Note: we are guaranteed to have at least one DIMM, as we are not broadcast capable without DIMM's
    // The ports are also required to have the same number and type of DIMM's to be broadcast capable
    // As such, we can be guaranteed that we have at least one DIMM below
    const uint64_t l_port_dimm_offset = l_dimms_under_mca - 1;
    const uint64_t l_portdimm_this_dimm_min = mss::relative_pos<fapi2::TARGET_TYPE_MCBIST>(l_dimms[0]);
    const uint64_t l_portdimm_this_dimm_max = l_portdimm_this_dimm_min + l_port_dimm_offset;

    FAPI_INF("Start port_dimm address %d, %s first configured mca start address %d",
             i_start_addr,
             mss::c_str(l_first_configured_mca),
             l_portdimm_this_dimm_min);


    // Checking that we are received a valid address (port_dimm) that is no less than the first configured port_dimm
    // on this MCBIST. This vector is sorted to make sure this is true.
    // Note: cronus always passes in a 0 address, so we need to support an address that is on or before this port
    FAPI_ASSERT( i_start_addr <= l_portdimm_this_dimm_max,
                 fapi2::MSS_MEMDIAGS_BCMODE_INVALID_ADDRESS()
                 .set_MCA_TARGET(l_first_configured_mca)
                 .set_START_ADDRESS(i_start_addr)
                 .set_MCA_START_ADDRESS(l_portdimm_this_dimm_min),
                 "%s address (%lu) is not the MCBIST's first configured port address (%lu)",
                 mss::c_str(l_mcbist), i_start_addr, l_portdimm_this_dimm_min);

    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    return fapi2::current_err;
}
Пример #7
0
///
/// @brief Check the omi status in Axone side
/// @param[in] i_target the OMIC target to operate on
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode p9a_omi_train_check( const fapi2::Target<fapi2::TARGET_TYPE_OMI>& i_target)
{
    mss::display_git_commit_info("p9a_omi_train_check");

    FAPI_INF("%s Start p9a_omi_train_check", mss::c_str(i_target));

    // Const
    constexpr uint8_t STATE_MACHINE_SUCCESS = 0b111;  // This value is from Lonny Lambrecht
    constexpr uint8_t MAX_LOOP_COUNT = 20;  // Retry times

    // Declares variables
    fapi2::buffer<uint64_t> l_omi_status;
    fapi2::buffer<uint64_t> l_omi_training_status;
    uint8_t l_state_machine_state = 0;
    uint8_t l_tries = 0;

    FAPI_TRY(mss::mc::omi_train_status(i_target, l_state_machine_state, l_omi_status));

    while (l_tries < MAX_LOOP_COUNT && l_state_machine_state != STATE_MACHINE_SUCCESS)
    {
        // Delay
        fapi2::delay(mss::DELAY_100US, 10 * mss::DELAY_1MS);

        // Check OMI training status
        FAPI_TRY(mss::mc::omi_train_status(i_target, l_state_machine_state, l_omi_status));
        // Note: this is very useful debug information while trying to debug training during polling
        FAPI_TRY(mss::getScom(i_target, P9A_MC_REG2_DL0_TRAINING_STATUS, l_omi_training_status));
        l_tries++;
    }

    FAPI_TRY(mss::getScom(i_target, P9A_MC_REG2_DL0_TRAINING_STATUS, l_omi_training_status));
    FAPI_ASSERT(l_state_machine_state == STATE_MACHINE_SUCCESS,
                fapi2::P9A_OMI_TRAIN_ERR()
                .set_TARGET(i_target)
                .set_EXPECTED_SM_STATE(STATE_MACHINE_SUCCESS)
                .set_ACTUAL_SM_STATE(l_state_machine_state)
                .set_DL0_STATUS(l_omi_status)
                .set_DL0_TRAINING_STATUS(l_omi_training_status),
                "%s OMI Training Failure, expected state:%d/actual state:%d",
                mss::c_str(i_target),
                STATE_MACHINE_SUCCESS,
                l_state_machine_state
               );

    FAPI_INF("%s End p9a_omi_train_check, expected state:%d/actual state:%d, DL0_STATUS:0x%016llx, DL0_TRAINING_STATUS:0x%016llx",
             mss::c_str(i_target),
             STATE_MACHINE_SUCCESS,
             l_state_machine_state,
             l_omi_status,
             l_omi_training_status);
    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    return fapi2::current_err;

}// p9a_omi_train_check
Пример #8
0
fapi2::ReturnCode decoder<mss::mc_type::NIMBUS>::find_slope (
    const std::vector< const std::vector<uint64_t>* >& i_slope)
{
    using TT = throttle_traits<mss::mc_type::NIMBUS>;

    // For nimbus only one attribute is used to get slope (i_slope[0])
    // Find iterator to matching key (if it exists)
    const auto l_value_iterator  =  std::find_if((*i_slope[0]).begin(),
                                    (*i_slope[0]).end(),
                                    is_match<>(iv_gen_key));

    //Should have matched with the default ATTR value at least
    //The last value should always be the default value
    FAPI_ASSERT(l_value_iterator != (*i_slope[0]).end(),
                fapi2::MSS_NO_POWER_THERMAL_ATTR_FOUND()
                .set_GENERATED_KEY(iv_gen_key)
                .set_FUNCTION(SLOPE)
                .set_DIMM_TARGET(iv_kind.iv_target)
                .set_SIZE(iv_kind.iv_size)
                .set_DRAM_GEN(iv_kind.iv_dram_generation)
                .set_DIMM_TYPE(iv_kind.iv_dimm_type)
                .set_DRAM_WIDTH( iv_kind.iv_dram_width)
                .set_DRAM_DENSITY(iv_kind.iv_dram_density)
                .set_STACK_TYPE(iv_kind.iv_stack_type)
                .set_MFGID(iv_kind.iv_mfgid),
                "Couldn't find %s value for generated key:%08lx, for target %s. "
                "DIMM values for generated key are "
                "size is %d, gen is %d, type is %d, width is %d, density %d, stack %d, mfgid %d, dimms %d",
                "ATTR_MSS_MRW_POWER_CURVE_SLOPE",
                iv_gen_key,
                mss::c_str(iv_kind.iv_target),
                iv_kind.iv_size,
                iv_kind.iv_dram_generation,
                iv_kind.iv_dimm_type,
                iv_kind.iv_dram_width,
                iv_kind.iv_dram_density,
                iv_kind.iv_stack_type,
                iv_kind.iv_mfgid,
                iv_dimms_per_port);

    {
        const fapi2::buffer<uint64_t> l_temp(*l_value_iterator);
        l_temp.extractToRight<TT::VDDR_START, TT::VDDR_LENGTH>( iv_vddr_slope);
        l_temp.extractToRight<TT::TOTAL_START, TT::TOTAL_LENGTH>(iv_total_slope);
    }
fapi_try_exit:
    return fapi2::current_err;
}
Пример #9
0
fapi2::ReturnCode p9_pm_occ_firinit(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
    const p9pm::PM_FLOW_MODE i_mode)
{
    FAPI_IMP("p9_pm_occ_firinit Enter");

    fapi2::buffer<uint64_t> l_data64;
    fapi2::buffer<uint64_t> l_mask64;

    uint64_t l_fir;
    uint64_t l_mask;
    uint64_t l_unmaskedErrors;

    FAPI_DBG("Checking OCC FIRs");
    FAPI_TRY(fapi2::getScom(i_target, PERV_TP_OCC_SCOM_OCCLFIR, l_data64),
             "ERROR: Failed to fetch OCC FIR");
    FAPI_TRY(fapi2::getScom(i_target, PERV_TP_OCC_SCOM_OCCLFIRMASK, l_mask64),
             "ERROR: Failed to fetch OCC FIRMASK");
    l_data64.extractToRight<0, 64>(l_fir);
    l_mask64.extractToRight<0, 64>(l_mask);
    l_unmaskedErrors = l_fir & l_mask;

    if(l_unmaskedErrors)
    {
        FAPI_INF("WARNING: OCC has active errors");
    }

    if(i_mode == p9pm::PM_RESET)
    {
        FAPI_TRY(pm_occ_fir_reset(i_target),
                 "ERROR: Failed to reset the OCC FIRs");
    }
    else if(i_mode == p9pm::PM_INIT)
    {
        FAPI_TRY(pm_occ_fir_init(i_target),
                 "ERROR: Failed to initialize the OCC FIRs");
    }
    else
    {
        FAPI_ASSERT(false, fapi2::PM_OCC_FIRINIT_BAD_MODE().set_BADMODE(i_mode),
                    "ERROR; Unknown mode passed to p9_pm_occ_firinit. Mode %x",
                    i_mode);
    }

fapi_try_exit:
    FAPI_IMP("p9_pm_occ_firinit Exit");
    return fapi2::current_err;
}
Пример #10
0
fapi2::ReturnCode empty_slot_zero(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
{
    fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
    const auto l_dimms = mss::find_targets<TARGET_TYPE_DIMM>(i_target);

    // If there's one dimm, make sure it's in slot 0
    if ( l_dimms.size() == 1 )
    {
        FAPI_ASSERT(  mss::index(l_dimms[0]) == 0,
                      fapi2::MSS_PLUG_RULES_SINGLE_DIMM_IN_WRONG_SLOT()
                      .set_MCA_TARGET(i_target)
                      .set_DIMM_TARGET(l_dimms[0]),
                      "%s DIMM is plugged into the wrong slot. Must plug into slot 0", mss::c_str(l_dimms[0]) );
    }

fapi_try_exit:
    return fapi2::current_err;
}
Пример #11
0
///
/// @brief Retrieves SDRAM Maximum Cycle Time (tCKmax) from SPD
/// @param[in] i_spd_decoder SPD decoder
/// @param[out] o_value tCKmax value in ps
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode get_tckmax( const mss::spd::facade& i_spd_decoder,
                              uint64_t& o_value )
{
    int64_t l_timing_ftb = 0;
    int64_t l_timing_mtb = 0;
    int64_t l_medium_timebase = 0;
    int64_t l_fine_timebase = 0;
    int64_t l_temp = 0;

    // Retrieve timing parameters
    const auto l_target = i_spd_decoder.get_dimm_target();

    FAPI_TRY( get_timebases(i_spd_decoder, l_medium_timebase, l_fine_timebase),
              "%s. Failed get_timebases", spd::c_str(l_target) );
    FAPI_TRY( i_spd_decoder.max_tck(l_timing_mtb),
              "%s. Failed max_tck()", spd::c_str(l_target) );
    FAPI_TRY( i_spd_decoder.fine_offset_max_tck(l_timing_ftb),
              "%s. Failed fine_offset_max_tck()", spd::c_str(l_target) );

    // Calculate timing value
    l_temp = spd::calc_timing_from_timebase(l_timing_mtb,
                                            l_medium_timebase,
                                            l_timing_ftb,
                                            l_fine_timebase);

    // Sanity check
    FAPI_ASSERT(l_temp > 0,
                fapi2::MSS_INVALID_TIMING_VALUE().
                set_VALUE(l_temp).
                set_FUNCTION(GET_TCKMAX).
                set_DIMM_TARGET(l_target),
                "%s. tCKmax invalid (<= 0) : %d",
                spd::c_str(l_target),
                l_temp);

    o_value = l_temp;

    FAPI_INF( "%s. tCKmax (ps): %d",
              spd::c_str(l_target),
              o_value);

fapi_try_exit:
    return fapi2::current_err;
}
Пример #12
0
///
/// @brief Enforce no mixing DIMM types
/// @param[in] i_target port target
/// @param[in] i_kinds a vector of DIMMs plugged into target
/// @return fapi2::FAPI2_RC_SUCCESS if okay
/// @note This function will commit error logs representing the mixing failure
///
fapi2::ReturnCode dimm_type_mixing(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
                                   const std::vector<dimm::kind>& i_kinds)
{
    fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;

    //If we have 1 or 0 DIMMs on the port, we don't care
    if (i_kinds.size() == MAX_DIMM_PER_PORT)
    {
        FAPI_ASSERT( i_kinds[0].iv_dimm_type == i_kinds[1].iv_dimm_type,
                     fapi2::MSS_PLUG_RULES_INVALID_DIMM_TYPE_MIX()
                     .set_DIMM_SLOT_ZERO(i_kinds[0].iv_dimm_type)
                     .set_DIMM_SLOT_ONE(i_kinds[1].iv_dimm_type)
                     .set_MCA_TARGET(i_target),
                     "%s has two different types of DIMM installed of type %d and of type %d. Cannot mix DIMM types on port",
                     mss::c_str(i_target), i_kinds[0].iv_dimm_type, i_kinds[1].iv_dimm_type );
    }

fapi_try_exit:
    return fapi2::current_err;
}
Пример #13
0
///
/// @brief Function to check the DRAM generation for DDR4
/// @param[in] i_kinds a vector of DIMM kind structs
/// @return fapi2::ReturnCode
///
fapi2::ReturnCode check_gen( const std::vector<dimm::kind>& i_kinds )
{
    fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;

    for (const auto& k : i_kinds)
    {
        // This should never fail ... but Just In Case a little belt-and-suspenders never hurt.
        // TODO RTC:160395 This needs to change for controllers which support different generations
        // Nimbus only supports DDR4 for now
        FAPI_ASSERT( k.iv_dram_generation == fapi2::ENUM_ATTR_EFF_DRAM_GEN_DDR4 ||
                     k.iv_dram_generation == fapi2::ENUM_ATTR_EFF_DRAM_GEN_EMPTY,
                     fapi2::MSS_PLUG_RULES_INVALID_DRAM_GEN()
                     .set_DRAM_GEN(k.iv_dimm_type)
                     .set_DIMM_TARGET(k.iv_target),
                     "%s is not DDR4 it is %d", mss::c_str(k.iv_target), k.iv_dram_generation );
    }

fapi_try_exit:
    return fapi2::current_err;
}
Пример #14
0
fapi2::ReturnCode check_dead_load( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
{
    const auto l_plugged_dimms = i_target.getChildren<TARGET_TYPE_DIMM>(fapi2::TARGET_STATE_PRESENT);
    const auto l_functional_dimms = mss::find_targets<TARGET_TYPE_DIMM>(i_target);
    fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;

    // If we have one deconfigured dimm and one functional dimm, we need to deconfigure the functional dimm
    FAPI_DBG(" Plugged dimm size is %d functional dimms size is %d",
             l_plugged_dimms.size(),
             l_functional_dimms.size());


    // So we check to see if there are functional dimms on the port,
    // if so, we check to see if there are less functional dimms than plugged in dimms (meaning one was deconfigured)
    // Third let's just double check we have two plugged dimms
    // The last check is for clarity
    if ( (l_functional_dimms.size() != 0)
         && (l_plugged_dimms.size() != l_functional_dimms.size())
         && (l_plugged_dimms.size() == 2) )
    {
        auto l_dead_dimm = l_plugged_dimms[0];
        auto l_live_dimm = l_plugged_dimms[1];

        // Now we determine if present_dimm[0] is functional by searching functional dimms
        const auto l_found = std::find(l_functional_dimms.begin(), l_functional_dimms.end(), l_dead_dimm);

        // if we don't find the dimm in the list of functional dimms, then it's deconfigured and the guess was good
        // Otherwise, we swap because our first guess was wrong
        l_dead_dimm = ( l_found == l_functional_dimms.end() ) ? l_dead_dimm : l_plugged_dimms[1];
        l_live_dimm = ( l_found == l_functional_dimms.end() ) ? l_live_dimm : l_plugged_dimms[0];
        FAPI_ASSERT( false,
                     fapi2::MSS_DEAD_LOAD_ON_PORT()
                     .set_FUNCTIONAL_DIMM(l_live_dimm),
                     "%s has two DIMMs installed, but one is deconfigured (%d), so deconfiguring the other (%d) because of dead load",
                     mss::c_str(i_target), mss::index(l_dead_dimm), mss::index(l_live_dimm));
    }

fapi_try_exit:
    return fapi2::current_err;
}
Пример #15
0
///
/// @brief Check validity of SMP topology
///
/// @param[in] i_op    Enumerated type representing SMP build phase (HB or FSP)
/// @param[in] i_smp   Fully specified structure encapsulating SMP
///
/// @return FAPI2_RC_SUCCESS if success, else error code.
///
fapi2::ReturnCode
p9_build_smp_check_topology(const p9_build_smp_operation i_op,
                            p9_build_smp_system& i_smp)
{
    // check that fabric topology is logically valid
    // 1) in a given group, all chips are connected to every other
    //    chip in the group, by an X bus (if pump mode = chip_is_node)
    // 2) each chip is connected to its partner chip (with same chip id)
    //    in every other group, by an A bus or X bus (if pump mode = chip_is_group)

    fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> FAPI_SYSTEM;
    fapi2::ATTR_PROC_FABRIC_PUMP_MODE_Type l_pump_mode;
    fapi2::buffer<uint8_t> l_group_ids_in_system;
    fapi2::buffer<uint8_t> l_chip_ids_in_groups;

    // determine pump mode
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PROC_FABRIC_PUMP_MODE, FAPI_SYSTEM, l_pump_mode),
             "Error from FAPI_ATTR_GET (ATTR_PROC_FABRIC_PUMP_MODE");

    // build set of all valid group IDs in system
    for (auto g_iter = i_smp.groups.begin();
         g_iter != i_smp.groups.end();
         g_iter++)
    {
        FAPI_INF("Adding g%d", g_iter->first);
        FAPI_TRY(l_group_ids_in_system.setBit(g_iter->first),
                 "Error from setBit (l_group_ids_in_system)");

        // build set of all valid chip IDs in group
        for (auto p_iter = g_iter->second.chips.begin();
             p_iter != g_iter->second.chips.end();
             p_iter++)
        {
            FAPI_INF("Adding g%d:p%d", g_iter->first, p_iter->first);
            FAPI_TRY(l_chip_ids_in_groups.setBit(p_iter->first),
                     "Error from setBit (l_chip_ids_in_groups)");
        }
    }

    // iterate over all groups
    for (auto g_iter = i_smp.groups.begin();
         g_iter != i_smp.groups.end();
         g_iter++)
    {
        // iterate over all chips in current group
        for (auto p_iter = g_iter->second.chips.begin();
             p_iter != g_iter->second.chips.end();
             p_iter++)
        {
            FAPI_DBG("Checking connectivity for g%d:p%d", g_iter->first, p_iter->first);
            bool intergroup_set_match = false;
            fapi2::buffer<uint8_t> l_connected_group_ids;
            bool intragroup_set_match = false;
            fapi2::buffer<uint8_t> l_connected_chip_ids;

            uint8_t l_x_en[P9_FBC_UTILS_MAX_X_LINKS] = { 0 };
            uint8_t l_a_en[P9_FBC_UTILS_MAX_A_LINKS] = { 0 };
            uint8_t l_x_rem_chip_id[P9_FBC_UTILS_MAX_X_LINKS] = { 0 };
            uint8_t l_a_rem_group_id[P9_FBC_UTILS_MAX_A_LINKS] = { 0 };

            // add IDs associated with current chip, to make direct set comparison easy
            FAPI_TRY(l_connected_group_ids.setBit(p_iter->second.group_id),
                     "Error from setBit (l_connected_group_ids)");

            FAPI_TRY(l_connected_chip_ids.setBit(p_iter->second.chip_id),
                     "Error from setBit (l_connected_chip_ids)");

            // process X links, mark reachable group/chip IDs
            FAPI_INF("Processing X links for g%d:p%d", g_iter->first, p_iter->first);
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PROC_FABRIC_X_ATTACHED_CHIP_CNFG, *(p_iter->second.target), l_x_en),
                     "Error from FAPI_ATTR_GET (ATTR_PROC_FABRIC_X_ATTACHED_CHIP_CNFG)");

            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PROC_FABRIC_X_ATTACHED_CHIP_ID, *(p_iter->second.target), l_x_rem_chip_id),
                     "Error from FAPI_ATTR_GET (ATTR_PROC_FABRIC_X_ATTACHED_CHIP_ID)");

            for (uint8_t l_link_id = 0; l_link_id < P9_FBC_UTILS_MAX_X_LINKS; l_link_id++)
            {
                if (l_x_en[l_link_id])
                {
                    FAPI_TRY(p9_build_smp_validate_link(*(p_iter->second.target),
                                                        P9_FBC_XBUS_LINK_CTL_ARR[l_link_id],
                                                        l_x_en[l_link_id]),
                             "Error from p9_build_smp_validate_link (g%d:p%d X%d)",
                             g_iter->first, p_iter->first, l_link_id);

                    if (l_pump_mode == fapi2::ENUM_ATTR_PROC_FABRIC_PUMP_MODE_CHIP_IS_NODE)
                    {
                        FAPI_TRY(l_connected_chip_ids.setBit(l_x_rem_chip_id[l_link_id]),
                                 "Error from setBit (l_connected_chip_ids, X)");
                    }
                    else
                    {
                        FAPI_TRY(l_connected_group_ids.setBit(l_x_rem_chip_id[l_link_id]),
                                 "Error from setBit (l_connected_group_ids, X)");
                    }
                }
            }

            // process A links, mark reachable group/chip IDs
            FAPI_INF("Processing A links for g%d:p%d", g_iter->first, p_iter->first);
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PROC_FABRIC_A_ATTACHED_CHIP_CNFG, *(p_iter->second.target), l_a_en),
                     "Error from FAPI_ATTR_GET (ATTR_PROC_FABRIC_A_ATTACHED_CHIP_CNFG)");

            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PROC_FABRIC_A_ATTACHED_CHIP_ID, *(p_iter->second.target), l_a_rem_group_id),
                     "Error from FAPI_ATTR_GET (ATTR_PROC_FABRIC_A_ATTACHED_CHIP_ID)");

            for (uint8_t l_link_id = 0; l_link_id < P9_FBC_UTILS_MAX_A_LINKS; l_link_id++)
            {
                if (l_a_en[l_link_id])
                {
                    FAPI_TRY(p9_build_smp_validate_link(*(p_iter->second.target),
                                                        P9_FBC_ABUS_LINK_CTL_ARR[l_link_id],
                                                        l_a_en[l_link_id]),
                             "Error from p9_build_smp_validate_link (g%d:p%d A%d)",
                             g_iter->first, p_iter->first, l_link_id);

                    FAPI_TRY(l_connected_group_ids.setBit(l_a_rem_group_id[l_link_id]),
                             "Error from setBit (l_connected_group_ids, A)");
                }

            }

            // compare ID sets, emit error if they don't match
            intergroup_set_match = (l_group_ids_in_system == l_connected_group_ids);
            intragroup_set_match = (l_chip_ids_in_groups == l_connected_chip_ids);

            if (!intergroup_set_match || !intragroup_set_match)
            {
                // display target information
                char l_target_str[fapi2::MAX_ECMD_STRING_LEN];
                fapi2::toString(*(p_iter->second.target), l_target_str, sizeof(l_target_str));

                if (!intragroup_set_match)
                {
                    FAPI_ERR("Target %s is not fully connected (X) to all other chips in its group",
                             l_target_str);
                }

                if (!intergroup_set_match)
                {
                    FAPI_ERR("Target %s is not fully connected (X/A) to all other groups in the system",
                             l_target_str);
                }

                FAPI_ASSERT(false,
                            fapi2::P9_BUILD_SMP_INVALID_TOPOLOGY()
                            .set_TARGET(*(p_iter->second.target))
                            .set_OP(i_op)
                            .set_GROUP_ID(p_iter->second.group_id)
                            .set_CHIP_ID(p_iter->second.chip_id)
                            .set_INTERGROUP_CONNECTIONS_OK(intergroup_set_match)
                            .set_CONNECTED_GROUP_IDS(l_connected_group_ids)
                            .set_GROUP_IDS_IN_SYSTEM(l_group_ids_in_system)
                            .set_INTRAGROUP_CONNECTIONS_OK(intragroup_set_match)
                            .set_CONNECTED_CHIP_IDS(l_connected_chip_ids)
                            .set_CHIP_IDS_IN_GROUPS(l_chip_ids_in_groups)
                            .set_FBC_PUMP_MODE(l_pump_mode),
                            "Invalid fabric topology detected");
            }
        }
    }

fapi_try_exit:
    FAPI_DBG("End");
    return fapi2::current_err;
}
Пример #16
0
///
/// @brief Check validity of link DL/TL logic
///
/// @param[in] i_target   Processor chip target
/// @param[in] i_link_ctl p9_fbc_link_ctl_t struct, defines link to check
/// @param[in] i_link_en  ATTACHED_CHIP_CNFG attribute value, defines
///                       active half-links
///
/// @return FAPI2_RC_SUCCESS if success, else error code.
///
fapi2::ReturnCode
p9_build_smp_validate_link(const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
                           const p9_fbc_link_ctl_t& i_link_ctl,
                           const uint8_t i_link_en)
{
    FAPI_DBG("Start");

    fapi2::buffer<uint64_t> l_dl_fir_reg;
    fapi2::buffer<uint64_t> l_tl_fir_reg;
    fapi2::buffer<uint64_t> l_cplt_conf1_reg;
    bool l_dl_trained = false;
    bool l_tl_trained = false;
    bool l_iovalid_set = false;

    // read DL training state
    FAPI_TRY(fapi2::getScom(i_target, i_link_ctl.dl_fir_addr, l_dl_fir_reg),
             "Error from getScom (0x%.16llX)", i_link_ctl.dl_fir_addr);
    // read TL training state
    FAPI_TRY(fapi2::getScom(i_target, i_link_ctl.tl_fir_addr, l_tl_fir_reg),
             "Error from getScom (0x%.16llX)", i_link_ctl.tl_fir_addr);
    // read iovalid state
    FAPI_TRY(fapi2::getScom(i_target, i_link_ctl.iovalid_or_addr & 0xFFFFFF0F, l_cplt_conf1_reg),
             "Error from getScom (0x%.16llX)", i_link_ctl.iovalid_or_addr & 0xFFFFFF0F);

    if (i_link_en == fapi2::ENUM_ATTR_PROC_FABRIC_X_ATTACHED_CHIP_CNFG_TRUE)
    {
        l_dl_trained  = l_dl_fir_reg.getBit<DL_FIR_LINK0_TRAINED_BIT>() &&
                        l_dl_fir_reg.getBit<DL_FIR_LINK1_TRAINED_BIT>();
        l_tl_trained  = l_tl_fir_reg.getBit(i_link_ctl.tl_fir_trained_field_start_bit) &&
                        l_tl_fir_reg.getBit(i_link_ctl.tl_fir_trained_field_start_bit + 1);
        l_iovalid_set = l_cplt_conf1_reg.getBit(i_link_ctl.iovalid_field_start_bit) &&
                        l_cplt_conf1_reg.getBit(i_link_ctl.iovalid_field_start_bit + 1);
    }
    else if (i_link_en == fapi2::ENUM_ATTR_PROC_FABRIC_X_ATTACHED_CHIP_CNFG_EVEN_ONLY)
    {
        l_dl_trained  = l_dl_fir_reg.getBit<DL_FIR_LINK0_TRAINED_BIT>();
        l_tl_trained  = l_tl_fir_reg.getBit(i_link_ctl.tl_fir_trained_field_start_bit);
        l_iovalid_set = l_cplt_conf1_reg.getBit(i_link_ctl.iovalid_field_start_bit);
    }
    else if (i_link_en == fapi2::ENUM_ATTR_PROC_FABRIC_X_ATTACHED_CHIP_CNFG_ODD_ONLY)
    {
        l_dl_trained  = l_dl_fir_reg.getBit<DL_FIR_LINK1_TRAINED_BIT>();
        l_tl_trained  = l_tl_fir_reg.getBit(i_link_ctl.tl_fir_trained_field_start_bit + 1);
        l_iovalid_set = l_cplt_conf1_reg.getBit(i_link_ctl.iovalid_field_start_bit + 1);
    }

    // assert if expected state is not present
    FAPI_ASSERT(l_dl_trained &&
                l_tl_trained &&
                l_iovalid_set,
                fapi2::P9_BUILD_SMP_INVALID_LINK_STATE()
                .set_TARGET(i_target)
                .set_ENDP_TYPE(i_link_ctl.endp_type)
                .set_ENDP_UNIT_ID(i_link_ctl.endp_unit_id)
                .set_LINK_EN(i_link_en)
                .set_DL_FIR_REG(l_dl_fir_reg)
                .set_TL_FIR_REG(l_tl_fir_reg)
                .set_CPLT_CONF1_REG(l_cplt_conf1_reg),
                "Link DL/TL/iovalid are not in expected state");

fapi_try_exit:
    FAPI_DBG("End");
    return fapi2::current_err;
}
Пример #17
0
///
/// @brief Insert HWP inputs and build SMP data structure
///
/// @param[in] i_chips                 Vector of processor chip targets to be included in SMP
/// @param[in] i_master_chip_sys_next  Target designating chip which should be designated fabric
///                                    system master post-reconfiguration
///                                    NOTE: this chip must currently be designated a
///                                          master in its enclosing fabric
///                                          PHASE1/HB: any chip
///                                          PHASE2/FSP: any current drawer master
/// @param[in] i_op                    Enumerated type representing SMP build phase (HB or FSP)
/// @param[in] io_smp                  Fully specified structure encapsulating SMP
///
/// @return FAPI2_RC_SUCCESS if success, else error code.
///
fapi2::ReturnCode p9_build_smp_insert_chips(
    std::vector<fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>>& i_chips,
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_master_chip_sys_next,
    const p9_build_smp_operation i_op,
    p9_build_smp_system& io_smp)
{
    FAPI_DBG("Start");

    // loop over input processor chips
    bool l_master_chip_sys_next_found = false;
    uint8_t l_master_chip_next_group_id = 0;

    for (auto l_iter = i_chips.begin(); l_iter != i_chips.end(); l_iter++)
    {
        bool l_master_chip_sys_next = ((*l_iter) == i_master_chip_sys_next);
        uint8_t l_group_id;

        if (l_master_chip_sys_next)
        {
            // ensure that we haven't already designated one
            FAPI_ASSERT(!l_master_chip_sys_next_found,
                        fapi2::P9_BUILD_SMP_MULTIPLE_MASTER_DESIGNATION_ERR()
                        .set_MASTER_CHIP_SYS_NEXT_TARGET(i_master_chip_sys_next)
                        .set_OP(i_op),
                        "Muliple chips found in input vector which match target designated as master");
            l_master_chip_sys_next_found = true;
        }

        FAPI_TRY(p9_build_smp_insert_chip(*l_iter,
                                          l_master_chip_sys_next,
                                          i_op,
                                          io_smp,
                                          l_group_id),
                 "Error from p9_build_smp_insert_chip");

        if (l_master_chip_sys_next)
        {
            l_master_chip_next_group_id = l_group_id;
        }
    }

    // ensure that new system master was designated
    FAPI_ASSERT(l_master_chip_sys_next_found,
                fapi2::P9_BUILD_SMP_NO_MASTER_DESIGNATION_ERR()
                .set_MASTER_CHIP_SYS_NEXT_TARGET(i_master_chip_sys_next)
                .set_OP(i_op),
                "No chips found in input vector which match target designated as master");

    // check that SMP size does not exceed maximum number of chips supported
    FAPI_ASSERT(i_chips.size() <= P9_BUILD_SMP_MAX_SIZE,
                fapi2::P9_BUILD_SMP_MAX_SIZE_ERR()
                .set_SIZE(i_chips.size())
                .set_MAX_SIZE(P9_BUILD_SMP_MAX_SIZE)
                .set_OP(i_op),
                "Number of chips found in input vector exceeds supported SMP size");

    // based on master designation, and operation phase,
    // determine whether each chip will be quiesced as a result
    // of hotplug switch activity
    for (auto g_iter = io_smp.groups.begin();
         g_iter != io_smp.groups.end();
         g_iter++)
    {
        for (auto p_iter = g_iter->second.chips.begin();
             p_iter != g_iter->second.chips.end();
             p_iter++)
        {
            if (((i_op == SMP_ACTIVATE_PHASE1) &&
                 (p_iter->second.issue_quiesce_next)) ||
                ((i_op == SMP_ACTIVATE_PHASE2) &&
                 (g_iter->first != l_master_chip_next_group_id)))
            {
                p_iter->second.quiesced_next = true;
            }
            else
            {
                p_iter->second.quiesced_next = false;
            }
        }
    }

fapi_try_exit:
    FAPI_DBG("End");
    return fapi2::current_err;
}
Пример #18
0
///
/// @brief Insert chip structure into proper position within SMP strucure based
///        on its fabric group/chip IDs
///
/// @param[in] i_target                 Processor chip target
/// @param[in] i_master_chip_sys_next   Flag designating this chip should be designated fabric
///                                     system master post-reconfiguration
///                                     NOTE: this chip must currently be designated a
///                                           master in its enclosing fabric
///                                           PHASE1/HB: any chip
///                                           PHASE2/FSP: any current drawer master
/// @param[in] i_op                     Enumerated type representing SMP build phase (HB or FSP)
/// @param[in/out] io_smp               Fully specified structure encapsulating SMP
/// @param[out] o_group_id              Group which chip belongs to
///
/// @return FAPI2_RC_SUCCESS if success, else error code.
///
fapi2::ReturnCode
p9_build_smp_insert_chip(fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
                         const bool i_master_chip_sys_next,
                         const p9_build_smp_operation i_op,
                         p9_build_smp_system& io_smp,
                         uint8_t& o_group_id)
{
    FAPI_DBG("Start");
    uint8_t l_group_id;
    uint8_t l_chip_id;
    p9_build_smp_chip l_smp_chip;
    bool l_first_chip_found_in_group = false;
    std::map<uint8_t, p9_build_smp_group>::iterator g_iter;
    std::map<uint8_t, p9_build_smp_chip>::iterator p_iter;

    // get chip/group ID attributes
    FAPI_TRY(p9_fbc_utils_get_group_id_attr(i_target, l_group_id),
             "Error from p9_fbc_utils_get_group_id_attr");
    FAPI_TRY(p9_fbc_utils_get_chip_id_attr(i_target, l_chip_id),
             "Error from p9_fbc_utils_get_chip_id_attr");

    // search to see if group structure already exists for the group this chip resides in
    g_iter = io_smp.groups.find(l_group_id);

    // if no matching groups found, create one
    if (g_iter == io_smp.groups.end())
    {
        FAPI_DBG("No matching group found, inserting new group structure");
        // insert new group into SMP structure
        p9_build_smp_group l_smp_group;
        l_smp_group.group_id = l_group_id;
        auto l_ret = io_smp.groups.insert(std::pair<uint8_t, p9_build_smp_group>(l_group_id, l_smp_group));
        g_iter = l_ret.first;
        FAPI_ASSERT(l_ret.second,
                    fapi2::P9_BUILD_SMP_GROUP_ADD_INTERNAL_ERR()
                    .set_TARGET(i_target)
                    .set_GROUP_ID(l_group_id),
                    "Error encountered adding group to SMP");
        // mark as first chip found in its group
        l_first_chip_found_in_group = true;
    }

    // ensure that no chip has already been inserted into this group
    // with the same chip ID as this chip
    p_iter = io_smp.groups[l_group_id].chips.find(l_chip_id);
    // matching chip ID & group ID already found, flag an error
    FAPI_ASSERT(p_iter == io_smp.groups[l_group_id].chips.end(),
                fapi2::P9_BUILD_SMP_DUPLICATE_FABRIC_ID_ERR()
                .set_TARGET1(i_target)
                .set_TARGET2(*(p_iter->second.target))
                .set_GROUP_ID(l_group_id)
                .set_CHIP_ID(l_chip_id),
                "Multiple chips found with the same fabric group ID / chip ID attribute values");

    // process/fill chip data structure
    FAPI_TRY(p9_build_smp_process_chip(i_target,
                                       l_group_id,
                                       l_chip_id,
                                       i_master_chip_sys_next,
                                       l_first_chip_found_in_group,
                                       i_op,
                                       l_smp_chip),
             "Error from p9_build_smp_process_chip");

    // insert chip into SMP structure
    FAPI_INF("Inserting g%d p%d", l_group_id, l_chip_id);
    io_smp.groups[l_group_id].chips[l_chip_id] = l_smp_chip;

    // return group ID
    o_group_id = l_group_id;

fapi_try_exit:
    FAPI_DBG("End");
    return fapi2::current_err;
}
Пример #19
0
    ///
    ///@brief mss_thermal_init procedure. Configure and start the OCC cache and Centaur thermal cache
    ///@param[in]  i_target  Reference to centaur target
    ///@return ReturnCode
    ///
    fapi2::ReturnCode p9c_mss_thermal_init(const fapi2::Target<fapi2::TARGET_TYPE_MEMBUF_CHIP>& i_target)
    {
        FAPI_INF("*** Running mss_thermal_init ***");

        constexpr uint32_t I2C_SETUP_UPPER_HALF = 0xD2314049;
        constexpr uint32_t I2C_SETUP_LOWER_HALF = 0x05000000;
        constexpr uint32_t ACT_MASK_UPPER_HALF = 0x00018000;
        constexpr uint32_t ACT_MASK_LOWER_HALF = 0x00000000;
        // OCC polls cacheline every 2 ms (could vary from this, as seen on scope)
        // For I2C bus at 50kHz (9.6 ms max to read 8 sensors), use interval of 15 for margin and to prevent stall errors when 8 sensors are enabled to be read
        constexpr uint32_t CONFIG_INTERVAL_TIMER = 15;
        constexpr uint32_t CONFIG_STALL_TIMER = 128;
        constexpr uint8_t I2C_BUS_ENCODE_PRIMARY = 0;
        constexpr uint8_t I2C_BUS_ENCODE_SECONDARY = 8;
        constexpr uint8_t MAX_NUM_DIMM_SENSORS = 8;
        constexpr uint8_t MAX_I2C_BUSSES = 2;

        // Variable declaration
        uint8_t l_dimm_ranks_array[MAX_MBA_PER_CEN][MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0};    // Number of ranks for each configured DIMM in each MBA
        uint8_t l_custom_dimm[MAX_MBA_PER_CEN] = {0};               // Custom DIMM
        uint8_t l_mba_pos = 0;                        // Current MBA for populating rank array
        fapi2::buffer<uint64_t> l_data;
        fapi2::buffer<uint64_t> l_data_scac_enable;
        fapi2::buffer<uint64_t> l_data_scac_addrmap;
        uint8_t l_cdimm_sensor_map = 0;
        uint8_t l_cdimm_sensor_map_primary = 0;
        uint8_t l_cdimm_sensor_map_secondary = 0;
        uint8_t l_cdimm_number_dimm_temp_sensors = 0;
        uint8_t l_i2c_address_map = 0;
        uint8_t l_data_scac_addrmap_offset = 0;
        uint8_t l_i2c_bus_encode = 0;
        uint8_t l_sensor_map_mask = 0;
        uint8_t l_master_i2c_temp_sensor_enable = 0;
        uint8_t l_spare_i2c_temp_sensor_enable = 0;
        uint32_t l_dimm_sensor_cache_addr_map = 0;
        fapi2::buffer<uint64_t> l_reset;
        uint8_t l_enable_safemode_throttle = 0;
        // Get input attributes from MBAs
        const auto l_target_mba_array = i_target.getChildren<fapi2::TARGET_TYPE_MBA>();

        //********************************************
        // Centaur internal temperature polling setup
        //********************************************
        // setup hang pulse
        FAPI_TRY(fapi2::getScom(i_target, CEN_PCBSLNEST_HANG_PULSE_0_REG_PCB, l_data));
        l_data.setBit<1>().setBit<2>();
        FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLNEST_HANG_PULSE_0_REG_PCB, l_data));
        FAPI_TRY(fapi2::getScom(i_target, CEN_TCN_THERM_MODE_REG_PCB, l_data));
        // setup DTS enables  NOTE: Does this need to be scom'd before enable dts sampling? LM
        l_data.setBit<20>().setBit<21>();
        // setup pulse count and enable DTS sampling
        l_data.setBit<5>().setBit<6>().setBit<7>().setBit<8>().setBit<9>();
        FAPI_TRY(fapi2::putScom(i_target, CEN_TCN_THERM_MODE_REG_PCB, l_data));
        // issue a reset
        l_data.flush<0>().setBit<0>().setBit<1>().setBit<2>().setBit<3>().setBit<4>();
        FAPI_TRY(fapi2::putScom(i_target, CEN_TCN_CONTROL_REG_PCB, l_data));
        // Centaur internal temperature polling setup complete

        for (const auto& mba : l_target_mba_array)
        {
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, mba, l_mba_pos), "Failed to get attr ATTR_CHIP_UNIT_POS on %s",
                     mss::c_str(mba));
            FAPI_INF("MBA_POS: %d", l_mba_pos);

            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_NUM_RANKS_PER_DIMM, mba, l_dimm_ranks_array[l_mba_pos]),
                     "Failed to get attr ATTR_CEN_EFF_NUM_RANKS_PER_DIMM on %s", mss::c_str(mba));
            FAPI_INF("EFF_NUM_RANKS: %d:%d:%d:%d", l_dimm_ranks_array[l_mba_pos][0][0], l_dimm_ranks_array[l_mba_pos][0][1],
                     l_dimm_ranks_array[l_mba_pos][1][0], l_dimm_ranks_array[l_mba_pos][1][1]);

            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_CUSTOM_DIMM, mba,  l_custom_dimm[l_mba_pos]),
                     "Failed to get attr ATTR_CEN_EFF_CUSTOM_DIMM on %s", mss::c_str(mba));
            FAPI_INF("ATTR_EFF_CUSTOM_DIMM: %d", l_custom_dimm[l_mba_pos]);
        }

        // Get attributes for dimm temperature sensor mapping for only a custom dimm so we don't get an error
        // Get attritute for custom dimms for enablement on the master i2c bus
        if ((l_custom_dimm[0] == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES)
            || (l_custom_dimm[1] == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES))
        {
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_VPD_CDIMM_SENSOR_MAP_PRIMARY, i_target,  l_cdimm_sensor_map_primary),
                     "Failed to get attr ATTR_CEN_VPD_CDIMM_SENSOR_MAP_PRIMARY on %s", mss::c_str(i_target));
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_VPD_CDIMM_SENSOR_MAP_SECONDARY, i_target,  l_cdimm_sensor_map_secondary),
                     "Failed to get attr ATTR_CEN_VPD_CDIMM_SENSOR_MAP_SECONDARY on %s", mss::c_str(i_target));
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MRW_CDIMM_MASTER_I2C_TEMP_SENSOR_ENABLE,
                                   fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_master_i2c_temp_sensor_enable),
                     "Failed to get attr ATTR_CEN_MRW_CDIMM_MASTER_I2C_TEMP_SENSOR_ENABLE on %s", mss::c_str(i_target));
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MRW_CDIMM_SPARE_I2C_TEMP_SENSOR_ENABLE,
                                   fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_spare_i2c_temp_sensor_enable),
                     "Failed to get attr ATTR_CEN_MRW_CDIMM_SPARE_I2C_TEMP_SENSOR_ENABLE on %s", mss::c_str(i_target));
        }
        else
        {
            // sensor cache address map for non custom dimm temperature sensors (which i2c bus and i2c address they are)
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MRW_MEM_SENSOR_CACHE_ADDR_MAP, i_target,  l_dimm_sensor_cache_addr_map),
                     "Failed to get attr ATTR_CEN_MRW_MEM_SENSOR_CACHE_ADDR_MAP on %s", mss::c_str(i_target));
        }

        // Configure Centaur Thermal Cache

        // ---------------------------------
        // Clear the master enable bit
        // ---------------------------------

        FAPI_TRY(fapi2::getScom(i_target, CEN_SCAC_CONFIG, l_data));
        l_data.clearBit<0>(); //Master enable is bit 0
        FAPI_TRY(fapi2::putScom(i_target, CEN_SCAC_CONFIG, l_data));

        // ---------------------------------
        // Mask FIR bit 33
        // Sets if any sensor cache addresses are written while the master enable is set
        // ---------------------------------

        FAPI_TRY(fapi2::getScom(i_target, CEN_SCAC_FIRMASK, l_data));
        l_data.setBit<33>();
        FAPI_TRY(fapi2::putScom(i_target, CEN_SCAC_FIRMASK, l_data));

        // ---------------------------------
        // Program PibTarget<fapi2::TARGET_TYPE_MBA> Register
        // ---------------------------------

        FAPI_TRY(fapi2::getScom(i_target, CEN_SCAC_PIBTARGET, l_data));
        l_data.insert<0, 32, 0>(CEN_I2CM_CONTROL_REGISTER_0_WOX);
        l_data.insert<32, 32, 0>(CEN_I2CM_CONTROL_REGISTER_0_WOX);
        FAPI_TRY(fapi2::putScom(i_target, CEN_SCAC_PIBTARGET, l_data));

        // ---------------------------------
        // Program I2CMCtrl Register
        // ---------------------------------

        FAPI_TRY(fapi2::getScom(i_target, CEN_SCAC_I2CMCTRL_SCAC_I2CMCTRL, l_data));
        l_data.insert<0, 32, 0>(I2C_SETUP_UPPER_HALF);
        l_data.insert<32, 32, 0>(I2C_SETUP_LOWER_HALF);
        FAPI_TRY(fapi2::putScom(i_target, CEN_SCAC_I2CMCTRL_SCAC_I2CMCTRL, l_data));


        // ---------------------------------
        // Program Action Mask Register
        // ---------------------------------

        FAPI_TRY(fapi2::getScom(i_target, CEN_SCAC_ACTIONMASK, l_data));
        l_data.insert<0, 32, 0>(ACT_MASK_UPPER_HALF);
        l_data.insert<32, 32, 0>(ACT_MASK_LOWER_HALF);
        FAPI_TRY(fapi2::putScom(i_target, CEN_SCAC_ACTIONMASK, l_data));


        // ---------------------------------
        // Program SensorCacheConfiguration Register
        // ---------------------------------

        FAPI_TRY(fapi2::getScom(i_target, CEN_SCAC_CONFIG, l_data));
        l_data.setBit<1>();   //Sync to OCC_Read signal
        l_data.insert < 11, 5, 32 - 5 > (CONFIG_INTERVAL_TIMER);
        l_data.insert < 16, 8, 32 - 8 > (CONFIG_STALL_TIMER);
        FAPI_TRY(fapi2::putScom(i_target, CEN_SCAC_CONFIG, l_data));

        // --------------------------------------------------------
        // Program SensorCacheEnable and SensorAddressMap Registers
        // --------------------------------------------------------

        FAPI_TRY(fapi2::getScom(i_target, CEN_SCAC_ENABLE, l_data_scac_enable));

        FAPI_TRY(fapi2::getScom(i_target, CEN_SCAC_ADDRMAP, l_data_scac_addrmap));

        if ((l_custom_dimm[0] == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES)
            || (l_custom_dimm[1] == fapi2::ENUM_ATTR_CEN_EFF_CUSTOM_DIMM_YES))
        {

            l_cdimm_number_dimm_temp_sensors = 0;

            // cycle through both primary and secondary i2c busses, determine i2c address and enable bits
            for (uint8_t l_i2c_bus = 0; l_i2c_bus < MAX_I2C_BUSSES; l_i2c_bus++)
            {
                for (uint8_t l_dimm_sensor = 0; l_dimm_sensor < MAX_NUM_DIMM_SENSORS; l_dimm_sensor++)
                {
                    if (l_i2c_bus == 0)
                    {
                        l_i2c_bus_encode = I2C_BUS_ENCODE_PRIMARY;
                        l_cdimm_sensor_map = l_cdimm_sensor_map_primary;
                    }
                    else
                    {
                        l_i2c_bus_encode = I2C_BUS_ENCODE_SECONDARY;
                        l_cdimm_sensor_map = l_cdimm_sensor_map_secondary;
                    }

                    switch (l_dimm_sensor)
                    {
                        case 0:
                            l_sensor_map_mask = 0x01;
                            break;

                        case 1:
                            l_sensor_map_mask = 0x02;
                            break;

                        case 2:
                            l_sensor_map_mask = 0x04;
                            break;

                        case 3:
                            l_sensor_map_mask = 0x08;
                            break;

                        case 4:
                            l_sensor_map_mask = 0x10;
                            break;

                        case 5:
                            l_sensor_map_mask = 0x20;
                            break;

                        case 6:
                            l_sensor_map_mask = 0x40;
                            break;

                        case 7:
                            l_sensor_map_mask = 0x80;
                            break;

                        default:
                            l_sensor_map_mask = 0x00;
                    }

                    if ((l_cdimm_sensor_map & l_sensor_map_mask) != 0)
                    {
                        if(
                            (
                                (l_i2c_bus == 0)
                                &&
                                (l_master_i2c_temp_sensor_enable ==
                                 fapi2::ENUM_ATTR_CEN_MRW_CDIMM_MASTER_I2C_TEMP_SENSOR_ENABLE_ON)
                            )
                            ||
                            (
                                (l_i2c_bus == 1)
                                &&
                                (l_spare_i2c_temp_sensor_enable ==
                                 fapi2::ENUM_ATTR_CEN_MRW_CDIMM_SPARE_I2C_TEMP_SENSOR_ENABLE_ON)
                            )
                        )

                        {
                            FAPI_TRY(l_data_scac_enable.setBit(l_cdimm_number_dimm_temp_sensors));
                        }

                        l_i2c_address_map = l_dimm_sensor + l_i2c_bus_encode;
                        l_data_scac_addrmap_offset = l_cdimm_number_dimm_temp_sensors * 4;
                        FAPI_TRY(l_data_scac_addrmap.insert(l_i2c_address_map, l_data_scac_addrmap_offset , 4, 4));
                        l_cdimm_number_dimm_temp_sensors++;
                        FAPI_ASSERT(l_cdimm_number_dimm_temp_sensors <= MAX_NUM_DIMM_SENSORS,
                                    fapi2::CEN_MSS_CDIMM_INVALID_NUMBER_SENSORS().
                                    set_MEM_CHIP(i_target).
                                    set_FFDC_DATA_1(l_cdimm_sensor_map_primary).
                                    set_FFDC_DATA_2(l_cdimm_sensor_map_secondary),
                                    "Invalid number of dimm temperature sensors specified in the CDIMM VPD MW keyword");

                    } // end if sensor map and mask != 0
                } // end for sensor
            } //end for i2c bus
        } //end if custom dimm
        else
        {
            // Iterate through the num_ranks array to determine what DIMMs are plugged
            // Enable sensor monitoring for each plugged DIMM
            uint32_t l_iterator = 0;

            for (uint32_t l_mba_index = 0; l_mba_index < MAX_MBA_PER_CEN; l_mba_index++)
            {
                if (l_dimm_ranks_array[l_mba_index][0][0] != 0)
                {
                    FAPI_TRY(l_data_scac_enable.setBit(l_iterator));
                }

                l_iterator++;

                if (l_dimm_ranks_array[l_mba_index][0][1] != 0)
                {
                    FAPI_TRY(l_data_scac_enable.setBit(l_iterator));
                }

                l_iterator++;

                if (l_dimm_ranks_array[l_mba_index][1][0] != 0)
                {
                    FAPI_TRY(l_data_scac_enable.setBit(l_iterator));
                }

                l_iterator++;

                if (l_dimm_ranks_array[l_mba_index][1][1] != 0)
                {
                    FAPI_TRY(l_data_scac_enable.setBit(l_iterator));
                }

                l_iterator++;
            }

            l_data_scac_addrmap.insert<0, 32, 0>(l_dimm_sensor_cache_addr_map);

        } //end not custom dimm

        FAPI_TRY(fapi2::putScom(i_target, CEN_SCAC_ENABLE, l_data_scac_enable));

        FAPI_TRY(fapi2::putScom(i_target, CEN_SCAC_ADDRMAP, l_data_scac_addrmap));

        //---------------------------------
        // Reset the I2CM
        //---------------------------------

        l_reset.setBit<0>();
        FAPI_TRY(fapi2::putScom(i_target, CEN_I2CM_RESET_REGISTER_0_WOX, l_reset));

        // ---------------------------------
        // Set the master enable bit
        // ---------------------------------

        FAPI_TRY(fapi2::getScom(i_target, CEN_SCAC_CONFIG, l_data));
        l_data.setBit<0>();
        FAPI_TRY(fapi2::putScom(i_target, CEN_SCAC_CONFIG, l_data));

        // Configure Centaur Thermal Cache COMPLETED

        // Disable Emergency Throttles

        // ---------------------------------
        // Clear the emergency throttle FIR bit (MBS FIR 21)
        // ---------------------------------

        FAPI_TRY(fapi2::getScom(i_target, CEN_MBS_FIR_REG, l_data));
        l_data.clearBit<21>();
        FAPI_TRY(fapi2::putScom(i_target, CEN_MBS_FIR_REG, l_data));


        // ---------------------------------
        // Reset emergency throttle in progress bit (EMER THROT 0)
        // ---------------------------------

        FAPI_TRY(fapi2::getScom(i_target, CEN_MBSEMERTHROQ, l_data));
        l_data.clearBit<0>();
        FAPI_TRY(fapi2::putScom(i_target, CEN_MBSEMERTHROQ, l_data));

        // Disable Emergency Throttles COMPLETED


        // Write the IPL Safe Mode Throttles
        // For centaur DD2 and above since OCC only writes runtime throttles for this

        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_CENTAUR_EC_FEATURE_ENABLE_SAFEMODE_THROTTLE,
                               i_target,
                               l_enable_safemode_throttle));

        if (l_enable_safemode_throttle)
        {
            uint32_t l_safemode_throttle_n_per_mba;
            uint32_t l_safemode_throttle_n_per_chip;
            uint32_t l_throttle_d;

            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MRW_SAFEMODE_MEM_THROTTLE_NUMERATOR_PER_MBA,
                                   fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(),
                                   l_safemode_throttle_n_per_mba));

            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MRW_SAFEMODE_MEM_THROTTLE_NUMERATOR_PER_CHIP,
                                   fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(),
                                   l_safemode_throttle_n_per_chip));

            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MRW_MEM_THROTTLE_DENOMINATOR,
                                   fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(),
                                   l_throttle_d));

            // write the N/M throttle control register
            for (const auto& mba : l_target_mba_array)
            {
                FAPI_TRY(fapi2::getScom(mba, CEN_MBA_MBA_FARB3Q, l_data));
                l_data.insertFromRight<0, 15>(l_safemode_throttle_n_per_mba);
                l_data.insertFromRight<15, 16>(l_safemode_throttle_n_per_chip);
                l_data.insertFromRight<31, 14>(l_throttle_d);
                FAPI_TRY(fapi2::putScom(mba, CEN_MBA_MBA_FARB3Q, l_data));
            }
        }

        // If mss_unmask_fetch_errors gets it's own bad rc,
        // it will commit the passed in rc (if non-zero), and return it's own bad rc.
        // Else if mss_unmask_fetch_errors runs clean,
        // it will just return the passed in rc.
        FAPI_TRY(mss_unmask_fetch_errors(i_target));

        FAPI_INF("*** mss_thermal_init COMPLETE ***");
    fapi_try_exit:
        return fapi2::current_err;

    } //end mss_thermal_init
Пример #20
0
fapi2::ReturnCode
p9_rng_init_phase2(const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target)
{
    FAPI_INF("Start");
    fapi2::buffer<uint64_t> l_rng_cfg_data;
    fapi2::buffer<uint64_t> l_rng_bar_data;
    fapi2::buffer<uint64_t> l_rng_failed_int_data;
    fapi2::buffer<uint64_t> l_security_switch_data;

    uint16_t l_rng_cfg_self_test_hard_fail_status = 0;
    uint8_t  l_nx_rng_bar_enable = 0;
    uint64_t l_nx_rng_bar_addr = 0;
    uint64_t l_nx_rng_bar_base_addr_offset = 0;
    uint8_t  l_nx_rng_failed_int_enable = 0;
    uint64_t l_nx_rng_failed_int_addr = 0;
    std::vector<uint64_t> l_base_addr_nm0, l_base_addr_nm1, l_base_addr_m;
    uint64_t l_base_addr_mmio;
    uint8_t  l_HW403701;

    // 5. RNG is allowed to run for M cycles (M = enough time to complete init;
    // recommend 1 second of time).
    // NOTE: accomplished by delay in execution time between phase1/phase2 HWPs

    // get the self test hard fail status in RNG CFG register
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_EC_FEATURE_HW403701,
                           i_target,
                           l_HW403701),
             "Error from FAPI_ATTR_GET (ATTR_CHIP_EC_FEATURE_HW403701)");

    FAPI_TRY(fapi2::getScom(i_target, PU_NX_RNG_CFG, l_rng_cfg_data),
             "Error from getScom (NX RNG Status and Control Register)");

    if (!l_HW403701)
    {
        // 6. Host boot checks RNG fail bits again and if a fail is detected
        // then RNG is declared broken

        FAPI_DBG("Checking RNG fail status...");
        // exit if failure is reported in self test hard fail status field
        l_rng_cfg_data.extractToRight<PU_NX_RNG_CFG_FAIL_REG,
                                      PU_NX_RNG_CFG_FAIL_REG_LEN>(l_rng_cfg_self_test_hard_fail_status);
        FAPI_ASSERT(!l_rng_cfg_self_test_hard_fail_status,
                    fapi2::P9_RNG_INIT_SELF_TEST_FAILED_ERR().
                    set_TARGET(i_target).
                    set_SELF_TEST_HARD_FAIL_STATUS(l_rng_cfg_self_test_hard_fail_status),
                    "Self test hard fail status indicates failure");
    }
    else
    {
        FAPI_DBG("Skipping check of RNG fail status...");
    }

    // 7. Host boot maps RNG BARs (see Section 5.31 RNG BAR on page 185).
    // • NX RNG BAR (not mapped/enabled if RNG is broken)
    // • NCU RNG BAR (always mapped to good RNG)
    // • NX RNG Fail Interrupt Addres

    // self test indicates no hard fail
    // if instructed to map the BAR:
    // - enable NX RNG MMIO BAR and get the bar address attributes
    // - optionally map NX RNG failed interrupt address
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PROC_NX_RNG_BAR_ENABLE,
                           i_target,
                           l_nx_rng_bar_enable),
             "Error from FAPI_ATTR_GET (ATTR_PROC_NX_BAR_ENABLE)");

    FAPI_TRY(p9_fbc_utils_get_chip_base_address(i_target,
             EFF_FBC_GRP_CHIP_IDS,
             l_base_addr_nm0,
             l_base_addr_nm1,
             l_base_addr_m,
             l_base_addr_mmio),
             "Error from p9_fbc_utils_get_chip_base_address");

    // get RNG BAR addr
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PROC_NX_RNG_BAR_BASE_ADDR_OFFSET,
                           i_target.getParent<fapi2::TARGET_TYPE_SYSTEM>(),
                           l_nx_rng_bar_base_addr_offset),
             "Error from FAPI_ATTR_GET (ATTR_PROC_NX_BAR_BASE_ADDR_OFFSET)");

    // caculate the NX RNG BAR ADDR based on the bar adddr offset
    l_nx_rng_bar_addr = l_base_addr_mmio;
    l_nx_rng_bar_addr += l_nx_rng_bar_base_addr_offset;

    if (l_nx_rng_bar_enable == fapi2::ENUM_ATTR_PROC_NX_RNG_BAR_ENABLE_ENABLE)
    {
        // map NX RNG MMIO BAR
        l_rng_bar_data.setBit<PU_NX_MMIO_BAR_ENABLE>();
        l_rng_bar_data.insert<PU_NX_MMIO_BAR_BAR,
                              PU_NX_MMIO_BAR_BAR_LEN, PU_NX_MMIO_BAR_BAR>(l_nx_rng_bar_addr);
        FAPI_TRY(fapi2::putScom(i_target, PU_NX_MMIO_BAR, l_rng_bar_data),
                 "Error from putScom (PU_NX_MMIO_BAR)");

        // map NX RNG failed interrupt address
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PROC_NX_RNG_FAILED_INT_ENABLE,
                               i_target,
                               l_nx_rng_failed_int_enable),
                 "Error from FAPI_ATTR_GET (ATTR_PROC_NX_RNG_FAILED_INT_ENABLE)");
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PROC_NX_RNG_FAILED_INT_ADDR,
                               i_target,
                               l_nx_rng_failed_int_addr),
                 "Error from FAPI_ATTR_GET (ATTR_PROC_NX_RNG_FAILED_INT_ADDR)");

        if (l_nx_rng_failed_int_enable ==
            fapi2::ENUM_ATTR_PROC_NX_RNG_FAILED_INT_ENABLE_ENABLE)
        {
            l_rng_failed_int_data.setBit<PU_RNG_FAILED_INT_ENABLE>();
            l_rng_failed_int_data.insert<PU_RNG_FAILED_INT_ADDRESS,
                                         PU_RNG_FAILED_INT_ADDRESS_LEN, PU_RNG_FAILED_INT_ADDRESS>
                                         (l_nx_rng_failed_int_addr);

            FAPI_TRY(fapi2::putScom(i_target,
                                    PU_RNG_FAILED_INT,
                                    l_rng_failed_int_data),
                     "Error from putScom (NX RNG Failed Interrupt Address Register");
        }
        else
        {
            FAPI_DBG("Skipping setup of NX RNG Failed Interrupt Address Register");
        }
    }
    else
    {
        FAPI_DBG("Skipping NX RNG BAR programming!");
    }

    // set NX RNG enable
    l_rng_cfg_data.setBit<PU_NX_RNG_CFG_ENABLE>();
    FAPI_TRY(fapi2::putScom(i_target, PU_NX_RNG_CFG, l_rng_cfg_data),
             "Error from putScom (NX RNG Status and Control Register)");

    // 8. Host boot sets the NX “sticky bit” that asserts
    // tc_nx_block_rng_scom_wr. If tc_nx_block_rng_scom_wr = 1 writes to RNG
    // SCOM register addresses 32 - 38 and 40 are blocked. An attempted
    // write sets Power-Bus Interface FIR Data Register[Write to RNG SCOM
    // reg detected when writes disabled].

    // set NX sticky bit to block future RNG SCOM writes
    // (tc_nx_block_rng_scom_wr)
    FAPI_TRY(fapi2::getScom(i_target,
                            PU_SECURITY_SWITCH_REGISTER_SCOM,
                            l_security_switch_data),
             "Error from getScom (Security Switch Register");

    l_security_switch_data.setBit<PU_SECURITY_SWITCH_REGISTER_NX_RAND_NUM_GEN_LOCK>();

    FAPI_TRY(fapi2::putScom(i_target,
                            PU_SECURITY_SWITCH_REGISTER_SCOM,
                            l_security_switch_data),
             "Error from putScom (Security Switch Register");

fapi_try_exit:
    FAPI_INF("End");
    return fapi2::current_err;
}
// See doxygen in header file
fapi2::ReturnCode p9_pm_get_poundw_bucket_attr(
    const fapi2::Target<fapi2::TARGET_TYPE_EQ>& i_target,
    uint8_t* o_data)
{
    FAPI_DBG("Entering p9_pm_get_poundw_bucket_attr ....");
    uint8_t* l_fullVpdData = nullptr;
    uint32_t l_vpdSize = 0;
    uint8_t l_bucketId;
    uint8_t l_bucketSize = 0;

    //To read MVPD we will need the proc parent of the inputted EQ target
    fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP> l_procParent =
        i_target.getParent<fapi2::TARGET_TYPE_PROC_CHIP>();

    //Get the #V bucket associated with EQ target
    fapi2::voltageBucketData_t l_voltageBucket;

    FAPI_TRY( p9_pm_get_poundv_bucket(i_target,
                                      l_voltageBucket) );

    //Use the bucket ID from the #V bucket
    l_bucketId = l_voltageBucket.bucketId;

    //First read is to get size of vpd record, note the o_buffer is NULL
    FAPI_TRY( getMvpdField(fapi2::MVPD_RECORD_CRP0,
                           fapi2::MVPD_KEYWORD_PDW,
                           l_procParent,
                           NULL,
                           l_vpdSize) );

    //Allocate memory for vpd data
    l_fullVpdData = reinterpret_cast<uint8_t*>(malloc(l_vpdSize));

    //Second read is to get data of vpd record
    FAPI_TRY( getMvpdField(fapi2::MVPD_RECORD_CRP0,
                           fapi2::MVPD_KEYWORD_PDW,
                           l_procParent,
                           l_fullVpdData,
                           l_vpdSize) );

    //#W record is laid out as follows:
    //Name:                  0x2 byte
    //Length:                0x2 byte
    //Version:               0x1 byte **buffer starts here
    //#V Bucket ID #1:       0x1 byte
    //VDM Data for bucket 1: varies by version
    //#V Bucket ID #2:       0x1 byte
    //VDM Data for bucket 2: varies by version
    //#V Bucket ID #3:       0x1 byte
    //VDM Data for bucket 3: varies by version
    //#V Bucket ID #4:       0x1 byte
    //VDM Data for bucket 4: varies by version
    //#V Bucket ID #5:       0x1 byte
    //VDM Data for bucket 5: varies by version
    //#V Bucket ID #6:       0x1 byte
    //VDM Data for bucket 6: varies by version
    if( *l_fullVpdData == POUNDW_VERSION_1)
    {
        //Set the size of the bucket
        l_bucketSize = POUNDW_BUCKETID_SIZE + PW_VER_1_VDMDATA_SIZE;
    }
    else if( *l_fullVpdData == POUNDW_VERSION_2)
    {
        //Set the size of the bucket
        l_bucketSize = POUNDW_BUCKETID_SIZE + PW_VER_2_VDMDATA_SIZE;
    }
    else
    {
        FAPI_ASSERT( false,
                     fapi2::INVALID_POUNDW_VERSION()
                     .set_EQ_TARGET(i_target)
                     .set_POUNDW_VERSION(*l_fullVpdData),
                     "p9_pm_get_poundw_bucket_attr::Invalid #W record "
                     "version: 0x%x",
                     *l_fullVpdData);
    }

    //Copy version into output data
    *o_data = *l_fullVpdData;

    // This assert ensures the size of the calculated data is correct
    FAPI_ASSERT(l_vpdSize - POUNDW_VERSION_SIZE - ((l_bucketId - 1) *
                l_bucketSize) >= l_bucketSize,
                fapi2::BAD_POUNDW_VPD_READ()
                .set_EQ_TARGET(i_target)
                .set_EXPECTED_SIZE(l_bucketSize)
                .set_ACTUAL_SIZE(l_vpdSize - POUNDW_VERSION_SIZE -
                                 ((l_bucketId - 1) * l_bucketSize)),
                "#W data read was too small!" );

    // Use the selected bucket id to populate the output data
    memcpy(o_data + POUNDW_VERSION_SIZE,
           l_fullVpdData + POUNDW_VERSION_SIZE +
           ((l_bucketId - 1) * l_bucketSize),
           l_bucketSize);

    // This assert ensures the output data bucket ID matches what we looked for
    FAPI_ASSERT( (l_bucketId == ((fapi2::vdmData_t*)o_data)->bucketId),
                 fapi2::INCORRECT_POUNDW_BUCKET_ID()
                 .set_EQ_TARGET(i_target)
                 .set_BUCKET_ID(((fapi2::vdmData_t*)o_data)->bucketId)
                 .set_EXP_BUCKET_ID(l_bucketId),
                 "Incorrect Bucket Id = %d, expected %d",
                 ((fapi2::vdmData_t*)o_data)->bucketId,
                 l_bucketId );

fapi_try_exit:

    if(l_fullVpdData != NULL)
    {
        free(l_fullVpdData);
        l_fullVpdData = NULL;
    }

    FAPI_DBG("Exiting p9_pm_get_poundw_bucket_attr ....");

    return fapi2::current_err;
}
Пример #22
0
fapi2::ReturnCode p9a_omi_setup_bars(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target)
{
    FAPI_DBG("Start");
    std::vector<uint64_t> l_base_addr_nm0;
    std::vector<uint64_t> l_base_addr_nm1;
    std::vector<uint64_t> l_base_addr_m;
    fapi2::buffer<uint64_t> l_mmio_bar;
    fapi2::buffer<uint64_t> l_cfg_bar;
    uint64_t l_base_addr_mmio;
    uint8_t l_pos;
    uint8_t l_mcc_pos;
    uint64_t l_ext_mask;

    // determine base address of chip MMIO range
    FAPI_TRY(p9_fbc_utils_get_chip_base_address(i_target,
             EFF_FBC_GRP_CHIP_IDS,
             l_base_addr_nm0,
             l_base_addr_nm1,
             l_base_addr_m,
             l_base_addr_mmio),
             "Error from p9_fbc_utils_get_chip_base_address");

    FAPI_TRY(p9a_get_ext_mask(l_ext_mask));

    FAPI_DBG("l_ext_mask: %x", l_ext_mask);
    FAPI_DBG("l_base_addr_mmio: 0x%llx", l_base_addr_mmio);

    for (auto l_mcc : i_target.getChildren<fapi2::TARGET_TYPE_MCC>())
    {
        fapi2::ATTR_OMI_INBAND_BAR_BASE_ADDR_OFFSET_Type l_bar_offset;
        uint64_t l_omi_inband_addr = 0;
        fapi2::buffer<uint64_t> l_scom_data;

        auto l_omi_targets = l_mcc.getChildren<fapi2::TARGET_TYPE_OMI>();

        if (l_omi_targets.size() > 0)
        {

            // Set the sizes for the MMIO/Config bars
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, l_mcc, l_pos),
                     "Error getting ATTR_CHIP_UNIT_POS, l_rc 0x%.8X",
                     (uint64_t)fapi2::current_err);

            l_scom_data.flush<0>();
            // 2GB cfg and MMIO
            l_scom_data.insertFromRight<P9A_MI_MCFGP0_MCFGPR0_CONFIGURATION_GROUP_SIZE,
                                        P9A_MI_MCFGP0_MCFGPR0_CONFIGURATION_GROUP_SIZE_LEN>(mss::exp::ib::EXPLR_IB_BAR_SIZE);
            l_scom_data.insertFromRight<P9A_MI_MCFGP0_MCFGPR0_MMIO_GROUP_SIZE,
                                        P9A_MI_MCFGP0_MCFGPR0_MMIO_GROUP_SIZE_LEN>(mss::exp::ib::EXPLR_IB_BAR_SIZE);

            // Write to reg
            if (l_pos % 2 == 0)
            {
                FAPI_INF("Write MCFGP0 reg 0x%.16llX, Value 0x%.16llX",
                         P9A_MI_MCFGP0, l_scom_data);
                FAPI_TRY(fapi2::putScom(l_mcc.getParent<fapi2::TARGET_TYPE_MI>(), P9A_MI_MCFGP0, l_scom_data),
                         "Error writing to MCS_MCFGP reg");
            }
            else
            {
                FAPI_INF("Write MCFGP1 reg 0x%.16llX, Value 0x%.16llX",
                         P9A_MI_MCFGP1, l_scom_data);
                FAPI_TRY(fapi2::putScom(l_mcc.getParent<fapi2::TARGET_TYPE_MI>(), P9A_MI_MCFGP1, l_scom_data),
                         "Error writing to MCS_MCFGP reg");
            }

            for (auto l_omi : l_omi_targets)
            {
                // retrieve OMI pos
                FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS,
                                       l_omi,
                                       l_pos),
                         "Error from FAPI_ATTR_GET (ATTR_CHIP_UNIT_POS)");

                // retrieve inband BAR offset
                FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_OMI_INBAND_BAR_BASE_ADDR_OFFSET,
                                       l_omi,
                                       l_bar_offset),
                         "Error from FAPI_ATTR_GET (ATTR_OMI_INBAND_BAR_BASE_ADDR_OFFSET)");

                FAPI_DBG("l_bar_offset: 0x%llx", l_bar_offset);

                // If this is channel B, then the B bit must be set.  If it is not, then the B bit must not be set.
                FAPI_ASSERT( ((l_pos % 2) == 1) ==  // Is this B channel?
                             ((l_bar_offset & mss::exp::ib::EXPLR_IB_BAR_B_BIT) == mss::exp::ib::EXPLR_IB_BAR_B_BIT),

                             fapi2::PROC_OMI_SETUP_BARS_INVALID_BAR()
                             .set_TARGET(l_omi)
                             .set_BAR_VALUE(l_bar_offset),
                             "B Channel requires BAR size bit set");

                FAPI_ASSERT(((l_bar_offset & mss::exp::ib::EXPLR_IB_BAR_MASK_ZERO) == 0),
                            fapi2::PROC_OMI_SETUP_BARS_INVALID_BAR()
                            .set_TARGET(l_omi)
                            .set_BAR_VALUE(l_bar_offset),
                            "Bar size not honored");

                FAPI_ASSERT(((l_bar_offset & mss::exp::ib::EXPLR_IB_MMIO_OFFSET) == 0),
                            fapi2::PROC_OMI_SETUP_BARS_INVALID_BAR()
                            .set_TARGET(l_omi)
                            .set_BAR_VALUE(l_bar_offset),
                            "MMIO bit must not be set");

                l_omi_inband_addr = l_bar_offset;
            }

            FAPI_DBG("l_omi_inband_addr: 0x%llx", l_omi_inband_addr);

            // Force A Bar value
            l_omi_inband_addr = l_omi_inband_addr & (~mss::exp::ib::EXPLR_IB_BAR_B_BIT);

            FAPI_DBG("l_omi_inband_addr: 0x%llx", l_omi_inband_addr);

            // Add MMIO address for the chip
            l_omi_inband_addr = l_omi_inband_addr | l_base_addr_mmio;

            FAPI_DBG("l_omi_inband_addr: 0x%llx", l_omi_inband_addr);

            // Get cfg bar value
            fapi2::buffer<uint64_t> l_omi_inband_buf = l_omi_inband_addr;
            FAPI_DBG("l_omi_inband_buf: 0x%llx", l_omi_inband_buf);
            FAPI_TRY(extendBarAddress(l_ext_mask, l_omi_inband_buf, l_cfg_bar));

            FAPI_DBG("l_cfg_bar: 0x%llx", l_cfg_bar);

            // Get MMIO bar value
            l_omi_inband_addr = l_omi_inband_addr | mss::exp::ib::EXPLR_IB_MMIO_OFFSET;
            l_omi_inband_buf = l_omi_inband_addr;
            FAPI_DBG("l_omi_inband_buf: 0x%llx", l_omi_inband_buf);
            FAPI_TRY(extendBarAddress(l_ext_mask, l_omi_inband_buf, l_mmio_bar));

            FAPI_DBG("l_mmio_bar: 0x%llx", l_mmio_bar);

            // Write the channel cfg reg
            l_scom_data.flush<0>();
            l_scom_data.setBit<P9A_MI_MCFGPR0_CONFIGURATION_VALID>(); //Enable CFG
            l_scom_data.setBit<P9A_MI_MCFGPR0_MMIO_VALID>(); //Enable MMIO
            l_scom_data.insert<P9A_MI_MCFGPR0_CONFIGURATION_GROUP_BASE_ADDRESS,
                               P9A_MI_MCFGPR0_CONFIGURATION_GROUP_BASE_ADDRESS_LEN>(l_cfg_bar);
            l_scom_data.insert<P9A_MI_MCFGPR0_MMIO_GROUP_BASE_ADDRESS,
                               P9A_MI_MCFGPR0_MMIO_GROUP_BASE_ADDRESS_LEN>(l_mmio_bar);

            // get MI target to configure MCFGPR
            fapi2::Target<fapi2::TARGET_TYPE_MI> l_mi =
                l_mcc.getParent<fapi2::TARGET_TYPE_MI>();
            // retrieve DMI pos
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS,
                                   l_mcc,
                                   l_mcc_pos),
                     "Error from FAPI_ATTR_GET (ATTR_CHIP_UNIT_POS)");

            // configure inband channel 0 MCFGPR0
            if(l_mcc_pos % 2 == 0)
            {
                FAPI_TRY(putScom(l_mi, P9A_MI_MCFGPR0, l_scom_data));
            }
            // configure inband channel 1 MCFGPR1
            else
            {
                FAPI_TRY(putScom(l_mi, P9A_MI_MCFGPR1, l_scom_data));
            }
        }
    }

fapi_try_exit:
    FAPI_DBG("End");
    return fapi2::current_err;
}
Пример #23
0
///
/// @brief Determine PHY TX lane inversions required to lock DL RX lanes
///
/// @param[in] i_target Reference to processor chip target
/// @param[in] i_loc_target Local endpoint target
/// @param[in] i_rem_target Remote endpoint target
/// @param[in] i_ctl Reference to link control structure
/// @param[in] i_even True=process even half-link, False=process odd half-link
///
/// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code.
///
fapi2::ReturnCode
p9_smp_link_layer_lock_lanes(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
    const fapi2::Target<fapi2::TARGET_TYPE_OBUS>& i_loc_target,
    const fapi2::Target<fapi2::TARGET_TYPE_OBUS>& i_rem_target,
    const p9_fbc_link_ctl_t& i_ctl,
    const bool i_even)
{
    FAPI_DBG("Start");

    bool l_all_locked = 0;
    fapi2::buffer<uint64_t> l_dl_rx_control;
    uint64_t l_dl_rx_control_addr = i_ctl.dl_control_addr +
                                    ((i_even) ?
                                     (OFFSET_FROM_DL_CONTROL_TO_RX_EVEN_LANE_CONTROL) :
                                     (OFFSET_FROM_DL_CONTROL_TO_RX_ODD_LANE_CONTROL));


    // loop a maximum of two times to determine lane lock status
    // 1st check is prior to application of any PHY TX inversions
    // if any lanes do not lock, apply inversions and check again
    // assert if any lane is unlocked at this point
    for (uint8_t l_phase = 0; (l_phase < 2) && !l_all_locked; l_phase++)
    {
        uint8_t l_stable_reads = 1;
        fapi2::buffer<uint64_t> l_dl_rx_control_stable = 0;

        FAPI_DBG("Polling for stable lane lock field (phase=%d)", l_phase);

        // poll for stable pattern
        for (uint8_t l_poll = 0; l_poll < MAX_LOCK_INDICATOR_POLLS; l_poll++)
        {
            FAPI_TRY(fapi2::delay(100000000, 1000000),
                     "Error from delay (even, poll = %d)", l_poll + 1);

            FAPI_TRY(fapi2::getScom(i_target,
                                    l_dl_rx_control_addr,
                                    l_dl_rx_control),
                     "Error from getScom (0x%08X)", l_dl_rx_control_addr);

            if ((l_dl_rx_control() & DL_RX_CONTROL_LANE_LOCK_MASK) != l_dl_rx_control_stable())
            {
                l_dl_rx_control_stable = (l_dl_rx_control() & DL_RX_CONTROL_LANE_LOCK_MASK);
                l_stable_reads = 1;
            }
            else
            {
                l_stable_reads++;

                if (l_stable_reads == MIN_LOCK_INDICATOR_STABLE_POLLS)
                {
                    break;
                }
            }
        }

        FAPI_ASSERT(l_stable_reads == MIN_LOCK_INDICATOR_STABLE_POLLS,
                    fapi2::P9_SMP_LINK_LAYER_RX_CONTROL_STABILITY_ERR()
                    .set_TARGET(i_loc_target)
                    .set_DL_RX_CONTROL_ADDR(l_dl_rx_control_addr)
                    .set_DL_RX_CONTROL(l_dl_rx_control())
                    .set_PHASE(l_phase),
                    "DL RX Control register per-lane lock value did not stabilize prior to timeout (phase=%d)!",
                    l_phase);

        l_all_locked = ((l_dl_rx_control() & DL_RX_CONTROL_LANE_LOCK_MASK) == DL_RX_CONTROL_ALL_LANES_LOCKED);

        // apply PHY TX inversions only if needed
        if (!l_phase && !l_all_locked)
        {
            for (uint8_t l_lane = 0; l_lane < LANES_PER_HALF_LINK; l_lane++)
            {
                // set PHY TX lane address, start at:
                // - PHY lane 0 for even (work up)
                // - PHY lane 23 for odd (work down) DD1.0
                uint64_t l_phy_tx_mode1_pl_addr = OBUS_TX0_TXPACKS0_SLICE0_TX_MODE1_PL;

                if (i_even)
                {
                    l_phy_tx_mode1_pl_addr |= ((uint64_t) l_lane << 32);
                }
                else
                {
                    l_phy_tx_mode1_pl_addr |= ((uint64_t) (23 - l_lane) << 32);
                }

                // read DL RX per-lane lock indicator bit
                // if locked: do nothing
                // if not locked: apply lane-invert to associated PHY TX side
                if (!l_dl_rx_control.getBit(OBUS_LL0_IOOL_LINK0_RX_LANE_CONTROL_LOCKED + l_lane))
                {
                    FAPI_DBG("Inverting lane %d", l_lane);
                    fapi2::buffer<uint64_t> l_phy_tx_mode1_pl;
                    FAPI_TRY(fapi2::getScom(i_rem_target,
                                            l_phy_tx_mode1_pl_addr,
                                            l_phy_tx_mode1_pl),
                             "Error from getScom (0x%08X)", l_phy_tx_mode1_pl_addr);

                    l_phy_tx_mode1_pl.setBit<OBUS_TX0_TXPACKS0_SLICE0_TX_MODE1_PL_LANE_INVERT>();

                    FAPI_TRY(fapi2::putScom(i_rem_target,
                                            l_phy_tx_mode1_pl_addr,
                                            l_phy_tx_mode1_pl),
                             "Error from putScom (0x%08X)", l_phy_tx_mode1_pl_addr);
                }
            }
        }
    }

    FAPI_ASSERT(l_all_locked,
                fapi2::P9_SMP_LINK_LAYER_RX_CONTROL_NOT_LOCKED_ERR()
                .set_TARGET(i_loc_target)
                .set_DL_RX_CONTROL_ADDR(l_dl_rx_control_addr)
                .set_DL_RX_CONTROL(l_dl_rx_control()),
                "DL RX Control register reports some lanes did not lock!");

fapi_try_exit:
    FAPI_DBG("End");
    return fapi2::current_err;
}
Пример #24
0
///
/// @brief mss_volt_vddr_offset procedure. Determines operating vddr voltage for dimms behind a vddr voltage domain
/// @param[in] i_targets  Reference to vector of Centaur Targets in a particular vddr power domain
/// @return ReturnCode
///
    fapi2::ReturnCode p9c_mss_volt_vddr_offset(const std::vector<fapi2::Target<fapi2::TARGET_TYPE_MEMBUF_CHIP>>& i_targets)
    {
        // If we're passed an empty vector, exit out
        if(i_targets.empty())
        {
            FAPI_INF("Empty vector of targets passed to VDDR offset. Exiting..");
            return fapi2::FAPI2_RC_SUCCESS;
        }

        // Constexpr's to pretty up some of the code
        constexpr double PERCENT = 100;
        constexpr uint64_t ATTR_VOLT_CONVERSION = 10000;
        // Note: per the power/thermal team, 5625 is the utilization for the max DMI speed at 1600 memory frequency
        // Please note, if dynamic VID is needed on all P9 centaur systems, then this value will become an MRW attribute
        // Currently, dynamic voltage is only needed on custom DIMM systems, if it is needed on ISDIMM systems, then the data bus utilization code will need to change:
        // ISDIMM systems could hypothetically have DIMM's on only one given MBA. In that case the data bus utilization will increase. We should then just look into using the attribute.
        constexpr uint64_t DATA_BUS_UTIL = 5625;

        // Declares variables
        fapi2::ReturnCode l_bad_vpd_rc = fapi2::FAPI2_RC_SUCCESS;
        uint32_t l_vpd_master_power_slope = 0;
        uint32_t l_vpd_master_power_intercept = 0;
        uint32_t l_volt_util_active = 0;
        uint32_t l_volt_util_inactive = 0;
        uint32_t l_volt_slope = 0;
        uint32_t l_volt_intercept = 0;
        uint32_t l_good_master_power_slope = 0;
        uint32_t l_good_master_power_intercept = 0;
        uint32_t l_num_dimms_to_add = 0;
        uint32_t l_var_power_on_vddr = 0;
        uint32_t l_num_logical_dimms = 0;
        uint8_t l_dram_gen = 0;
        uint8_t l_enable = 0;
        uint8_t l_is_functional = 0;
        uint8_t l_ec_disable_attr = 0;
        uint8_t l_percent_uplift = 0;
        uint8_t l_percent_uplift_idle = 0;
        uint32_t l_vddr_max_limit_mv = 0;
        uint32_t l_param_vddr_voltage_mv = 0;
        uint32_t l_data_bus_util = 0;

        // Gets and checks the DRAM generation and centaur configuration
        // Note: Plug rules checks haven't been done up to this point
        // The below checks that all DRAM have the same generation on this VDDR rail and returns the valid DRAM generation
        FAPI_TRY(check_dram_gen_plug(i_targets, l_dram_gen));

        // Voltage should not be updated if the disable is set
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_VDDR_OFFSET_ENABLE, fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), l_enable));

        // Attribute is disabled, just exit
        if(l_enable == fapi2::ENUM_ATTR_MSS_MRW_VDDR_OFFSET_ENABLE_DISABLE)
        {
            FAPI_INF("ATTR_MSS_MRW_VDDR_OFFSET_ENABLE is set to be disabled. Exiting....., %d", l_enable);
            return fapi2::FAPI2_RC_SUCCESS;
        }

        // Checks if any MC's have the disable attribute set, if so, set to MSS_VOLT value
        // If not, continue with the code
        for(const auto& l_chip : i_targets)
        {
            //reads in the attribute
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_CENTAUR_EC_FEATURE_DISABLE_VDDR_DYNAMIC_VID, l_chip, l_ec_disable_attr));

            // Disable is set, read mss_volt and exit out of the code
            if(l_ec_disable_attr)
            {
                break;
            }
        }

        // Disable is set, sets the l_enable attribute based upon MSS_VOLT attribute
        if(l_ec_disable_attr)
        {
            FAPI_INF("Found Centaur with EC disable attribute set. Setting ATTR_CEN_MSS_VDDR_OFFSET based upon ATTR_CEN_MSS_VOLT");

            //sets the output attributes
            for(const auto& l_chip : i_targets)
            {
                FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_VOLT, l_chip, l_param_vddr_voltage_mv));
                FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_VDDR_OFFSET, l_chip, l_param_vddr_voltage_mv));
            }//end for

            return  fapi2::FAPI2_RC_SUCCESS;
        }

        // Gets the attributes and computes var_power_on based upon whether the DRAM type is DDR3 or DDR4
        if(l_dram_gen == fapi2::ENUM_ATTR_CEN_SPD_DRAM_DEVICE_TYPE_DDR3)
        {
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_DDR3_VDDR_SLOPE, i_targets[0], l_volt_slope));
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_DDR3_VDDR_INTERCEPT, i_targets[0], l_volt_intercept));
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MRW_DDR3_VDDR_MAX_LIMIT, i_targets[0], l_vddr_max_limit_mv));
        }
        // DDR4
        else
        {
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_DDR4_VDDR_SLOPE, i_targets[0], l_volt_slope));
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MSS_DDR4_VDDR_INTERCEPT, i_targets[0], l_volt_intercept));
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_MRW_DDR4_VDDR_MAX_LIMIT, i_targets[0], l_vddr_max_limit_mv));
        }

        // Gets the data bus utilization and picks the lower of the two values
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_MAX_DRAM_DATABUS_UTIL,
                               fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(),
                               l_data_bus_util));
        l_data_bus_util = l_data_bus_util < DATA_BUS_UTIL ? l_data_bus_util : DATA_BUS_UTIL;

        // Computes the active and inactive attribute values
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_DIMM_POWER_CURVE_PERCENT_UPLIFT,
                               fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(),
                               l_percent_uplift));
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_MSS_MRW_DIMM_POWER_CURVE_PERCENT_UPLIFT_IDLE,
                               fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(),
                               l_percent_uplift_idle));


        l_volt_util_active = l_data_bus_util;
        l_volt_util_inactive = 0;

        // Checks to make sure that none of the values that were read were set to zeros
        FAPI_ASSERT((l_volt_util_active != 0) &&
                    (l_volt_slope != 0) &&
                    (l_volt_intercept != 0) &&
                    (l_vddr_max_limit_mv != 0),
                    fapi2::CEN_MSS_VOLT_VDDR_OFFSET_VALUE_ERROR()
                    .set_CEN_TARGET(i_targets[0])
                    .set_VDDR_UTIL_ACTIVE(l_volt_util_active)
                    .set_VDDR_SLOPE(l_volt_slope)
                    .set_VDDR_INTERCEPT(l_volt_intercept)
                    .set_VDDR_MAX_LIMIT(l_vddr_max_limit_mv),
                    "%s One or more dynamic VDD attributes is 0 slope_util_active %lu slope %lu slope_intercept %lu!  Exiting....",
                    mss::c_str(i_targets[0]), l_volt_util_active, l_volt_slope, l_volt_intercept);

        // Print to check the calculation
        FAPI_INF("l_data_bus_util %d per 10k l_volt_util_active: %d per 10k l_volt_util_inactive: %d per 10k",
                 l_data_bus_util, l_volt_util_active, l_volt_util_inactive);


        l_num_dimms_to_add = 1;

        // Computes the preliminary VDDR value
        for(const auto& l_chip : i_targets)
        {
            // Gets the functional attribute to check for an active centaur
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_FUNCTIONAL, l_chip, l_is_functional));

            // Gets the power slope values and does error checks if this card is functional, as it should have good VPD.  if the card is non-functional, continue using good VPD power slope values
            auto l_rc = FAPI_ATTR_GET(fapi2::ATTR_CEN_CDIMM_VPD_MASTER_POWER_SLOPE, l_chip, l_vpd_master_power_slope);

            if(l_is_functional == fapi2::ENUM_ATTR_FUNCTIONAL_FUNCTIONAL)
            {
                FAPI_TRY(l_rc);
            }

            l_rc = FAPI_ATTR_GET(fapi2::ATTR_CEN_CDIMM_VPD_MASTER_POWER_INTERCEPT, l_chip, l_vpd_master_power_intercept);

            if(l_is_functional == fapi2::ENUM_ATTR_FUNCTIONAL_FUNCTIONAL)
            {
                FAPI_TRY(l_rc);
            }

            // Removes leading bits from the VPD MASTER POWER attributes, leaving only the values needed for the power calculations
            l_vpd_master_power_slope &= 0x1FFF;
            l_vpd_master_power_intercept &= 0x1FFF;

            // Checks to make sure that the attribute values are non-zero - calls out all bad DIMMs
            if(((l_vpd_master_power_slope * l_vpd_master_power_intercept) == 0)
               && (l_is_functional == fapi2::ENUM_ATTR_FUNCTIONAL_FUNCTIONAL))
            {
                FAPI_ASSERT((l_volt_util_active != 0) &&
                            (l_volt_slope != 0) &&
                            (l_volt_intercept != 0),
                            fapi2::CEN_MSS_VOLT_VDDR_OFFSET_VPD_VALUE_ERROR()
                            .set_CEN_TARGET(i_targets[0])
                            .set_VPD_MASTER_POWER_SLOPE(l_vpd_master_power_slope)
                            .set_VPD_MASTER_POWER_INTERCEPT(l_vpd_master_power_intercept),
                            "%s One or more VPD Power slope attributes is 0.  Logging error and looking for additional bad DIMMs. power_slope  %lu power_intercept %lu!  Exiting....",
                            mss::c_str(i_targets[0]), l_vpd_master_power_slope, l_vpd_master_power_intercept);

                // Using a generic error here as we already logged the other error above
                l_bad_vpd_rc = fapi2::FAPI2_RC_INVALID_PARAMETER;
                continue;
            }
            // One or more DIMM has already been called out, skip doing the calculation and continue to try to find bad DIMMs
            else if(l_bad_vpd_rc)
            {
                FAPI_INF("Already found a bad DIMM.  Skipping calculations on this DIMM.");
                continue;
            }
            // Has not found good master_power_slopes and has bad master power slopes
            else if(((l_good_master_power_slope == 0) || (l_good_master_power_intercept == 0)) &&
                    ((l_vpd_master_power_slope == 0) || (l_vpd_master_power_intercept == 0)))
            {
                l_num_dimms_to_add++;
                FAPI_INF("Found bad l_vpd_master_power_slope or l_vpd_master_power_intercept values on non-functional DIMM. Program has not found good values yet, adding one more DIMM to run when good values are found. Currently going to run %d DIMMs in the next dimm.",
                         l_num_dimms_to_add);
                continue;
            }
            // Found bad master power slope or power intercept but has good master power slope or intercepts
            else if(((l_vpd_master_power_slope == 0) || (l_vpd_master_power_intercept == 0)) &&
                    ((l_good_master_power_slope > 0) && (l_good_master_power_intercept > 0)))
            {
                // Uses assumed (last good master power slope and intercept) values for these calculations
                FAPI_INF("Found bad l_vpd_master_power_slope or l_vpd_master_power_intercept values on non-functional DIMM. Program is using the last good values for the calculations for this DIMM.");
                l_vpd_master_power_slope = l_good_master_power_slope;
                l_vpd_master_power_intercept = l_good_master_power_intercept;
            }
            // Found good master power slopes -> set the good master power slope values
            else if((l_vpd_master_power_slope > 0) && (l_vpd_master_power_intercept > 0 ))
            {
                l_good_master_power_slope = l_vpd_master_power_slope;
                l_good_master_power_intercept = l_vpd_master_power_intercept;
            }

            // Loops through all MBA chiplets to compare the compute the total number of logical dimms associated with a centaur
            l_num_logical_dimms = 0;

            for(const auto& l_mba : mss::find_targets<fapi2::TARGET_TYPE_MBA>(l_chip))
            {
                l_num_logical_dimms += mss::count_dimm(l_mba);
            }//end for

            // Multiply by total number of active logical dimms
            {
                // Temporary variables to compress the functions below
                const bool l_functional = l_is_functional == fapi2::ENUM_ATTR_FUNCTIONAL_FUNCTIONAL;
                const auto l_volt_util = l_functional ? l_volt_util_active : l_volt_util_inactive;

                // Calculates the uplift percentage
                const auto UPLIFT = (PERCENT + l_percent_uplift) / PERCENT;
                // Note: static cast makes the entire calcuation a floating point calculation, which is what we want
                // Calculates the power usage per active DIMM
                const auto POWER_CURVE = (static_cast<double>(l_vpd_master_power_slope) * l_volt_util / ATTR_VOLT_CONVERSION) +
                                         l_vpd_master_power_intercept;

                // Calculates the power on VDDR
                l_var_power_on_vddr += static_cast<uint32_t>(l_num_dimms_to_add * POWER_CURVE * l_num_logical_dimms * UPLIFT);
                FAPI_INF("%s l_var_power_on_vddr: %d cW l_vpd_master_power_slope: %d cW l_volt_util_%sactive: %d per 10k l_vpd_master_power_intercept %d cW l_num_logical_dimms %d l_percent_uplift %d %%",
                         mss::c_str(l_chip), l_var_power_on_vddr, l_vpd_master_power_slope, l_functional ? "" : "in",
                         l_volt_util_active, l_vpd_master_power_intercept, l_num_logical_dimms, l_percent_uplift);
            }

            // Resets the number of DIMMs to add.
            l_num_dimms_to_add = 1;
        }//end for

        // Found a bad DIMM, exit
        FAPI_TRY(l_bad_vpd_rc, "Found one or more functional DIMM with bad VPD. Exiting....");

        // Debug print
        FAPI_INF("l_var_power_on_vddr: %d cW l_volt_slope: %d uV/W l_volt_intercept: %d mV",
                 l_var_power_on_vddr, l_volt_slope, l_volt_intercept);

        // Computes and converts the voltage offset into mV
        // Naked numbers are for this calculation and are a one to one port from the p8 code base
        l_param_vddr_voltage_mv = (500 + l_var_power_on_vddr * l_volt_slope / 100) / 1000 + l_volt_intercept;
        FAPI_INF("l_param_vddr_voltage_mv: %d mV", l_param_vddr_voltage_mv);

        // Found that the VDDR voltage is over the maximum limit
        if(l_param_vddr_voltage_mv > l_vddr_max_limit_mv)
        {
            FAPI_INF("l_param_vddr_voltage_mv, %d mV, is over l_vddr_max_limit_mv of %d mV.", l_param_vddr_voltage_mv,
                     l_vddr_max_limit_mv);
            FAPI_INF("Setting l_param_vddr_voltage_mv to l_vddr_max_limit_mv");
            l_param_vddr_voltage_mv = l_vddr_max_limit_mv;
        }

        // Prints out the final attribute value
        FAPI_INF("ATTR_CEN_MSS_VDDR_OFFSET: %d mV", l_param_vddr_voltage_mv);

        // Sets the output attributes
        for(const auto& l_chip : i_targets)
        {
            FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_MSS_VDDR_OFFSET, l_chip, l_param_vddr_voltage_mv));
        }//end for

    fapi_try_exit:
        return fapi2::current_err;
    }
    ///
    /// @brief mss_eff_config_rank_group determines proper rank groupings
    /// @param[in] i_target_mba
    /// @return ReturnCode
    ///
    fapi2::ReturnCode mss_eff_config_rank_group(const fapi2::Target<fapi2::TARGET_TYPE_MBA> i_target_mba)
    {
        const char* const PROCEDURE_NAME = "mss_eff_config_rank_group";
        FAPI_INF("*** Running %s on %s ... ***", PROCEDURE_NAME, mss::c_str(i_target_mba));

        uint8_t num_ranks_per_dimm_u8array[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0};
        uint8_t l_num_master_ranks[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0};
        uint8_t dram_gen_u8 = 0;
        uint8_t dimm_type_u8 = 0;
        uint8_t l_stack_type[MAX_PORTS_PER_MBA][MAX_DIMM_PER_PORT] = {0};
        uint8_t primary_rank_group0_u8array[MAX_PORTS_PER_MBA] = {0};
        uint8_t primary_rank_group1_u8array[MAX_PORTS_PER_MBA] = {0};
        uint8_t primary_rank_group2_u8array[MAX_PORTS_PER_MBA] = {0};
        uint8_t primary_rank_group3_u8array[MAX_PORTS_PER_MBA] = {0};
        uint8_t secondary_rank_group0_u8array[MAX_PORTS_PER_MBA] = {0};
        uint8_t secondary_rank_group1_u8array[MAX_PORTS_PER_MBA] = {0};
        uint8_t secondary_rank_group2_u8array[MAX_PORTS_PER_MBA] = {0};
        uint8_t secondary_rank_group3_u8array[MAX_PORTS_PER_MBA] = {0};
        uint8_t tertiary_rank_group0_u8array[MAX_PORTS_PER_MBA] = {0};
        uint8_t tertiary_rank_group1_u8array[MAX_PORTS_PER_MBA] = {0};
        uint8_t tertiary_rank_group2_u8array[MAX_PORTS_PER_MBA] = {0};
        uint8_t tertiary_rank_group3_u8array[MAX_PORTS_PER_MBA] = {0};
        uint8_t quanternary_rank_group0_u8array[MAX_PORTS_PER_MBA] = {0};
        uint8_t quanternary_rank_group1_u8array[MAX_PORTS_PER_MBA] = {0};
        uint8_t quanternary_rank_group2_u8array[MAX_PORTS_PER_MBA] = {0};
        uint8_t quanternary_rank_group3_u8array[MAX_PORTS_PER_MBA] = {0};

        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_NUM_RANKS_PER_DIMM, i_target_mba,  num_ranks_per_dimm_u8array));
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DRAM_GEN, i_target_mba,  dram_gen_u8));
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_DIMM_TYPE, i_target_mba,  dimm_type_u8));
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_NUM_MASTER_RANKS_PER_DIMM, i_target_mba,  l_num_master_ranks));
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_EFF_STACK_TYPE, i_target_mba,  l_stack_type));

        for (uint8_t cur_port = 0; cur_port < MAX_PORTS_PER_MBA; cur_port += 1)
        {
            if ((num_ranks_per_dimm_u8array[cur_port][0] > 0) && (num_ranks_per_dimm_u8array[cur_port][1] == 0))    //Single Drop
            {
                primary_rank_group0_u8array[cur_port] = 0;

                if (num_ranks_per_dimm_u8array[cur_port][0] > 1)
                {
                    primary_rank_group1_u8array[cur_port] = 1;
                }
                else
                {
                    primary_rank_group1_u8array[cur_port] = INVALID;
                }

                if (num_ranks_per_dimm_u8array[cur_port][0] > 2)
                {
                    primary_rank_group2_u8array[cur_port] = 2;
                    primary_rank_group3_u8array[cur_port] = 3;
                }
                else
                {
                    primary_rank_group2_u8array[cur_port] = INVALID;
                    primary_rank_group3_u8array[cur_port] = INVALID;
                }

                secondary_rank_group0_u8array[cur_port] = INVALID;
                secondary_rank_group1_u8array[cur_port] = INVALID;
                secondary_rank_group2_u8array[cur_port] = INVALID;
                secondary_rank_group3_u8array[cur_port] = INVALID;

                //Preet Add 3TSV /2H  Type - Single Drop Case
                //ATTR_EFF_STACK_TYPE <enum>NONE = 0, DDP_QDP = 1, STACK_3DS = 2</enum>

                if((l_num_master_ranks[cur_port][0] != 0) && (dram_gen_u8 == 2) && (l_stack_type[cur_port][0] == 2))
                {
                    if(num_ranks_per_dimm_u8array[cur_port][0] == 2)
                    {
                        primary_rank_group0_u8array[cur_port] = 0;
                        primary_rank_group1_u8array[cur_port] = INVALID;
                        primary_rank_group2_u8array[cur_port] = INVALID;
                        primary_rank_group3_u8array[cur_port] = INVALID;
                        secondary_rank_group0_u8array[cur_port] = 1;
                        secondary_rank_group1_u8array[cur_port] = INVALID;
                        secondary_rank_group2_u8array[cur_port] = INVALID;
                        secondary_rank_group3_u8array[cur_port] = INVALID;
                    }

                    //if 4H
                    else if(num_ranks_per_dimm_u8array[cur_port][0] == 4)
                    {
                        primary_rank_group0_u8array[cur_port] = 0;
                        primary_rank_group1_u8array[cur_port] = INVALID;
                        primary_rank_group2_u8array[cur_port] = INVALID;
                        primary_rank_group3_u8array[cur_port] = INVALID;
                        secondary_rank_group0_u8array[cur_port] = 1;
                        secondary_rank_group1_u8array[cur_port] = INVALID;
                        secondary_rank_group2_u8array[cur_port] = INVALID;
                        secondary_rank_group3_u8array[cur_port] = INVALID;
                        tertiary_rank_group0_u8array[cur_port] = 2;
                        tertiary_rank_group1_u8array[cur_port] = INVALID;
                        tertiary_rank_group2_u8array[cur_port] = INVALID;
                        tertiary_rank_group3_u8array[cur_port] = INVALID;
                        quanternary_rank_group0_u8array[cur_port] = 3;
                        quanternary_rank_group1_u8array[cur_port] = INVALID;
                        quanternary_rank_group2_u8array[cur_port] = INVALID;
                        quanternary_rank_group3_u8array[cur_port] = INVALID;
                    }

                    //if 8H   <Add Later if Required>
                } //end of if 3DS Stack
            }
            else if ((num_ranks_per_dimm_u8array[cur_port][0] > 0) && (num_ranks_per_dimm_u8array[cur_port][1] > 0)) //Dual Drop
            {
                if (num_ranks_per_dimm_u8array[cur_port][0] != num_ranks_per_dimm_u8array[cur_port][1])
                {
                    FAPI_ASSERT(false,
                                fapi2::CEN_MSS_EFF_CONFIG_RANK_GROUP_NON_MATCH_RANKS().
                                set_TARGET_MBA(i_target_mba),
                                "Plug rule violation, num_ranks_per_dimm=%d[0],%d[1] on %s PORT%d!", num_ranks_per_dimm_u8array[cur_port][0],
                                num_ranks_per_dimm_u8array[cur_port][1], mss::c_str(i_target_mba), cur_port);
                }

                primary_rank_group0_u8array[cur_port] = 0;
                primary_rank_group1_u8array[cur_port] = 4;
                primary_rank_group2_u8array[cur_port] = INVALID;
                primary_rank_group3_u8array[cur_port] = INVALID;
                secondary_rank_group0_u8array[cur_port] = INVALID;
                secondary_rank_group1_u8array[cur_port] = INVALID;
                secondary_rank_group2_u8array[cur_port] = INVALID;
                secondary_rank_group3_u8array[cur_port] = INVALID;

                if (num_ranks_per_dimm_u8array[cur_port][0] == 2)
                {
                    primary_rank_group2_u8array[cur_port] = 1;
                    primary_rank_group3_u8array[cur_port] = 5;
                }
                else if (num_ranks_per_dimm_u8array[cur_port][0] == 4)
                {
                    primary_rank_group2_u8array[cur_port] = 2;
                    primary_rank_group3_u8array[cur_port] = 6;
                    secondary_rank_group0_u8array[cur_port] = 1;
                    secondary_rank_group1_u8array[cur_port] = 5;
                    secondary_rank_group2_u8array[cur_port] = 3;
                    secondary_rank_group3_u8array[cur_port] = 7;
                }
                else if (num_ranks_per_dimm_u8array[cur_port][0] != 1)
                {
                    FAPI_ASSERT(false,
                                fapi2::CEN_MSS_EFF_CONFIG_RANK_GROUP_NUM_RANKS_NEQ1().
                                set_TARGET_MBA(i_target_mba),
                                "Plug rule violation, num_ranks_per_dimm=%d[0],%d[1] on %s PORT%d!", num_ranks_per_dimm_u8array[cur_port][0],
                                num_ranks_per_dimm_u8array[cur_port][1], mss::c_str(i_target_mba), cur_port);

                }

                //Preet Add 3TSV
                if((l_num_master_ranks[cur_port][0] != 0) && (dram_gen_u8 == 2) && (l_stack_type[cur_port][0] == 2))
                {
                    //2H Type - Dual Drop Case
                    if(num_ranks_per_dimm_u8array[cur_port][0] == 2)
                    {
                        primary_rank_group0_u8array[cur_port] = 0;
                        primary_rank_group1_u8array[cur_port] = 4;
                        primary_rank_group2_u8array[cur_port] = INVALID;
                        primary_rank_group3_u8array[cur_port] = INVALID;
                        secondary_rank_group0_u8array[cur_port] = INVALID;
                        secondary_rank_group1_u8array[cur_port] = INVALID;
                        secondary_rank_group2_u8array[cur_port] = INVALID;
                        secondary_rank_group3_u8array[cur_port] = INVALID;
                    }
                    //if 4H
                    else if(num_ranks_per_dimm_u8array[cur_port][0] == 4)
                    {
                        primary_rank_group0_u8array[cur_port] = 0;
                        primary_rank_group1_u8array[cur_port] = 4;
                        primary_rank_group2_u8array[cur_port] = INVALID;
                        primary_rank_group3_u8array[cur_port] = INVALID;
                        secondary_rank_group0_u8array[cur_port] = INVALID;
                        secondary_rank_group1_u8array[cur_port] = INVALID;
                        secondary_rank_group2_u8array[cur_port] = INVALID;
                        secondary_rank_group3_u8array[cur_port] = INVALID;
                        tertiary_rank_group0_u8array[cur_port] = INVALID;
                        tertiary_rank_group1_u8array[cur_port] = INVALID;
                        tertiary_rank_group2_u8array[cur_port] = INVALID;
                        tertiary_rank_group3_u8array[cur_port] = INVALID;
                        quanternary_rank_group0_u8array[cur_port] = INVALID;
                        quanternary_rank_group1_u8array[cur_port] = INVALID;
                        quanternary_rank_group2_u8array[cur_port] = INVALID;
                        quanternary_rank_group3_u8array[cur_port] = INVALID;
                    }

                    //if 8H   <Add Later if Required>
                } //end of if 3DS Stack
            }
            else if ((num_ranks_per_dimm_u8array[cur_port][0] == 0) && (num_ranks_per_dimm_u8array[cur_port][1] == 0))
            {
                primary_rank_group0_u8array[cur_port] = INVALID;
                primary_rank_group1_u8array[cur_port] = INVALID;
                primary_rank_group2_u8array[cur_port] = INVALID;
                primary_rank_group3_u8array[cur_port] = INVALID;
                secondary_rank_group0_u8array[cur_port] = INVALID;
                secondary_rank_group1_u8array[cur_port] = INVALID;
                secondary_rank_group2_u8array[cur_port] = INVALID;
                secondary_rank_group3_u8array[cur_port] = INVALID;
            }
            else
            {
                FAPI_ASSERT(false,
                            fapi2::CEN_MSS_EFF_CONFIG_RANK_GROUP_NO_MATCH().
                            set_TARGET_MBA(i_target_mba),
                            "Plug rule violation, num_ranks_per_dimm=%d[0],%d[1] on %s PORT%d!", num_ranks_per_dimm_u8array[cur_port][0],
                            num_ranks_per_dimm_u8array[cur_port][1], mss::c_str(i_target_mba), cur_port);

            }

            tertiary_rank_group0_u8array[cur_port] = INVALID;
            tertiary_rank_group1_u8array[cur_port] = INVALID;
            tertiary_rank_group2_u8array[cur_port] = INVALID;
            tertiary_rank_group3_u8array[cur_port] = INVALID;
            quanternary_rank_group0_u8array[cur_port] = INVALID;
            quanternary_rank_group1_u8array[cur_port] = INVALID;
            quanternary_rank_group2_u8array[cur_port] = INVALID;
            quanternary_rank_group3_u8array[cur_port] = INVALID;

            FAPI_INF("P[%02d][%02d][%02d][%02d],S[%02d][%02d][%02d][%02d],T[%02d][%02d][%02d][%02d],Q[%02d][%02d][%02d][%02d] on %s PORT%d.",
                     primary_rank_group0_u8array[cur_port], primary_rank_group1_u8array[cur_port], primary_rank_group2_u8array[cur_port],
                     primary_rank_group3_u8array[cur_port], secondary_rank_group0_u8array[cur_port], secondary_rank_group1_u8array[cur_port],
                     secondary_rank_group2_u8array[cur_port], secondary_rank_group3_u8array[cur_port],
                     tertiary_rank_group0_u8array[cur_port], tertiary_rank_group1_u8array[cur_port], tertiary_rank_group2_u8array[cur_port],
                     tertiary_rank_group3_u8array[cur_port], quanternary_rank_group0_u8array[cur_port],
                     quanternary_rank_group1_u8array[cur_port], quanternary_rank_group2_u8array[cur_port],
                     quanternary_rank_group3_u8array[cur_port], mss::c_str(i_target_mba), cur_port);
        } // For port

        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_EFF_PRIMARY_RANK_GROUP0, i_target_mba, primary_rank_group0_u8array));
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_EFF_PRIMARY_RANK_GROUP1, i_target_mba, primary_rank_group1_u8array));
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_EFF_PRIMARY_RANK_GROUP2, i_target_mba, primary_rank_group2_u8array));
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_EFF_PRIMARY_RANK_GROUP3, i_target_mba, primary_rank_group3_u8array));
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_EFF_SECONDARY_RANK_GROUP0, i_target_mba, secondary_rank_group0_u8array));
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_EFF_SECONDARY_RANK_GROUP1, i_target_mba, secondary_rank_group1_u8array));
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_EFF_SECONDARY_RANK_GROUP2, i_target_mba, secondary_rank_group2_u8array));
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_EFF_SECONDARY_RANK_GROUP3, i_target_mba, secondary_rank_group3_u8array));
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_EFF_TERTIARY_RANK_GROUP0, i_target_mba, tertiary_rank_group0_u8array));
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_EFF_TERTIARY_RANK_GROUP1, i_target_mba, tertiary_rank_group1_u8array));
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_EFF_TERTIARY_RANK_GROUP2, i_target_mba, tertiary_rank_group2_u8array));
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_EFF_TERTIARY_RANK_GROUP3, i_target_mba, tertiary_rank_group3_u8array));
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_EFF_QUATERNARY_RANK_GROUP0, i_target_mba, quanternary_rank_group0_u8array));
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_EFF_QUATERNARY_RANK_GROUP1, i_target_mba, quanternary_rank_group1_u8array));
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_EFF_QUATERNARY_RANK_GROUP2, i_target_mba, quanternary_rank_group2_u8array));
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_CEN_EFF_QUATERNARY_RANK_GROUP3, i_target_mba, quanternary_rank_group3_u8array));

        FAPI_INF("%s on %s COMPLETE", PROCEDURE_NAME, mss::c_str(i_target_mba));
    fapi_try_exit:
        return fapi2::current_err;
    } //rank group
Пример #26
0
    ///
    /// @brief Enable function for pmic module. Calls appropriate enable func with matching DIMM target
    /// @param[in] i_target ocmb target
    /// @param[in] i_mode enable mode operation
    /// @return FAPI2_RC_SUCCESS iff ok
    ///
    fapi2::ReturnCode pmic_enable(const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_ocmb_target,
                                  const mss::pmic::enable_mode i_mode)
    {
        auto l_dimms = mss::find_targets<fapi2::TARGET_TYPE_DIMM>(i_ocmb_target);
        auto l_pmics = mss::find_targets<fapi2::TARGET_TYPE_PMIC>(i_ocmb_target);

        // Sort by index (low to high) since find_targets may not return the correct order
        std::sort(l_dimms.begin(), l_dimms.end(),
                  [] (const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& l_first_dimm,
                      const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& l_second_dimm) -> bool
        {
            return mss::index(l_first_dimm) < mss::index(l_second_dimm);
        });

        std::sort(l_pmics.begin(), l_pmics.end(),
                  [] (const fapi2::Target<fapi2::TARGET_TYPE_PMIC>& l_first_pmic,
                      const fapi2::Target<fapi2::TARGET_TYPE_PMIC>& l_second_pmic) -> bool
        {
            return mss::index(l_first_pmic) < mss::index(l_second_pmic);
        });

        // Start at PMIC0. If there was ever a weird case where there is a 4U dimm
        // on the same OCMB as a 2U dimm (is this possible?),
        // we would have 6 total PMICs. So, we need to keep
        // track of where we left off for the last pmic we enabled
        uint8_t l_pmic_index = 0;

        // Not asserting vectors non-empty because there could be OCMBs without DIMMs on them
        for (const auto& l_dimm : l_dimms)
        {
            // Get module height for DIMM to determine the number of PMICs we should be using
            uint8_t l_module_height = 0;
            FAPI_TRY(mss::attr::get_dram_module_height(l_dimm, l_module_height));

            if (l_module_height == mss::pmic::module_height::HEIGHT_1U ||
                l_module_height == mss::pmic::module_height::HEIGHT_2U)
            {
                // 1U and 2U are the same sequence, use 1U traits
                using PMIC_TRAITS = mss::pmic::pmic_traits<mss::pmic::module_height::HEIGHT_1U>;

                uint16_t l_vendor_id = 0;

                // PMIC0 and PMIC1 of each DIMM
                for (uint8_t l_current_pmic = 0; l_current_pmic < PMIC_TRAITS::PMICS_PER_DIMM; ++l_current_pmic)
                {
                    const auto l_current_pmic_target = l_pmics[l_pmic_index + l_current_pmic];
                    // Get vendor ID
                    FAPI_TRY(mss::pmic::get_mfg_id[l_current_pmic](l_dimm, l_vendor_id));

                    // Poll to make sure PBULK reports good, then we can enable the chip and write/read registers
                    FAPI_TRY(mss::pmic::poll_for_pbulk_good(l_current_pmic_target),
                             "pmic_enable: poll for pbulk good either failed, or returned not good status on PMIC %s",
                             mss::c_str(l_current_pmic_target));

                    // Call the enable procedure
                    FAPI_TRY((mss::pmic::enable_chip
                              <mss::pmic::module_height::HEIGHT_1U>
                              (l_current_pmic_target, l_dimm, l_vendor_id, i_mode)),
                             "pmic_enable: Error enabling PMIC %s", mss::c_str(l_current_pmic_target));

                }

                // Increment by the number of PMICs that were enabled and move on to the next dimm
                l_pmic_index += PMIC_TRAITS::PMICS_PER_DIMM;
            }
            else // 4U DIMM:
            {
                // Asserting out here as if we see a 4U at this point we shouldn't be able to proceed
                // Ugly assert false, but we need the above else later so we will use this for now
                FAPI_ASSERT(false,
                            fapi2::PMIC_DIMM_SPD_4U()
                            .set_TARGET(l_dimm),
                            "DIMM %s module height attribute identified as 4U. Not supported yet.",
                            mss::c_str(l_dimm));

                // The enable algorithm will be:
                // Load SPD for PMIC0 and PMIC1
                // Broadcast enable both together

                // Load SPD for PMIC2 and PMIC3 (which should be the same data as for PMIC0 and PMIC1)
                // Broadcast and enable both together

                // using PMIC_TRAITS = mss::pmic::pmic_traits<mss::pmic::module_height::HEIGHT_4U>;
                // l_pmic_index += PMIC_TRAITS::PMICS_PER_DIMM;
            }
        }

        return fapi2::FAPI2_RC_SUCCESS;

    fapi_try_exit:
        return fapi2::current_err;
    }
Пример #27
0
///
/// @brief Process single chip target into SMP chip data structure
///
/// @param[in] i_target                     Processor chip target
/// @param[in] i_group_id                   Fabric group ID for this chip target
/// @param[in] i_chip_id                    Fabric chip ID for this chip target
/// @param[in] i_master_chip_sys_next       True if this chip should be designated
///                                         fabric system master post-reconfiguration
/// @param[in] i_first_chip_found_in_group  True if this chip is the first discovered
///                                         in its group (when processing HWP inputs)
/// @param[in] i_op                         Enumerated type representing SMP build phase
/// @param[in/out] io_smp_chip              Structure encapsulating single chip in SMP topology
///
/// @return FAPI2_RC_SUCCESS if success, else error code.
///
fapi2::ReturnCode
p9_build_smp_process_chip(fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
                          const uint8_t i_group_id,
                          const uint8_t i_chip_id,
                          const bool i_master_chip_sys_next,
                          const bool i_first_chip_found_in_group,
                          const p9_build_smp_operation i_op,
                          p9_build_smp_chip& io_smp_chip)
{
    fapi2::buffer<uint64_t> l_hp_mode_curr;
    bool l_err = false;
    char l_target_str[fapi2::MAX_ECMD_STRING_LEN];
    fapi2::ATTR_PROC_FABRIC_SYSTEM_MASTER_CHIP_Type l_sys_master_chip_attr;
    fapi2::ATTR_PROC_FABRIC_GROUP_MASTER_CHIP_Type l_group_master_chip_attr;

    // display target information for this chip
    fapi2::toString(i_target, l_target_str, sizeof(l_target_str));
    FAPI_INF("Target: %s", l_target_str);

    // set target handle pointer
    io_smp_chip.target = &i_target;

    // set group/chip IDs
    io_smp_chip.group_id = i_group_id;
    io_smp_chip.chip_id = i_chip_id;

    // set group/system master CURR data structure fields from HW
    FAPI_TRY(fapi2::getScom(i_target, PU_PB_CENT_SM0_PB_CENT_HP_MODE_CURR, l_hp_mode_curr),
             "Error from getScom (PU_PB_CENT_SM0_PB_CENT_HP_MODE_CURR)");
    io_smp_chip.master_chip_group_curr =
        l_hp_mode_curr.getBit<PU_PB_CENT_SM0_PB_CENT_HP_MODE_CURR_CFG_CHG_RATE_GP_MASTER>();
    io_smp_chip.master_chip_sys_curr =
        l_hp_mode_curr.getBit<PU_PB_CENT_SM0_PB_CENT_HP_MODE_CURR_CFG_MASTER_CHIP>();
    FAPI_DBG("   Master chip GROUP CURR = %d",
             io_smp_chip.master_chip_group_curr);
    FAPI_DBG("   Master chip SYS CURR = %d",
             io_smp_chip.master_chip_sys_curr);

    // set system master NEXT designation from HWP platform input
    io_smp_chip.master_chip_sys_next = i_master_chip_sys_next;
    FAPI_DBG("   Master chip SYS NEXT = %d",
             io_smp_chip.master_chip_sys_next);

    // set group master NEXT designation based on phase
    if (i_op == SMP_ACTIVATE_PHASE1)
    {
        // each chip should match the flush state of the fabric logic
        if (!io_smp_chip.master_chip_sys_curr ||
            io_smp_chip.master_chip_group_curr)
        {
            FAPI_DBG("Error: chip does not match flash state of fabric: sys_curr: %d, group_curr: %d",
                     io_smp_chip.master_chip_sys_curr ? 1 : 0, io_smp_chip.master_chip_group_curr ? 1 : 0);
            l_err = true;
        }
        else
        {
            // designate first chip found in each group as group master after reconfiguration
            io_smp_chip.master_chip_group_next = i_first_chip_found_in_group;
        }
    }
    else
    {
        // maintain current group master status after reconfiguration
        io_smp_chip.master_chip_group_next = io_smp_chip.master_chip_group_curr;
    }

    // set issue quiesce NEXT flag
    if (io_smp_chip.master_chip_sys_next)
    {
        // this chip will not be quiesced, to enable switch AB
        io_smp_chip.issue_quiesce_next = false;

        // in both activation scenarios, we expect that
        // the newly designated master is currently configured
        // as a master within the scope of its current enclosing fabric
        if (!io_smp_chip.master_chip_sys_curr)
        {
            FAPI_DBG("Error: newly designated master is not currently a master");
            l_err = true;
        }
    }
    else
    {
        if (io_smp_chip.master_chip_sys_curr)
        {
            // this chip will not be the new master, but is one now
            // use it to quiesce all chips in its fabric
            io_smp_chip.issue_quiesce_next = true;
        }
        else
        {
            io_smp_chip.issue_quiesce_next = false;
        }
    }

    FAPI_DBG("   Issue quiesce NEXT = %d",
             io_smp_chip.issue_quiesce_next);

    // default remaining NEXT state data structure fields
    io_smp_chip.quiesced_next = false;
    FAPI_DBG("   Quiesced NEXT = %d",
             io_smp_chip.quiesced_next);

    // assert if local error is set
    FAPI_ASSERT(l_err == false,
                fapi2::P9_BUILD_SMP_MASTER_DESIGNATION_ERR()
                .set_TARGET(i_target)
                .set_OP(i_op)
                .set_GROUP_ID(io_smp_chip.group_id)
                .set_CHIP_ID(io_smp_chip.chip_id)
                .set_MASTER_CHIP_SYS_CURR(io_smp_chip.master_chip_sys_curr)
                .set_MASTER_CHIP_GROUP_CURR(io_smp_chip.master_chip_group_curr)
                .set_MASTER_CHIP_SYS_NEXT(io_smp_chip.master_chip_sys_next)
                .set_MASTER_CHIP_GROUP_NEXT(io_smp_chip.master_chip_group_next),
                "Fabric group/system master designation error");

    // write attributes for initfile consumption
    l_sys_master_chip_attr = (io_smp_chip.master_chip_sys_next) ?
                             (fapi2::ENUM_ATTR_PROC_FABRIC_SYSTEM_MASTER_CHIP_TRUE) :
                             (fapi2::ENUM_ATTR_PROC_FABRIC_SYSTEM_MASTER_CHIP_FALSE);
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_PROC_FABRIC_SYSTEM_MASTER_CHIP, i_target, l_sys_master_chip_attr),
             "Error from FAPI_ATTR_SET (ATTR_PROC_FABRIC_SYSTEM_MASTER_CHIP)");

    l_group_master_chip_attr = (io_smp_chip.master_chip_group_next) ?
                               (fapi2::ENUM_ATTR_PROC_FABRIC_GROUP_MASTER_CHIP_TRUE) :
                               (fapi2::ENUM_ATTR_PROC_FABRIC_GROUP_MASTER_CHIP_FALSE);
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_PROC_FABRIC_GROUP_MASTER_CHIP, i_target, l_group_master_chip_attr),
             "Error from FAPI_ATTR_SET (ATTR_PROC_FABRIC_GROUP_MASTER_CHIP)");

fapi_try_exit:
    FAPI_INF("End");
    return fapi2::current_err;
}
Пример #28
0
fapi2::ReturnCode operation<DEFAULT_MC_TYPE>::multi_port_init_internal()
{
    FAPI_INF("multi-port init internal for %s", mss::c_str(iv_target));


    // Let's assume we are going to send out all subtest unless we are in broadcast mode,
    // where we only send up to 2 subtests under an MCA ( 1 for each DIMM) which is why no const
    auto l_dimms = mss::find_targets<fapi2::TARGET_TYPE_DIMM>(iv_target);

    // Get the port/DIMM information for the addresses. This is an integral value which allows us to index
    // all the DIMM across a controller.
    const uint64_t l_portdimm_start_address = iv_const.iv_start_address.get_port_dimm();
    const uint64_t l_portdimm_end_address = iv_const.iv_end_address.get_port_dimm();

    FAPI_INF("%s start port/dimm: %d end port/dimm: %d", mss::c_str(iv_target), l_portdimm_start_address,
             l_portdimm_end_address);

    // If start address == end address we can handle the single port case simply
    if (l_portdimm_start_address == l_portdimm_end_address)
    {
        // Single port case; simple.
        return single_port_init();
    }

    FAPI_ASSERT( l_portdimm_start_address < l_portdimm_end_address,
                 fapi2::MSS_START_ADDR_BIGGER_THAN_END_ADDR()
                 .set_TARGET(iv_target)
                 .set_START_ADDRESS(l_portdimm_start_address)
                 .set_END_ADDRESS(l_portdimm_end_address),
                 "Start address %d larger than end address %d for %s",
                 l_portdimm_start_address, l_portdimm_end_address, mss::c_str(iv_target));

    // Determine which ports are functional and whether we can broadcast to them
    // If we're in broadcast mode, PRD sends DIMM 0/1 of the first functional and configured port,
    // and we then run all ports in parallel (ports set in subtest config)
    if( mss::mcbist::is_broadcast_capable(iv_target) == mss::YES )
    {
        const auto l_prev_size = l_dimms.size();
        FAPI_TRY( broadcast_mode_start_address_check(iv_target, l_portdimm_start_address, l_dimms) );

        FAPI_INF("Updated %d DIMMs on the MCBIST to %d on the first configured MCA due to broadcast mode for %s",
                 l_prev_size, l_dimms.size(), mss::c_str(iv_target));
    }

    // Configures all subtests under an MCBIST
    // If we're here we know start port < end port. We want to run one subtest (for each DIMM) from start_address
    // to the max range of the start address port, then one subtest (for each DIMM) for each port between the
    // start/end ports and one test (for each DIMM) from the start of the end port to the end address.

    // Setup the address configurations
    FAPI_TRY( multi_port_addr() );

    // We need to do three things here. One is to create a subtest which starts at start address and runs to
    // the end of the port. Next, create subtests to go from the start of the next port to the end of the
    // next port. Last we need a subtest which goes from the start of the last port to the end address specified
    // in the end address. Notice this may mean one subtest (start and end are on the same port) or it might
    // mean two subtests (start is one one port, end is on the next.) Or it might mean three or more subtests.

    // Configure multiport subtests, can be all subtests for the DIMMs under an MCBIST,
    // or just the DIMMs under the first configured MCA if in broadcast mode.
    configure_multiport_subtests(l_dimms);

    // Here's an interesting problem. PRD (and others maybe) expect the operation to proceed in address-order.
    // That is, when PRD finds an address it stops on, it wants to continue from there "to the end." That means
    // we need to keep the subtests sorted, otherwise PRD could pass one subtest come upon a fail in a subsequent
    // subtest and re-test something it already passed. So we sort the resulting iv_subtest vector by port/DIMM
    // in the subtest.
    std::sort(iv_program.iv_subtests.begin(), iv_program.iv_subtests.end(),
              [](const decltype(iv_subtest)& a, const decltype(iv_subtest)& b) -> bool
    {
        const uint64_t l_a_portdimm = (a.get_port() << 1) | a.get_dimm();
        const uint64_t l_b_portdimm = (b.get_port() << 1) | b.get_dimm();

        return l_a_portdimm < l_b_portdimm;
    });

    // Initialize the common sections
    FAPI_TRY( base_init() );

    // And configure broadcast mode if required
    FAPI_TRY(mss::mcbist::configure_broadcast_mode(iv_target, iv_program));

fapi_try_exit:
    return fapi2::current_err;
}
Пример #29
0
fapi2::ReturnCode
p9_rng_init_phase1(const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target)
{
    FAPI_INF("Start");

    fapi2::buffer<uint64_t> l_rng_cfg_data;
    fapi2::buffer<uint64_t> l_rng_st0_data;
    fapi2::buffer<uint64_t> l_rng_st1_data;
    fapi2::buffer<uint64_t> l_rng_st2_data;
    fapi2::buffer<uint64_t> l_rng_st3_data;
    fapi2::buffer<uint64_t> l_rng_rdelay_data;

    uint8_t l_rng_adaptest_dd1 = 0;
    uint8_t l_HW403701 = 0;

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_EC_FEATURE_RNG_ADAPTEST_SETTINGS,
                           i_target,
                           l_rng_adaptest_dd1),
             "Error from FAPI_ATTR_GET (ATTR_CHIP_EC_FEATURE_RNG_ADAPTEST_SETTINGS");

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_EC_FEATURE_HW403701,
                           i_target,
                           l_HW403701),
             "Error from FAPI_ATTR_GET (ATTR_CHIP_EC_FEATURE_HW403701");

    // 1. RNG will start running with FIFO write / self tests disabled (enable
    // doesn't gate the osc; it turns off FIFO writes and self test fails);
    // rng_enable = 0.

    // 2. RNG Conditioner Startup Test runs and reports status.
    // Host boot reads Conditioner Startup Test Fail status. If a fail is
    // detected then RNG is declared broken.

    // read conditioner startup test fail status, exit if failure has been
    // reported to declare RNG broken/unusable
    FAPI_TRY(fapi2::getScom(i_target, PU_NX_RNG_CFG, l_rng_cfg_data),
             "Error from getScom (NX RNG Status and Control Register)");

    FAPI_ASSERT(!l_rng_cfg_data.getBit<PU_NX_RNG_CFG_COND_STARTUP_TEST_FAIL>(),
                fapi2::P9_RNG_INIT_CONDITIONER_STARTUP_TEST_FAILED_ERR().
                set_TARGET(i_target).
                set_RNG_CFG(l_rng_cfg_data),
                "Conditioner startup test failed");

    // 3. Host boot programs window sizes, pace, self test enables and
    // parameters, read delay parameters.  program window sizes, pace, self test
    // enables/parameters, and read delay parameters get values from self test
    // registers
    FAPI_TRY(fapi2::getScom(i_target, PU_NX_RNG_ST0, l_rng_st0_data),
             "Error from getScom (NX RNG Self Test Register 0)");
    FAPI_TRY(fapi2::getScom(i_target, PU_NX_RNG_ST1, l_rng_st1_data),
             "Error from getScom (NX RNG Self Test Register 1)");
    FAPI_TRY(fapi2::getScom(i_target, PU_NX_RNG_ST3, l_rng_st3_data),
             "Error from getScom (NX RNG Self Test Register 3)");
    FAPI_TRY(fapi2::getScom(i_target, PU_NX_RNG_RDELAY, l_rng_rdelay_data),
             "Error from putScom (NX RNG Read Delay Parameters Register)");

    if (l_rng_adaptest_dd1)
    {
        FAPI_INF("Configuring Self Test Registers for P9N DD1");
        // configure RNG Self Test Register 0
        l_rng_st0_data.insertFromRight<PU_NX_RNG_ST0_REPTEST_MATCH_TH,
                                       PU_NX_RNG_ST0_REPTEST_MATCH_TH_LEN>
                                       (NX_RNG_ST0_REPTEST_MATCH_TH_DD1);
        l_rng_st0_data.insertFromRight<PU_NX_RNG_ST0_ADAPTEST_SAMPLE_SIZE,
                                       PU_NX_RNG_ST0_ADAPTEST_SAMPLE_SIZE_LEN>
                                       (NX_RNG_ST0_ADAPTEST_SAMPLE_SIZE_DD1);
        l_rng_st0_data.insertFromRight<PU_NX_RNG_ST0_ADAPTEST_WINDOW_SIZE,
                                       PU_NX_RNG_ST0_ADAPTEST_WINDOW_SIZE_LEN>
                                       (NX_RNG_ST0_ADAPTEST_WINDOW_SIZE_DD1);
        l_rng_st0_data.insertFromRight<PU_NX_RNG_ST0_ADAPTEST_RRN_RNG0_MATCH_TH,
                                       PU_NX_RNG_ST0_ADAPTEST_RRN_RNG0_MATCH_TH_LEN>
                                       (NX_RNG_ST0_ADAPTEST_RRN_RNG0_MATCH_TH_DD1);
        l_rng_st0_data.insertFromRight<PU_NX_RNG_ST0_ADAPTEST_RRN_RNG1_MATCH_TH,
                                       PU_NX_RNG_ST0_ADAPTEST_RRN_RNG1_MATCH_TH_LEN>
                                       (NX_RNG_ST0_ADAPTEST_RRN_RNG1_MATCH_TH_DD1);
        l_rng_st0_data.insertFromRight<PU_NX_RNG_ST0_ADAPTEST_CRN_RNG0_MATCH_TH,
                                       PU_NX_RNG_ST0_ADAPTEST_CRN_RNG0_MATCH_TH_LEN>
                                       (NX_RNG_ST0_ADAPTEST_CRN_RNG0_MATCH_TH_DD1);
        l_rng_st0_data.insertFromRight<PU_NX_RNG_ST0_ADAPTEST_CRN_RNG1_MATCH_TH,
                                       PU_NX_RNG_ST0_ADAPTEST_CRN_RNG1_MATCH_TH_LEN>
                                       (NX_RNG_ST0_ADAPTEST_CRN_RNG1_MATCH_TH_DD1);

        // configure RNG Self Test Register 1
        l_rng_st1_data.insertFromRight<PU_NX_RNG_ST1_ADAPTEST_SOFT_FAIL_TH,
                                       PU_NX_RNG_ST1_ADAPTEST_SOFT_FAIL_TH_LEN>
                                       (NX_RNG_ST1_ADAPTEST_SOFT_FAIL_TH_DD1);
        l_rng_st1_data.insertFromRight<PU_NX_RNG_ST1_ADAPTEST_1BIT_MATCH_TH_MIN,
                                       PU_NX_RNG_ST1_ADAPTEST_1BIT_MATCH_TH_MIN_LEN>
                                       (NX_RNG_ST1_ADAPTEST_1BIT_MATCH_TH_MIN_DD1);
        l_rng_st1_data.insertFromRight<PU_NX_RNG_ST1_ADAPTEST_1BIT_MATCH_TH_MAX,
                                       PU_NX_RNG_ST1_ADAPTEST_1BIT_MATCH_TH_MAX_LEN>
                                       (NX_RNG_ST1_ADAPTEST_1BIT_MATCH_TH_MAX_DD1);

        // configure RNG Self Test Register 3
        l_rng_st3_data.writeBit<PU_NX_RNG_ST3_SAMPTEST_RRN_ENABLE>
        (NX_RNG_ST3_SAMPTEST_RRN_ENABLE_DD1);
        l_rng_st3_data.insertFromRight<PU_NX_RNG_ST3_SAMPTEST_WINDOW_SIZE,
                                       PU_NX_RNG_ST3_SAMPTEST_WINDOW_SIZE_LEN>
                                       (NX_RNG_ST3_SAMPTEST_WINDOW_SIZE_DD1);
        l_rng_st3_data.insertFromRight<PU_NX_RNG_ST3_SAMPTEST_MATCH_TH_MIN,
                                       PU_NX_RNG_ST3_SAMPTEST_MATCH_TH_MIN_LEN>
                                       (NX_RNG_ST3_SAMPTEST_MATCH_TH_MIN_DD1);
        l_rng_st3_data.insertFromRight<PU_NX_RNG_ST3_SAMPTEST_MATCH_TH_MAX,
                                       PU_NX_RNG_ST3_SAMPTEST_MATCH_TH_MAX_LEN>
                                       (NX_RNG_ST3_SAMPTEST_MATCH_TH_MAX_DD1);

        // configure RNG Read Delay Parameters Register
        l_rng_rdelay_data.insertFromRight<PU_NX_RNG_RDELAY_CQ_READ_RTY_RATIO,
                                          PU_NX_RNG_RDELAY_CQ_READ_RTY_RATIO_LEN>
                                          (NX_RNG_CQ_RDELAY_READ_RTY_RATIO_DD1);
    }
    else
    {
        FAPI_INF("Configuring Self Test Registers (non P9N DD1)");
        // configure RNG Self Test Register 0
        l_rng_st0_data.insertFromRight<PU_NX_RNG_ST0_REPTEST_MATCH_TH,
                                       PU_NX_RNG_ST0_REPTEST_MATCH_TH_LEN>
                                       (NX_RNG_ST0_REPTEST_MATCH_TH_DD2);
        l_rng_st0_data.insertFromRight<PU_NX_RNG_ST0_ADAPTEST_SAMPLE_SIZE,
                                       PU_NX_RNG_ST0_ADAPTEST_SAMPLE_SIZE_LEN>
                                       (NX_RNG_ST0_ADAPTEST_SAMPLE_SIZE_DD2);
        l_rng_st0_data.insertFromRight<PU_NX_RNG_ST0_ADAPTEST_WINDOW_SIZE,
                                       PU_NX_RNG_ST0_ADAPTEST_WINDOW_SIZE_LEN>
                                       (NX_RNG_ST0_ADAPTEST_WINDOW_SIZE_DD2);
        l_rng_st0_data.insertFromRight<PU_NX_RNG_ST0_ADAPTEST_RRN_RNG0_MATCH_TH,
                                       PU_NX_RNG_ST0_ADAPTEST_RRN_RNG0_MATCH_TH_LEN>
                                       (NX_RNG_ST0_ADAPTEST_RRN_RNG0_MATCH_TH_DD2);
        l_rng_st0_data.insertFromRight<PU_NX_RNG_ST0_ADAPTEST_RRN_RNG1_MATCH_TH,
                                       PU_NX_RNG_ST0_ADAPTEST_RRN_RNG1_MATCH_TH_LEN>
                                       (NX_RNG_ST0_ADAPTEST_RRN_RNG1_MATCH_TH_DD2);
        l_rng_st0_data.insertFromRight<PU_NX_RNG_ST0_ADAPTEST_CRN_RNG0_MATCH_TH,
                                       PU_NX_RNG_ST0_ADAPTEST_CRN_RNG0_MATCH_TH_LEN>
                                       (NX_RNG_ST0_ADAPTEST_CRN_RNG0_MATCH_TH_DD2);
        l_rng_st0_data.insertFromRight<PU_NX_RNG_ST0_ADAPTEST_CRN_RNG1_MATCH_TH,
                                       PU_NX_RNG_ST0_ADAPTEST_CRN_RNG1_MATCH_TH_LEN>
                                       (NX_RNG_ST0_ADAPTEST_CRN_RNG1_MATCH_TH_DD2);

        // configure RNG Self Test Register 1
        l_rng_st1_data.insertFromRight<PU_NX_RNG_ST1_ADAPTEST_SOFT_FAIL_TH,
                                       PU_NX_RNG_ST1_ADAPTEST_SOFT_FAIL_TH_LEN>
                                       (NX_RNG_ST1_ADAPTEST_SOFT_FAIL_TH_DD2);
        l_rng_st1_data.insertFromRight<PU_NX_RNG_ST1_ADAPTEST_1BIT_MATCH_TH_MIN,
                                       PU_NX_RNG_ST1_ADAPTEST_1BIT_MATCH_TH_MIN_LEN>
                                       (NX_RNG_ST1_ADAPTEST_1BIT_MATCH_TH_MIN_DD2);
        l_rng_st1_data.insertFromRight<PU_NX_RNG_ST1_ADAPTEST_1BIT_MATCH_TH_MAX,
                                       PU_NX_RNG_ST1_ADAPTEST_1BIT_MATCH_TH_MAX_LEN>
                                       (NX_RNG_ST1_ADAPTEST_1BIT_MATCH_TH_MAX_DD2);

        // configure RNG Self Test Register 3
        l_rng_st3_data.writeBit<PU_NX_RNG_ST3_SAMPTEST_RRN_ENABLE>
        (NX_RNG_ST3_SAMPTEST_RRN_ENABLE_DD2);
        l_rng_st3_data.insertFromRight<PU_NX_RNG_ST3_SAMPTEST_WINDOW_SIZE,
                                       PU_NX_RNG_ST3_SAMPTEST_WINDOW_SIZE_LEN>
                                       (NX_RNG_ST3_SAMPTEST_WINDOW_SIZE_DD2);
        l_rng_st3_data.insertFromRight<PU_NX_RNG_ST3_SAMPTEST_MATCH_TH_MIN,
                                       PU_NX_RNG_ST3_SAMPTEST_MATCH_TH_MIN_LEN>
                                       (NX_RNG_ST3_SAMPTEST_MATCH_TH_MIN_DD2);
        l_rng_st3_data.insertFromRight<PU_NX_RNG_ST3_SAMPTEST_MATCH_TH_MAX,
                                       PU_NX_RNG_ST3_SAMPTEST_MATCH_TH_MAX_LEN>
                                       (NX_RNG_ST3_SAMPTEST_MATCH_TH_MAX_DD2);

        // configure RNG Read Delay Parameters Register
        l_rng_rdelay_data.writeBit<PU_NX_RNG_RDELAY_CQ_LFSR_RESEED_EN>
        (NX_RNG_CQ_RDELAY_LFSR_RESEED_EN_DD2);
        l_rng_rdelay_data.insertFromRight<PU_NX_RNG_RDELAY_CQ_READ_RTY_RATIO,
                                          PU_NX_RNG_RDELAY_CQ_READ_RTY_RATIO_LEN>
                                          (NX_RNG_CQ_RDELAY_READ_RTY_RATIO_DD2);

    }

    FAPI_TRY(fapi2::putScom(i_target, PU_NX_RNG_ST0, l_rng_st0_data),
             "Error from putScom (NX RNG Self Test Register 0)");

    FAPI_TRY(fapi2::putScom(i_target, PU_NX_RNG_ST1, l_rng_st1_data),
             "Error from putScom (NX RNG Self Test Register 1)");

    FAPI_TRY(fapi2::putScom(i_target, PU_NX_RNG_ST3, l_rng_st3_data),
             "Error from putScom (NX RNG Self Test Register 3)");

    FAPI_TRY(fapi2::putScom(i_target, PU_NX_RNG_RDELAY, l_rng_rdelay_data),
             "Error from putScom (NX RNG Read Delay Parameters Register)");

    // 4. If RNG is not broken then host boot sets rng_enable =1.
    // update RNG Status and Control Register to engage initialization test
    FAPI_TRY(fapi2::getScom(i_target, PU_NX_RNG_CFG, l_rng_cfg_data),
             "Error from getScom (NX RNG Status and Control Register)");

    l_rng_cfg_data.setBit<PU_NX_RNG_CFG_ENABLE>();
    l_rng_cfg_data.writeBit<PU_NX_RNG_CFG_MASK_TOGGLE_ENABLE>
    (NX_RNG_CFG_CONDITIONER_MASK_TOGGLE);
    l_rng_cfg_data.writeBit<PU_NX_RNG_CFG_SAMPTEST_ENABLE>
    (NX_RNG_CFG_SAMPLE_RATE_TEST_ENABLE);
    l_rng_cfg_data.writeBit<PU_NX_RNG_CFG_REPTEST_ENABLE>
    (NX_RNG_CFG_REPTEST_ENABLE);
    l_rng_cfg_data.writeBit<PU_NX_RNG_CFG_ADAPTEST_1BIT_ENABLE>
    (NX_RNG_CFG_ADAPTEST_1BIT_ENABLE);
    l_rng_cfg_data.writeBit<PU_NX_RNG_CFG_ADAPTEST_ENABLE>
    (NX_RNG_CFG_ADAPTEST_ENABLE);
    l_rng_cfg_data.insertFromRight<PU_NX_RNG_CFG_ST2_RESET_PERIOD,
                                   PU_NX_RNG_CFG_ST2_RESET_PERIOD_LEN>
                                   (NX_RNG_CFG_ST2_RESET_PERIOD);

    if (l_HW403701 != 0)
    {
        l_rng_cfg_data.insertFromRight<PU_NX_RNG_CFG_PACE_RATE,
                                       PU_NX_RNG_CFG_PACE_RATE_LEN>
                                       (NX_RNG_CFG_PACE_RATE_HW403701);
    }
    else
    {
        l_rng_cfg_data.insertFromRight<PU_NX_RNG_CFG_PACE_RATE,
                                       PU_NX_RNG_CFG_PACE_RATE_LEN>
                                       (NX_RNG_CFG_PACE_RATE);
    }

    FAPI_TRY(fapi2::putScom(i_target, PU_NX_RNG_CFG, l_rng_cfg_data),
             "Error from putScom (NX RNG Status and Control Register)");

fapi_try_exit:
    FAPI_INF("End");
    return fapi2::current_err;
}
Пример #30
0
fapi2::ReturnCode
p9_hcd_core_stopclocks(
    const fapi2::Target<fapi2::TARGET_TYPE_CORE>& i_target,
    const bool i_sync_stop_quad_clk)
{
    FAPI_INF(">>p9_hcd_core_stopclocks");
    fapi2::ReturnCode                              l_rc;
    fapi2::buffer<uint64_t>                        l_ccsr;
    fapi2::buffer<uint64_t>                        l_data64;
    fapi2::buffer<uint64_t>                        l_temp64;
    uint32_t                                       l_loops1ms;
    uint8_t                                        l_attr_chip_unit_pos;
    uint8_t                                        l_attr_vdm_enabled;
    uint8_t                                        l_attr_sdisn_setup;
    const fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> l_sys;
    auto  l_quad = i_target.getParent<fapi2::TARGET_TYPE_EQ>();
    auto  l_perv = i_target.getParent<fapi2::TARGET_TYPE_PERV>();
    auto  l_chip = i_target.getParent<fapi2::TARGET_TYPE_PROC_CHIP>();

    auto l_ex_vector = l_quad.getChildren<fapi2::TARGET_TYPE_EX>
                       (fapi2::TARGET_STATE_FUNCTIONAL);

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_EC_FEATURE_SDISN_SETUP, l_chip,
                           l_attr_sdisn_setup));

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_VDM_ENABLED,      l_chip,
                           l_attr_vdm_enabled));
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS,    l_perv,
                           l_attr_chip_unit_pos));
    l_attr_chip_unit_pos = (l_attr_chip_unit_pos -
                            p9hcd::PERV_TO_CORE_POS_OFFSET) % 4;

    //Check if EQ is powered off; if so, return
    FAPI_TRY(fapi2::getScom(l_quad, EQ_PPM_PFSNS, l_data64),
             "Error reading data from EQ_PPM_PFSNS");

    if (l_data64.getBit<EQ_PPM_PFSNS_VDD_PFETS_DISABLED_SENSE>())
    {
        FAPI_DBG("Set core as stopped in STOP history register");
        FAPI_TRY(putScom(i_target, C_PPM_SSHSRC, BIT64(0)));
        return fapi2::current_err;
    }

    //Check if core is powered off; if so, return
    FAPI_TRY(fapi2::getScom(i_target, C_PPM_PFSNS, l_data64),
             "Error reading data from C_PPM_PFSNS");

    if (l_data64.getBit<C_PPM_PFSNS_VDD_PFETS_DISABLED_SENSE>())
    {
        FAPI_DBG("Set core as stopped in STOP history register");
        FAPI_TRY(putScom(i_target, C_PPM_SSHSRC, BIT64(0)));
        return fapi2::current_err;
    }


    // ----------------------------
    // Prepare to stop core clocks
    // ----------------------------

    FAPI_DBG("Check PM_RESET_STATE_INDICATOR via GPMMR[15]");
    FAPI_TRY(getScom(i_target, C_PPM_GPMMR_SCOM, l_data64));

    if (!l_data64.getBit<15>())
    {
        FAPI_DBG("Gracefully turn off power management, continue anyways if fail");
        /// @todo RTC158181 suspend_pm()
    }

    FAPI_DBG("Check core clock controller status");
    l_rc = p9_common_clk_ctrl_state<fapi2::TARGET_TYPE_CORE>(i_target);

    if (l_rc)
    {
        FAPI_INF("Clock controller of this core chiplet is inaccessible, return");
        goto fapi_try_exit;
    }

    FAPI_DBG("Check cache clock controller status");
    l_rc = p9_common_clk_ctrl_state<fapi2::TARGET_TYPE_EQ>(l_quad);

    if (l_rc)
    {
        FAPI_INF("WARNING: core is enabled while cache is not, continue anyways");
    }
    else
    {

        FAPI_DBG("Check PERV clock status for access to CME via CLOCK_STAT[4]");
        FAPI_TRY(getScom(l_quad, EQ_CLOCK_STAT_SL, l_data64));

        FAPI_DBG("Check PERV fence status for access to CME via CPLT_CTRL1[4]");
        FAPI_TRY(getScom(l_quad, EQ_CPLT_CTRL1, l_temp64));

        if (l_data64.getBit<4>() == 0 && l_temp64.getBit<4>() == 0)
        {

#ifdef DD2
            FAPI_DBG("Halting the PGPE ...");
            l_rc = ppe_halt(l_chip, PGPE_BASE_ADDRESS);
            FAPI_ASSERT_NOEXIT(!l_rc,
                               fapi2::CORE_STOPCLKS_PGPE_HALT_TIMEOUT()
                               .set_CHIP(l_chip),
                               "PSTATE GPE Halt timeout");

            FAPI_DBG("Halting the SGPE ...");
            l_rc = ppe_halt(l_chip, SGPE_BASE_ADDRESS);
            FAPI_ASSERT_NOEXIT(!l_rc,
                               fapi2::CORE_STOPCLKS_SGPE_HALT_TIMEOUT()
                               .set_CHIP(l_chip),
                               "STOP GPE Halt timeout");

            FAPI_DBG("Clear the atomic lock on EQ %d", l_attr_chip_unit_pos);
            l_rc = p9_clear_atomic_lock(l_quad);
            FAPI_ASSERT_NOEXIT(!l_rc,
                               fapi2::CORE_STOPCLKS_ATOMIC_LOCK_FAIL()
                               .set_EQ(l_quad),
                               "EQ Atomic Halt timeout");

            for ( auto& ex : l_ex_vector )
            {
                fapi2::ATTR_CHIP_UNIT_POS_Type  l_cme_id = 0;
                FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, ex, l_cme_id));

                FAPI_DBG("Halting CME %d", l_cme_id );
                uint64_t l_cme_base_address = getCmeBaseAddress (l_cme_id);
                l_rc = ppe_halt(l_chip, l_cme_base_address);
                FAPI_ASSERT_NOEXIT(!l_rc,
                                   fapi2::CACHE_STOPCLKS_CME_HALT_TIMEOUT()
                                   .set_EX(ex),
                                   "CME Halt timeout");
            }

#endif

            //if a core is only in special wakeup and asserting pm_exit,
            //then setting 6,7 of SICR will cause pm_exit to drop and
            //the core will re-enter a power saving state
            FAPI_DBG("Prevent Core-L2 Quiesce from removing PM_EXIT CME_SCOM_LMCR[22]");
            FAPI_TRY(putScom(l_quad,
                             (l_attr_chip_unit_pos < 2) ?
                             EX_0_CME_SCOM_LMCR_OR : EX_1_CME_SCOM_LMCR_OR,
                             (BIT64(22))));

            FAPI_DBG("Assert Core-L2/CC Quiesces via CME_SCOM_SICR[6,8]/[7,9]");
            FAPI_TRY(putScom(l_quad,
                             (l_attr_chip_unit_pos < 2) ?
                             EX_0_CME_SCOM_SICR_OR : EX_1_CME_SCOM_SICR_OR,
                             (BIT64(6 + (l_attr_chip_unit_pos % 2)) |
                              BIT64(8 + (l_attr_chip_unit_pos % 2)))));
        }
    }

    FAPI_DBG("Assert pm_mux_disable to get PCB Mux from CME via SLAVE_CONFIG[7]");
    FAPI_TRY(getScom(i_target, C_SLAVE_CONFIG_REG, l_data64));
    FAPI_TRY(putScom(i_target, C_SLAVE_CONFIG_REG, DATA_SET(7)));

    FAPI_DBG("Override possible PPM write protection to CME via CPPM_CPMMR[1]");
    FAPI_TRY(putScom(i_target, C_CPPM_CPMMR_OR, MASK_SET(1)));

    FAPI_DBG("Assert chiplet fence via NET_CTRL0[18]");
    FAPI_TRY(putScom(i_target, C_NET_CTRL0_WOR, MASK_SET(18)));

    // -------------------------------
    // Stop core clocks
    // -------------------------------

    FAPI_DBG("Clear all SCAN_REGION_TYPE bits");
    FAPI_TRY(putScom(i_target, C_SCAN_REGION_TYPE, MASK_ZERO));

    if(i_sync_stop_quad_clk)
    {
        FAPI_DBG("Stop core clocks(all but pll) via CLK_REGION in SLAVE mode");
        l_data64 = (p9hcd::CLK_STOP_CMD_SLAVE     |
                    p9hcd::CLK_REGION_ALL_BUT_PLL |
                    p9hcd::CLK_THOLD_ALL);
        FAPI_TRY(putScom(i_target, C_CLK_REGION, l_data64));

    }
    else
    {
        FAPI_DBG("Stop core clocks(all but pll) via CLK_REGION");
        l_data64 = (p9hcd::CLK_STOP_CMD           |
                    p9hcd::CLK_REGION_ALL_BUT_PLL |
                    p9hcd::CLK_THOLD_ALL);
        FAPI_TRY(putScom(i_target, C_CLK_REGION, l_data64));

        FAPI_DBG("Poll for core clocks stopped via CPLT_STAT0[8]");
        l_loops1ms = 1E6 / CORE_CLK_STOP_POLLING_HW_NS_DELAY;

        do
        {
            fapi2::delay(CORE_CLK_STOP_POLLING_HW_NS_DELAY,
                         CORE_CLK_STOP_POLLING_SIM_CYCLE_DELAY);

            FAPI_TRY(getScom(i_target, C_CPLT_STAT0, l_data64));
        }
        while((l_data64.getBit<8>() != 1) && ((--l_loops1ms) != 0));

        FAPI_ASSERT((l_loops1ms != 0),
                    fapi2::PMPROC_CORECLKSTOP_TIMEOUT().set_CORECPLTSTAT(l_data64),
                    "Core Clock Stop Timeout");

        FAPI_DBG("Check core clocks stopped via CLOCK_STAT_SL[4-13]");
        FAPI_TRY(getScom(i_target, C_CLOCK_STAT_SL, l_data64));

        FAPI_ASSERT((((~l_data64) & p9hcd::CLK_REGION_ALL_BUT_PLL) == 0),
                    fapi2::PMPROC_CORECLKSTOP_FAILED().set_CORECLKSTAT(l_data64),
                    "Core Clock Stop Failed");
        FAPI_DBG("Core clocks stopped now");
    }

    // -------------------------------
    // Disable core clock sync
    // -------------------------------

    FAPI_DBG("Drop core clock sync enable via CPPM_CACCR[15]");
    FAPI_TRY(putScom(i_target, C_CPPM_CACCR_CLEAR, MASK_SET(15)));

    FAPI_DBG("Poll for core clock sync done to drop via CPPM_CACSR[13]");
    l_loops1ms = 1E6 / CORE_CLK_SYNC_POLLING_HW_NS_DELAY;

    do
    {
        fapi2::delay(CORE_CLK_SYNC_POLLING_HW_NS_DELAY,
                     CORE_CLK_SYNC_POLLING_SIM_CYCLE_DELAY);

        FAPI_TRY(getScom(i_target, C_CPPM_CACSR, l_data64));
    }
    while((l_data64.getBit<13>() == 1) && ((--l_loops1ms) != 0));

    FAPI_ASSERT((l_loops1ms != 0),
                fapi2::PMPROC_CORECLKSYNCDROP_TIMEOUT().set_COREPPMCACSR(l_data64),
                "Core Clock Sync Drop Timeout");
    FAPI_DBG("Core clock sync done dropped");

    // -------------------------------
    // Fence up
    // -------------------------------

    FAPI_DBG("Assert skew sense to skew adjust fence via NET_CTRL0[22]");
    FAPI_TRY(putScom(i_target, C_NET_CTRL0_WOR, MASK_SET(22)));

    FAPI_DBG("Drop ABIST_SRAM_MODE_DC to support ABIST Recovery via BIST[1]");
    FAPI_TRY(getScom(i_target, C_BIST, l_data64));
    FAPI_TRY(putScom(i_target, C_BIST, DATA_UNSET(1)));

    FAPI_DBG("Assert vital fence via CPLT_CTRL1[3]");
    FAPI_TRY(putScom(i_target, C_CPLT_CTRL1_OR, MASK_SET(3)));

    FAPI_DBG("Assert regional fences via CPLT_CTRL1[4-14]");
    FAPI_TRY(putScom(i_target, C_CPLT_CTRL1_OR, p9hcd::CLK_REGION_ALL));

    if (l_attr_sdisn_setup)
    {
        FAPI_DBG("DD1 Only: Drop sdis_n(flushing LCBES condition) vai CPLT_CONF0[34]");
        FAPI_TRY(putScom(i_target, C_CPLT_CONF0_CLEAR, MASK_SET(34)));
    }

    // -------------------------------
    // Disable VDM
    // -------------------------------

    if (l_attr_vdm_enabled == fapi2::ENUM_ATTR_VDM_ENABLED_TRUE)
    {
        FAPI_DBG("Set VDM Disable via CPPM_VDMCR[1]");
        FAPI_TRY(putScom(i_target, C_PPM_VDMCR_OR, MASK_SET(1)));
        FAPI_DBG("Drop VDM Poweron via CPPM_VDMCR[0]");
        FAPI_TRY(putScom(i_target, C_PPM_VDMCR_CLEAR, MASK_SET(0)));
    }

    // -------------------------------
    // Update stop history
    // -------------------------------

    FAPI_DBG("Set core as stopped in STOP history register");
    FAPI_TRY(putScom(i_target, C_PPM_SSHSRC, BIT64(0)));

    // -------------------------------
    // Clean up
    // -------------------------------

    FAPI_DBG("Return possible PPM write protection to CME via CPPM_CPMMR[1]");
    FAPI_TRY(putScom(i_target, C_CPPM_CPMMR_CLEAR, MASK_SET(1)));

    FAPI_DBG("Drop pm_mux_disable to release PCB Mux via SLAVE_CONFIG[7]");
    FAPI_TRY(getScom(i_target, C_SLAVE_CONFIG_REG, l_data64));
    FAPI_TRY(putScom(i_target, C_SLAVE_CONFIG_REG, DATA_UNSET(7)));

fapi_try_exit:

    FAPI_INF("<<p9_hcd_core_stopclocks");
    return fapi2::current_err;
}