Example #1
0
static fapi2::ReturnCode setup_pcie_work_around_attributes(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
    const fapi2::buffer<uint64_t>& i_ecid_part)
{
    uint8_t l_version = 0;
    i_ecid_part.extractToRight<DD_LEVEL, DD_LEVEL_LEN>(l_version);

    {
        // Workarounds for DD1.00 modulues
        fapi2::ATTR_CHIP_EC_FEATURE_PCIE_LOCK_PHASE_ROTATOR_Type l_ec_feature_pcie_lock_phase_rotator = 0;
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_EC_FEATURE_PCIE_LOCK_PHASE_ROTATOR, i_target,
                               l_ec_feature_pcie_lock_phase_rotator),
                 "Error from FAPI_ATTR_GET (ATTR_CHIP_EC_FEATURE_PCIE_LOCK_PHASE_ROTATOR)");

        uint8_t l_value = 0;

        if (l_ec_feature_pcie_lock_phase_rotator && (l_version < ddLevelPciePart))
        {
            FAPI_DBG("seeing version 1.00 (0x%x) setting ATTR_PROC_PCIE_PCS_RX_ROT_EXTEL", l_version);
            l_value = 1;
        }

        for (auto& l_pec_trgt : i_target.getChildren<fapi2::TARGET_TYPE_PEC>(fapi2::TARGET_STATE_FUNCTIONAL))
        {
            FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_PROC_PCIE_PCS_RX_ROT_EXTEL, l_pec_trgt, l_value),
                     "Error from FAPI_ATTR_SET (ATTR_PROC_PCIE_PCS_RX_ROT_EXTEL)");
        }

    }
    {
        // Workarounds for DD1.01/DD1.02 modules
        fapi2::ATTR_CHIP_EC_FEATURE_PCIE_DISABLE_FDDC_Type l_ec_feature_pcie_disable_fddc = 0;
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_EC_FEATURE_PCIE_DISABLE_FDDC, i_target, l_ec_feature_pcie_disable_fddc),
                 "Error from FAPI_ATTR_GET (ATTR_CHIP_EC_FEATURE_PCIE_DISABLE_FDDC)");

        uint8_t l_value = 1;

        if (l_ec_feature_pcie_disable_fddc && (l_version >= ddLevelPciePart))
        {
            FAPI_DBG("seeing version >= 1.01 (0x%x) clearing ATTR_PROC_PCIE_PCS_RX_DFE_FDDC", l_version);
            l_value = 0;
        }

        for (auto& l_pec_trgt : i_target.getChildren<fapi2::TARGET_TYPE_PEC>(fapi2::TARGET_STATE_FUNCTIONAL))
        {
            FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_PROC_PCIE_PCS_RX_DFE_FDDC, l_pec_trgt, l_value),
                     "Error from FAPI_ATTR_SET (ATTR_PROC_PCIE_PCS_RX_DFE_FDDC)");
        }
    }

    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    return fapi2::current_err;
}
    /// @brief FW Team Utility function that sets the Bad DQ Bitmap.
    /// @param[in] i_mba  Reference to MBA Chiplet
    /// @param[in] i_port MBA port number (0-(MAX_PORTS_PER_MBA - 1))
    /// @param[in] i_dimm MBA port DIMM number (0-(MAX_DIMM_PER_PORT - 1))
    /// @param[in] i_rank DIMM rank number (0-(MAX_RANKS_PER_DIMM -1))
    /// @param[in] i_data Reference to data where Bad DQ bitmap is copied from
    /// @return FAPI2_RC_SUCCESS
    fapi2::ReturnCode dimmSetBadDqBitmap(const fapi2::Target<fapi2::TARGET_TYPE_MBA>& i_mba,
                                         const uint8_t i_port,
                                         const uint8_t i_dimm,
                                         const uint8_t i_rank,
                                         const uint8_t (&i_data)[DIMM_DQ_RANK_BITMAP_SIZE])
    {
        FAPI_INF(">>dimmSetBadDqBitmap. %s:%d:%d:%d", mss::c_str(i_mba), i_port, i_dimm, i_rank);

        // Check parameters and find the DIMM fapi2::Target<fapi2::TARGET_TYPE_MBA>
        fapi2::Target<fapi2::TARGET_TYPE_DIMM> l_dimm;

        // Get the Bad DQ bitmap by querying ATTR_BAD_DQ_BITMAP.
        // Use a heap based array to avoid large stack alloc
        uint8_t (&l_dqBitmap)[MAX_RANKS_PER_DIMM][DIMM_DQ_RANK_BITMAP_SIZE] =
            *(reinterpret_cast<uint8_t(*)[MAX_RANKS_PER_DIMM][DIMM_DQ_RANK_BITMAP_SIZE]>
              (new uint8_t[MAX_RANKS_PER_DIMM * DIMM_DQ_RANK_BITMAP_SIZE]));

        FAPI_TRY(dimmBadDqCheckParamFindDimm(i_mba, i_port, i_dimm, i_rank, l_dimm));
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_BAD_DQ_BITMAP, l_dimm, l_dqBitmap));

        // Add the rank bitmap to the DIMM bitmap and write the bitmap
        memcpy(l_dqBitmap[i_rank], i_data, DIMM_DQ_RANK_BITMAP_SIZE);

        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_BAD_DQ_BITMAP, l_dimm, l_dqBitmap));

        delete [] &l_dqBitmap;

        FAPI_INF("<<dimmSetBadDqBitmap");
    fapi_try_exit:
        return fapi2::current_err;
    }
Example #3
0
// ----------------------------------------------------------------------
// Function definitions
// ----------------------------------------------------------------------
fapi2::ReturnCode p9_pm_firinit(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
    const p9pm::PM_FLOW_MODE i_mode)
{
    FAPI_IMP("p9_pm_firinit start");

    fapi2::ReturnCode l_rc;
    uint8_t l_pm_firinit_flag;
    fapi2::buffer<uint64_t> l_data64;

    // CHECKING FOR FIRS BEFORE RESET and INIT
    FAPI_DBG("Checking PBA FIRs");
    FAPI_TRY(fapi2::getScom(i_target, PU_PBAFIR , l_data64),
             "ERROR: Failed to fetch PBA FIR");

    if(l_data64)
    {
        FAPI_INF("WARNING: PBA has active error(s)");
    }

    // Handle PBA FIRs, Masks and actions
    FAPI_DBG("Calling PBA firinit ...");
    FAPI_EXEC_HWP(l_rc, p9_pm_pba_firinit, i_target, i_mode);
    FAPI_TRY(l_rc);

    // Handle Core and Quad errors
    FAPI_DBG("Calling PPM firinit ...");
    FAPI_EXEC_HWP(l_rc, p9_pm_ppm_firinit, i_target, i_mode);
    FAPI_TRY(l_rc);

    // Handle CME FIRs, Masks and actions
    FAPI_DBG("Calling CME firinit ...");
    FAPI_EXEC_HWP(l_rc, p9_pm_cme_firinit, i_target, i_mode);
    FAPI_TRY(l_rc);

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PM_FIRINIT_DONE_ONCE_FLAG, i_target,
                           l_pm_firinit_flag),
             "ERROR: Failed to fetch the firinit call status flag");

    // Set the ATTR_PM_FIRINIT_DONE_ONCE_FLAG attribute
    if (i_mode == p9pm::PM_INIT)
    {
        if (l_pm_firinit_flag != 1)
        {
            l_pm_firinit_flag = 1;
            FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_PM_FIRINIT_DONE_ONCE_FLAG,
                                   i_target, l_pm_firinit_flag),
                     "ERROR: Failed to set firinit call status after init");
        }
    }

fapi_try_exit:
    FAPI_INF("p9_pm_firinit end");
    return fapi2::current_err;
} // END p9_pm_firinit
Example #4
0
fapi2::ReturnCode p9_getecid(const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target_chip,
                             fapi2::variable_buffer& o_fuseString)
{
    uint64_t attr_data[2];
    fapi2::buffer<uint64_t> l_ecid_part0_data64 = 0;
    fapi2::buffer<uint64_t> l_ecid_part1_data64 = 0;
    fapi2::buffer<uint64_t> l_ecid_part2_data64 = 0;
    fapi2::variable_buffer l_fuseString(p9_getecid_fuseString_len);
    FAPI_INF("Entering ...");


    FAPI_DBG("extract and manipulate ECID data");
    FAPI_TRY(fapi2::getScom(i_target_chip, PU_OTPROM0_ECID_PART0_REGISTER, l_ecid_part0_data64));
    FAPI_TRY(fapi2::getScom(i_target_chip, PU_OTPROM0_ECID_PART1_REGISTER, l_ecid_part1_data64));
    FAPI_TRY(fapi2::getScom(i_target_chip, PU_OTPROM0_ECID_PART2_REGISTER, l_ecid_part2_data64));

    l_ecid_part0_data64.reverse();
    l_ecid_part1_data64.reverse();
    l_ecid_part2_data64.reverse();

    attr_data[0] = l_ecid_part0_data64();
    attr_data[1] = l_ecid_part1_data64();

    FAPI_TRY(l_fuseString.insert(l_ecid_part0_data64(), 0, 64));

    FAPI_TRY(l_fuseString.insert(l_ecid_part1_data64(), 64, 64));

    FAPI_TRY(l_fuseString.insert(l_ecid_part2_data64(), 128, 64));

    o_fuseString = l_fuseString;

    FAPI_DBG("push fuse string into attribute");

    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_ECID, i_target_chip, attr_data));

    // Set some attributes memory can used to make work-around decisions.
    FAPI_TRY( setup_memory_work_around_attributes(i_target_chip, l_ecid_part2_data64) );
    FAPI_TRY( setup_pcie_work_around_attributes(i_target_chip, l_ecid_part2_data64) );

    FAPI_INF("Exiting ...");

fapi_try_exit:
    return fapi2::current_err;

}
Example #5
0
fapi::ReturnCode mss_volt(std::vector<fapi::Target> & i_targets_memb)
{

    fapi::ReturnCode l_rc;
    uint8_t l_dimm_functionality=0;
    uint8_t l_spd_dramtype=0;
    uint8_t l_spd_volts=0;
    uint8_t l_spd_volts_all_dimms=0x06;  //start assuming all voltages supported
    uint8_t l_dram_ddr3_found_flag=0;
    uint8_t l_dram_ddr4_found_flag=0;
    uint8_t l_volt_override = 0x00;
    uint8_t l_volt_override_domain = 0x00;

    uint32_t l_selected_dram_voltage=0;  //this gets written into all centaurs when done.
    uint32_t l_selected_dram_voltage_vpp=0;
    uint32_t l_tolerated_dram_voltage = MAX_TOLERATED_VOLT; //initially set to the max tolerated voltage

    do
    {
        // Iterate through the list of centaurs
        for (uint32_t i=0; i < i_targets_memb.size(); i++)
        {
            std::vector<fapi::Target> l_mbaChiplets;
            // Get associated MBA's on this centaur
            l_rc=fapiGetChildChiplets(i_targets_memb[i], fapi::TARGET_TYPE_MBA_CHIPLET, l_mbaChiplets);
            if (l_rc) break;


	    l_rc = FAPI_ATTR_GET(ATTR_MSS_VOLT_OVERRIDE, &i_targets_memb[i], l_volt_override);
	    if (l_rc) break;

	    // Note if there is an overrride being applied on the domain
	    if ( (l_volt_override != fapi::ENUM_ATTR_MSS_VOLT_OVERRIDE_NONE) && (l_volt_override_domain == fapi::ENUM_ATTR_MSS_VOLT_OVERRIDE_NONE) )
	    {
	    	l_volt_override_domain = l_volt_override;
	    }

	    // Error if our overides are not the same across the domain
	    if (l_volt_override_domain != l_volt_override)
	    {
                        // this just needs to callout the mismatching memb.
                        const uint8_t &OVERRIDE_TYPE = l_volt_override;
                        const uint8_t &OVERRIDE_DOMAIN_TYPE = l_volt_override_domain;
                        const fapi::Target &MEMB_TARGET = i_targets_memb[i];
                        FAPI_ERR("Mismatch volt override request.  Domain: 0x%x  Current Target Requests: 0x%x", l_volt_override_domain, l_volt_override);
                        FAPI_SET_HWP_ERROR(l_rc, RC_MSS_VOLT_OVERIDE_MIXING);
                        fapiLogError(l_rc);
	    }

            // Loop through the 2 MBA's
            for (uint32_t j=0; j < l_mbaChiplets.size(); j++)
            {
                std::vector<fapi::Target> l_dimm_targets;
                // Get a vector of DIMM targets
                l_rc = fapiGetAssociatedDimms(l_mbaChiplets[j], l_dimm_targets, fapi::TARGET_STATE_PRESENT);
                if (l_rc) break;

                for (uint32_t k=0; k < l_dimm_targets.size(); k++)
                {
                    l_rc = FAPI_ATTR_GET(ATTR_SPD_DRAM_DEVICE_TYPE, &l_dimm_targets[k], l_spd_dramtype);
                    if (l_rc) break;
                    l_rc = FAPI_ATTR_GET(ATTR_SPD_MODULE_NOMINAL_VOLTAGE, &l_dimm_targets[k], l_spd_volts);
                    if (l_rc) break;
                    l_rc = FAPI_ATTR_GET(ATTR_FUNCTIONAL, &l_dimm_targets[k], l_dimm_functionality);
                    if (l_rc) break;

                    // spd_volts:  bit0= NOT 1.5V bit1=1.35V bit2=1.25V, assume a 1.20V in future for DDR4
                    // check for supported voltage/dram type combo  DDR3=12, DDR4=13
                    if (l_spd_dramtype == fapi::ENUM_ATTR_SPD_DRAM_DEVICE_TYPE_DDR3)
                    {
                        l_dram_ddr3_found_flag=1;
                    }
                    else if (l_spd_dramtype == fapi::ENUM_ATTR_SPD_DRAM_DEVICE_TYPE_DDR4)
                    {
                        l_dram_ddr4_found_flag=1;
                    }
                    else 
                    {
                        // this just needs to be deconfiged at the dimm level
                        const uint8_t &DEVICE_TYPE = l_spd_dramtype;
                        const fapi::Target &DIMM_TARGET = l_dimm_targets[k];
                        FAPI_ERR("Unknown DRAM Device Type 0x%x", l_spd_dramtype);
                        FAPI_SET_HWP_ERROR(l_rc, RC_MSS_VOLT_UNRECOGNIZED_DRAM_DEVICE_TYPE);
                        fapiLogError(l_rc);
                    }

                    if(l_dimm_functionality == fapi::ENUM_ATTR_FUNCTIONAL_FUNCTIONAL)
                    {
                        //AND dimm voltage capabilities together to find aggregate voltage support on all dimms
                        l_spd_volts_all_dimms = l_spd_volts_all_dimms & l_spd_volts;
                    }

                }//end of dimms loop
                if (l_rc)
                {
                    break;
                }
            }//end of mba loop
            if (l_rc)
            {
                break;
            }
        }//end of centaur (memb) loop      
        if (l_rc)
        {
            // Break out of do...while(0)
            break;
        }

        // now we figure out if we have a supported ddr type and voltage
        // note: only support DDR3=1.35V and DDR4=1.2xV


        // Mixed Dimms, Deconfig the DDR4.
        if (l_dram_ddr3_found_flag && l_dram_ddr4_found_flag)
        {
            std::vector<fapi::Target> l_dimm_targets_deconfig;
            // Iterate through the list of centaurs
            for (uint32_t i=0; i < i_targets_memb.size(); i++)
            {
                std::vector<fapi::Target> l_mbaChiplets;
                // Get associated MBA's on this centaur
                l_rc=fapiGetChildChiplets(i_targets_memb[i], fapi::TARGET_TYPE_MBA_CHIPLET, l_mbaChiplets);
                if (l_rc) break;
                // Loop through the 2 MBA's
                for (uint32_t j=0; j < l_mbaChiplets.size(); j++)
                {
                    std::vector<fapi::Target> l_dimm_targets;
                    // Get a vector of DIMM targets
                    l_rc = fapiGetAssociatedDimms(l_mbaChiplets[j], l_dimm_targets, fapi::TARGET_STATE_PRESENT);
                    if (l_rc) break;
                    for (uint32_t k=0; k < l_dimm_targets.size(); k++)
                    {

                        l_rc = FAPI_ATTR_GET(ATTR_SPD_DRAM_DEVICE_TYPE, &l_dimm_targets[k], l_spd_dramtype);
                        if (l_rc) break;

                        if (l_spd_dramtype == fapi::ENUM_ATTR_SPD_DRAM_DEVICE_TYPE_DDR4)
                        {
                            const fapi::Target &DIMM_DDR4_TARGET = l_dimm_targets[k];
                            const uint8_t &DEVICE_TYPE = l_spd_dramtype;
                            FAPI_ERR("mss_volt: DDR3 and DDR4 mixing not allowed");
                            FAPI_SET_HWP_ERROR(l_rc, RC_MSS_VOLT_DDR_TYPE_MIXING_UNSUPPORTED);
                            fapiLogError(l_rc);
                        }

                    }//end of dimms loop
                    if (l_rc)
                    {
                        break;
                    }
                }//end of mba loop
                if (l_rc)
                {
                    break;
                }
            }//end of centaur (memb) loop 

        }
        if (l_rc)
        {
            // Break out of do...while(0)
            break;
        }


	if (l_volt_override != fapi::ENUM_ATTR_MSS_VOLT_OVERRIDE_NONE)
	{
	    if (l_volt_override == fapi::ENUM_ATTR_MSS_VOLT_OVERRIDE_VOLT_135)
	    {
		l_tolerated_dram_voltage = 1350;
		FAPI_INF( "mss_volt_overide being applied.  MSS_VOLT_OVERRIDE: 1.35V");
		FAPI_INF( "NOTE: Still checking for violations of tolerated voltage.  If DIMMs cannot tolerate, the override will not be applied.");
	    }
	    if (l_volt_override == fapi::ENUM_ATTR_MSS_VOLT_OVERRIDE_VOLT_120)
	    {
	        l_tolerated_dram_voltage = 1200;
		FAPI_INF( "mss_volt_overide being applied.  MSS_VOLT_OVERRIDE: 1.20V");
		FAPI_INF( "NOTE: Still checking for violations of tolerated voltage.  If DIMMs cannot tolerate, the override will not be applied.");
	    }
	    else
	    {
                const uint8_t &OVERRIDE_TYPE = l_volt_override;
                FAPI_ERR("Unknown volt override request.  Override Request: 0x%x", l_volt_override);
                FAPI_SET_HWP_ERROR(l_rc, RC_MSS_VOLT_OVERIDE_UKNOWN);
                fapiLogError(l_rc);
	    }

	}
        else if (l_dram_ddr3_found_flag && ((l_spd_volts_all_dimms & fapi::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_OP1_35) == fapi::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_OP1_35))
        {
            l_selected_dram_voltage=1350;
	    l_selected_dram_voltage_vpp = DDR3_VPP_VOLT;
        }
        else if (l_dram_ddr4_found_flag && ((l_spd_volts_all_dimms & fapi::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_OP1_2X) == fapi::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_OP1_2X))
        {
            l_selected_dram_voltage=1200;
            l_selected_dram_voltage_vpp = DDR4_VPP_VOLT;
        }
        else if ((l_spd_volts_all_dimms & fapi::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_NOTOP1_5) != fapi::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_NOTOP1_5)
        {
            l_selected_dram_voltage=1500;
	    l_selected_dram_voltage_vpp = DDR3_VPP_VOLT;
        }
        else
        {

            std::vector<fapi::Target> l_dimm_targets_deconfig;
            // Iterate through the list of centaurs
            for (uint32_t i=0; i < i_targets_memb.size(); i++)
            {
                std::vector<fapi::Target> l_mbaChiplets;
                // Get associated MBA's on this centaur
                l_rc=fapiGetChildChiplets(i_targets_memb[i], fapi::TARGET_TYPE_MBA_CHIPLET, l_mbaChiplets);
                if (l_rc) break;
                // Loop through the 2 MBA's
                for (uint32_t j=0; j < l_mbaChiplets.size(); j++)
                {
                    std::vector<fapi::Target> l_dimm_targets; 
                    // Get a vector of DIMM targets
                    l_rc = fapiGetAssociatedDimms(l_mbaChiplets[j], l_dimm_targets, fapi::TARGET_STATE_PRESENT);
                    if (l_rc) break;
                    for (uint32_t k=0; k < l_dimm_targets.size(); k++)
                    {
                        l_rc = FAPI_ATTR_GET(ATTR_SPD_MODULE_NOMINAL_VOLTAGE, &l_dimm_targets[k], l_spd_volts);
                        if (l_rc) break;

                        if((l_spd_volts & fapi::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_NOTOP1_5) == fapi::ENUM_ATTR_SPD_MODULE_NOMINAL_VOLTAGE_NOTOP1_5)
                        {
                            const fapi::Target &DIMM_UV_TARGET = l_dimm_targets[k];
                            const uint8_t &DIMM_VOLTAGE = l_spd_volts;
                            FAPI_ERR("One or more DIMMs do not support required voltage for DIMM type");
                            FAPI_SET_HWP_ERROR(l_rc, RC_MSS_VOLT_DDR_TYPE_REQUIRED_VOLTAGE);
                            fapiLogError(l_rc);
                        }

                    }//end of dimms loop
                    if (l_rc)
                    {
                        break;
                    }
                }//end of mba loop
                if (l_rc)
                {
                    break;
                }
            }//end of centaur (memb) loop  
        }
        if (l_rc)
        {
            // Break out of do...while(0)
            break;
        }



        // Must check to see if we violate Tolerent voltages of Non-functional Dimms
        // If so we must error/deconfigure on the dimm level primarily then centaur level.
        // Iterate through the list of centaurs
        for (uint32_t i=0; i < i_targets_memb.size(); i++)
        {
            std::vector<fapi::Target> l_dimm_targets_deconfig;

            l_tolerated_dram_voltage = MAX_TOLERATED_VOLT; // using 1.5 as this is the largest supported voltage
            std::vector<fapi::Target> l_mbaChiplets;
            // Get associated MBA's on this centaur
            l_rc=fapiGetChildChiplets(i_targets_memb[i], fapi::TARGET_TYPE_MBA_CHIPLET, l_mbaChiplets);
            if (l_rc) break;
            for (uint32_t j=0; j < l_mbaChiplets.size(); j++)
            {
                std::vector<fapi::Target> l_dimm_targets;
                // Get a vector of DIMM targets
                l_rc = fapiGetAssociatedDimms(l_mbaChiplets[j], l_dimm_targets, fapi::TARGET_STATE_PRESENT);
                if (l_rc) break;
                for (uint32_t k=0; k < l_dimm_targets.size(); k++)
                {
                    l_rc = FAPI_ATTR_GET(ATTR_FUNCTIONAL, &l_dimm_targets[k], l_dimm_functionality);
                    if (l_rc) break;

                    if(l_dimm_functionality == fapi::ENUM_ATTR_FUNCTIONAL_NON_FUNCTIONAL)
                    {
                        if (l_spd_dramtype == fapi::ENUM_ATTR_SPD_DRAM_DEVICE_TYPE_DDR3)
                        {
                            if (l_tolerated_dram_voltage > MAX_TOLERATED_DDR3_VOLT)
                            {
                                l_tolerated_dram_voltage =  MAX_TOLERATED_DDR3_VOLT;
                            }

                            if (MAX_TOLERATED_DDR3_VOLT < l_selected_dram_voltage)
                            {
                                FAPI_ERR("One or more DIMMs classified non-functional has a"
                                         " tolerated voltage below selected voltage.");
                                const fapi::Target & CHIP_TARGET = l_dimm_targets[k];
                                const uint8_t &DIMM_VOLTAGE = l_selected_dram_voltage;
                                FAPI_SET_HWP_ERROR(l_rc, RC_MSS_VOLT_TOLERATED_VOLTAGE_VIOLATION);
                                fapiLogError(l_rc);
                            }
                        }
                        if (l_spd_dramtype == fapi::ENUM_ATTR_SPD_DRAM_DEVICE_TYPE_DDR4)
                        {
                            if (l_tolerated_dram_voltage > MAX_TOLERATED_DDR4_VOLT)
                            {
                                l_tolerated_dram_voltage =  MAX_TOLERATED_DDR4_VOLT;
                            }

                            if (MAX_TOLERATED_DDR4_VOLT < l_selected_dram_voltage)
                            {
                                FAPI_ERR("One or more DIMMs classified non-functional has a"
                                         " tolerated voltage below selected voltage.");
                                const fapi::Target & CHIP_TARGET = l_dimm_targets[k];
                                const uint8_t &DIMM_VOLTAGE = l_selected_dram_voltage;
                                FAPI_SET_HWP_ERROR(l_rc, RC_MSS_VOLT_TOLERATED_VOLTAGE_VIOLATION);
                                fapiLogError(l_rc);
                            }
                        }

                    }//End of functional check
                }//End of Dimm loop
                if (l_rc)
                {
                    break;
                }
            }// End of MBA loop
            if (l_rc)
            {
                break;
            }
            if ( l_tolerated_dram_voltage < l_selected_dram_voltage )
            {

                FAPI_ERR("Deconfiguring the associated Centaur.");
                const fapi::Target & CHIP_TARGET = i_targets_memb[i];
                const uint8_t &DIMM_VOLTAGE = l_selected_dram_voltage;
                FAPI_SET_HWP_ERROR(l_rc, RC_MSS_VOLT_TOLERATED_VOLTAGE_VIOLATION);
                break;
            }
        }//End of Centaur (MEMB) loop
        if (l_rc)
        {
            // Break out of do...while(0)
            break;
        }

        // Iterate through the list of centaurs again, to update ATTR
        for (uint32_t i=0; i < i_targets_memb.size(); i++)
        {
            l_rc = FAPI_ATTR_SET(ATTR_MSS_VOLT, &i_targets_memb[i], l_selected_dram_voltage);
            FAPI_INF( "mss_volt calculation complete.  MSS_VOLT: %d", l_selected_dram_voltage);
            if (l_rc) break;

	    l_rc = FAPI_ATTR_SET(ATTR_MSS_VOLT_VPP, &i_targets_memb[i], l_selected_dram_voltage_vpp);
            FAPI_INF( "mss_volt calculation complete.  MSS_VOLT_VPP: %d", l_selected_dram_voltage_vpp);
            if (l_rc) break;

        }
    }while(0);
    return l_rc;
}
//******************************************************************************
//* name=mss_eff_config_rank_group, param=i_target_mba, return=ReturnCode
//******************************************************************************
fapi::ReturnCode mss_eff_config_rank_group(const fapi::Target i_target_mba) {
   fapi::ReturnCode rc = fapi::FAPI_RC_SUCCESS;
   const char * const PROCEDURE_NAME = "mss_eff_config_rank_group";
   const fapi::Target& TARGET_MBA = i_target_mba;
   FAPI_INF("*** Running %s on %s ... ***", PROCEDURE_NAME, i_target_mba.toEcmdString());

   const uint8_t PORT_SIZE = 2;
   const uint8_t DIMM_SIZE = 2;
   // ATTR_EFF_DRAM_GEN: EMPTY = 0, DDR3 = 1, DDR4 = 2,
   // ATTR_EFF_DIMM_TYPE: CDIMM = 0, RDIMM = 1, UDIMM = 2, LRDIMM = 3,
   uint8_t num_ranks_per_dimm_u8array[PORT_SIZE][DIMM_SIZE];
   uint8_t dram_gen_u8;
   uint8_t dimm_type_u8;

   rc = FAPI_ATTR_GET(ATTR_EFF_NUM_RANKS_PER_DIMM, &i_target_mba, num_ranks_per_dimm_u8array); if(rc) return rc;
   rc = FAPI_ATTR_GET(ATTR_EFF_DRAM_GEN, &i_target_mba, dram_gen_u8); if(rc) return rc;
   rc = FAPI_ATTR_GET(ATTR_EFF_DIMM_TYPE, &i_target_mba, dimm_type_u8); if(rc) return rc;

   uint8_t primary_rank_group0_u8array[PORT_SIZE];
   uint8_t primary_rank_group1_u8array[PORT_SIZE];
   uint8_t primary_rank_group2_u8array[PORT_SIZE];
   uint8_t primary_rank_group3_u8array[PORT_SIZE];
   uint8_t secondary_rank_group0_u8array[PORT_SIZE];
   uint8_t secondary_rank_group1_u8array[PORT_SIZE];
   uint8_t secondary_rank_group2_u8array[PORT_SIZE];
   uint8_t secondary_rank_group3_u8array[PORT_SIZE];
   uint8_t tertiary_rank_group0_u8array[PORT_SIZE];
   uint8_t tertiary_rank_group1_u8array[PORT_SIZE];
   uint8_t tertiary_rank_group2_u8array[PORT_SIZE];
   uint8_t tertiary_rank_group3_u8array[PORT_SIZE];
   uint8_t quanternary_rank_group0_u8array[PORT_SIZE];
   uint8_t quanternary_rank_group1_u8array[PORT_SIZE];
   uint8_t quanternary_rank_group2_u8array[PORT_SIZE];
   uint8_t quanternary_rank_group3_u8array[PORT_SIZE];

   for (uint8_t cur_port = 0; cur_port < PORT_SIZE; cur_port += 1) {
      //Removed 32G CDIMM 1R dualdrop workaround.
      //NOTE: Needs mss_draminit_training.C v1.57 or newer.
      //if ((dimm_type_u8 == CDIMM) && (num_ranks_per_dimm_u8array[cur_port][0] == 1) && (num_ranks_per_dimm_u8array[cur_port][1] == 1)) {
         // NOTE: 32G CDIMM 1R dualdrop workaround, normally primary_rank_group0=0, primary_rank_group1=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] = 4;
         //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;
      //} else if (dimm_type_u8 == LRDIMM) {
      if (dimm_type_u8 == LRDIMM) {
         primary_rank_group2_u8array[cur_port] = INVALID;
         secondary_rank_group2_u8array[cur_port] = INVALID;
         tertiary_rank_group2_u8array[cur_port] = INVALID;
         quanternary_rank_group2_u8array[cur_port] = INVALID;

         primary_rank_group3_u8array[cur_port] = INVALID;
         secondary_rank_group3_u8array[cur_port] = INVALID;
         tertiary_rank_group3_u8array[cur_port] = INVALID;
         quanternary_rank_group3_u8array[cur_port] = INVALID;

         // dimm 0 (far socket)
         switch (num_ranks_per_dimm_u8array[cur_port][0]) {
           case 4:               // 4 rank lrdimm
                 primary_rank_group0_u8array[cur_port] = 0;
                 secondary_rank_group0_u8array[cur_port] = 1;
                 tertiary_rank_group0_u8array[cur_port] = 2;
                 quanternary_rank_group0_u8array[cur_port] = 3;
                 break;
           case 8:               // 8 rank lrdimm falls through to 2 rank case
         // Rank Multiplication mode needed, CS2 & CS3 used as address lines into LRBuffer
         // RM=4 -> only 2 CS valid, each CS controls 4 ranks with CS2 & CS3 as address
         // CS0 = rank 0, 2, 4, 6;  CS1 = rank 1, 3, 5, 7
           case 2:               // 2 rank lrdimm
                 primary_rank_group0_u8array[cur_port] = 0;
                 secondary_rank_group0_u8array[cur_port] = 1;
                 tertiary_rank_group0_u8array[cur_port] = INVALID;
                 quanternary_rank_group0_u8array[cur_port] = INVALID;
                 break;
           case 1:               // 1 rank lrdimm
                 primary_rank_group0_u8array[cur_port] = 0;
                 secondary_rank_group0_u8array[cur_port] = INVALID;
                 tertiary_rank_group0_u8array[cur_port] = INVALID;
                 quanternary_rank_group0_u8array[cur_port] = INVALID;
                 break;
           default:              // not 1, 2, 4, or 8 ranks
                 primary_rank_group0_u8array[cur_port] = INVALID;
                 secondary_rank_group0_u8array[cur_port] = INVALID;
                 tertiary_rank_group0_u8array[cur_port] = INVALID;
                 quanternary_rank_group0_u8array[cur_port] = INVALID;
         }
         // dimm 1 (near socket)
         switch (num_ranks_per_dimm_u8array[cur_port][1]) {
           case 4:               // 4 rank lrdimm
                 primary_rank_group1_u8array[cur_port] = 4;
                 secondary_rank_group1_u8array[cur_port] = 5;
                 tertiary_rank_group1_u8array[cur_port] = 6;
                 quanternary_rank_group1_u8array[cur_port] = 7;
                 break;
           case 8:               // 8 rank lrdimm falls through to case 2
         // Rank Multiplication mode needed, CS6 & CS7 used as address lines into LRBuffer
         // RM=4 -> only 2 CS valid, each CS controls 4 ranks with CS6 & CS7 as address
         // CS4 = rank 0, 2, 4, 6;  CS5 = rank 1, 3, 5, 7
           case 2:               // 2 rank lrdimm, RM=0
                 primary_rank_group1_u8array[cur_port] = 4;
                 secondary_rank_group1_u8array[cur_port] = 5;
                 tertiary_rank_group1_u8array[cur_port] = INVALID;
                 quanternary_rank_group1_u8array[cur_port] = INVALID;
                 break;
           case 1:               // 1 rank lrdimm
                 primary_rank_group1_u8array[cur_port] = 4;
                 secondary_rank_group1_u8array[cur_port] = INVALID;
                 tertiary_rank_group1_u8array[cur_port] = INVALID;
                 quanternary_rank_group1_u8array[cur_port] = INVALID;
                 break;
           default:              // not 1, 2, 4, or 8 ranks
                 primary_rank_group1_u8array[cur_port] = INVALID;
                 secondary_rank_group1_u8array[cur_port] = INVALID;
                 tertiary_rank_group1_u8array[cur_port] = INVALID;
                 quanternary_rank_group1_u8array[cur_port] = INVALID;
         }

      } else { // RDIMM or CDIMM
         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] = 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;
         } else if ((num_ranks_per_dimm_u8array[cur_port][0] > 0) && (num_ranks_per_dimm_u8array[cur_port][1] > 0)) {
            if (num_ranks_per_dimm_u8array[cur_port][0] != num_ranks_per_dimm_u8array[cur_port][1]) {
               FAPI_ERR("%s: FAILED!", PROCEDURE_NAME);
               FAPI_ERR("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], i_target_mba.toEcmdString(), cur_port);
               FAPI_SET_HWP_ERROR(rc, RC_MSS_EFF_CONFIG_RANK_GROUP_NON_MATCH_RANKS);
               return rc;
            }
            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_ERR("%s: FAILED!", PROCEDURE_NAME);
               FAPI_ERR("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], i_target_mba.toEcmdString(), cur_port);
               FAPI_SET_HWP_ERROR(rc, RC_MSS_EFF_CONFIG_RANK_GROUP_NUM_RANKS_NEQ1);
               return rc;
            }
         } 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_ERR("%s: FAILED!", PROCEDURE_NAME);
            FAPI_ERR("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], i_target_mba.toEcmdString(), cur_port);
            FAPI_SET_HWP_ERROR(rc, RC_MSS_EFF_CONFIG_RANK_GROUP_NO_MATCH);
            return rc;
         }
         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], i_target_mba.toEcmdString(), cur_port);
   }
   rc = FAPI_ATTR_SET(ATTR_EFF_PRIMARY_RANK_GROUP0, &i_target_mba, primary_rank_group0_u8array); if(rc) return rc;
   rc = FAPI_ATTR_SET(ATTR_EFF_PRIMARY_RANK_GROUP1, &i_target_mba, primary_rank_group1_u8array); if(rc) return rc;
   rc = FAPI_ATTR_SET(ATTR_EFF_PRIMARY_RANK_GROUP2, &i_target_mba, primary_rank_group2_u8array); if(rc) return rc;
   rc = FAPI_ATTR_SET(ATTR_EFF_PRIMARY_RANK_GROUP3, &i_target_mba, primary_rank_group3_u8array); if(rc) return rc;
   rc = FAPI_ATTR_SET(ATTR_EFF_SECONDARY_RANK_GROUP0, &i_target_mba, secondary_rank_group0_u8array); if(rc) return rc;
   rc = FAPI_ATTR_SET(ATTR_EFF_SECONDARY_RANK_GROUP1, &i_target_mba, secondary_rank_group1_u8array); if(rc) return rc;
   rc = FAPI_ATTR_SET(ATTR_EFF_SECONDARY_RANK_GROUP2, &i_target_mba, secondary_rank_group2_u8array); if(rc) return rc;
   rc = FAPI_ATTR_SET(ATTR_EFF_SECONDARY_RANK_GROUP3, &i_target_mba, secondary_rank_group3_u8array); if(rc) return rc;
   rc = FAPI_ATTR_SET(ATTR_EFF_TERTIARY_RANK_GROUP0, &i_target_mba, tertiary_rank_group0_u8array); if(rc) return rc;
   rc = FAPI_ATTR_SET(ATTR_EFF_TERTIARY_RANK_GROUP1, &i_target_mba, tertiary_rank_group1_u8array); if(rc) return rc;
   rc = FAPI_ATTR_SET(ATTR_EFF_TERTIARY_RANK_GROUP2, &i_target_mba, tertiary_rank_group2_u8array); if(rc) return rc;
   rc = FAPI_ATTR_SET(ATTR_EFF_TERTIARY_RANK_GROUP3, &i_target_mba, tertiary_rank_group3_u8array); if(rc) return rc;
   rc = FAPI_ATTR_SET(ATTR_EFF_QUATERNARY_RANK_GROUP0, &i_target_mba, quanternary_rank_group0_u8array); if(rc) return rc;
   rc = FAPI_ATTR_SET(ATTR_EFF_QUATERNARY_RANK_GROUP1, &i_target_mba, quanternary_rank_group1_u8array); if(rc) return rc;
   rc = FAPI_ATTR_SET(ATTR_EFF_QUATERNARY_RANK_GROUP2, &i_target_mba, quanternary_rank_group2_u8array); if(rc) return rc;
   rc = FAPI_ATTR_SET(ATTR_EFF_QUATERNARY_RANK_GROUP3, &i_target_mba, quanternary_rank_group3_u8array); if(rc) return rc;

   FAPI_INF("%s on %s COMPLETE", PROCEDURE_NAME, i_target_mba.toEcmdString());
   return rc;
}
///
/// @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;
    }
Example #8
0
fapi2::ReturnCode pm_cme_fir_reset(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target)
{
    FAPI_IMP("pm_cme_fir_reset start");
    auto l_eqChiplets = i_target.getChildren<fapi2::TARGET_TYPE_EQ>
                        (fapi2::TARGET_STATE_FUNCTIONAL);
    uint8_t firinit_done_flag;

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PM_FIRINIT_DONE_ONCE_FLAG,
                           i_target, firinit_done_flag),
             "ERROR: Failed to fetch the entry status of FIRINIT");

    for (auto l_eq_chplt : l_eqChiplets)
    {
        //We cannot rely on the HWAS state because during an MPIPL
        //the cores get stopped and the SP doesnt know until an
        //attr sync occurs with the platform. We must use the
        //query_cache_state to safely determine if we can scom
        //the ex targets
        fapi2::ReturnCode l_rc;
        bool l_l2_is_scanable[MAX_L2_PER_QUAD];
        bool l_l2_is_scomable[MAX_L2_PER_QUAD];
        bool l_l3_is_scanable[MAX_L3_PER_QUAD];
        bool l_l3_is_scomable[MAX_L3_PER_QUAD];

        for (auto cnt = 0; cnt < MAX_L2_PER_QUAD; ++cnt)
        {
            l_l2_is_scomable[cnt] = false;
            l_l2_is_scanable[cnt] = false;
        }

        for (auto cnt = 0; cnt < MAX_L3_PER_QUAD; ++cnt)
        {
            l_l3_is_scanable[cnt] = false;
            l_l3_is_scomable[cnt] = false;
        }

        uint8_t l_chip_unit_pos;

        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS,
                               l_eq_chplt, l_chip_unit_pos),
                 "ERROR: Failed to get the chip unit pos attribute from the eq");

        FAPI_EXEC_HWP(l_rc, p9_query_cache_access_state, l_eq_chplt,
                      l_l2_is_scomable, l_l2_is_scanable,
                      l_l3_is_scomable, l_l3_is_scanable);
        FAPI_TRY(l_rc, "ERROR: failed to query cache access state for EQ %d",
                 l_chip_unit_pos);


        auto l_exChiplets = l_eq_chplt.getChildren<fapi2::TARGET_TYPE_EX>
                            (fapi2::TARGET_STATE_FUNCTIONAL);

        for(auto l_ex_chplt : l_exChiplets)
        {
            FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS,
                                   l_ex_chplt, l_chip_unit_pos),
                     "ERROR: Failed to get the chip unit pos attribute from the ex");

            //look ex is scommable
            l_chip_unit_pos = l_chip_unit_pos % 2;

            if ((!(l_l2_is_scomable[l_chip_unit_pos]) &&
                 !(l_l3_is_scomable[l_chip_unit_pos])))
            {
                continue;
            }

            p9pmFIR::PMFir <p9pmFIR::FIRTYPE_CME_LFIR> l_cmeFir(l_ex_chplt);

            /* Only save off the FIR masks if they have been initialized */
            if ( firinit_done_flag != fapi2::ENUM_ATTR_PM_FIRINIT_DONE_ONCE_FLAG_FIRS_RESET_IN_HB )
            {
                FAPI_TRY(l_cmeFir.get(p9pmFIR::REG_FIRMASK),
                         "ERROR: Failed to get the PBA FIR MASK value");

                /* Fetch the CME FIR MASK; Save it to HWP attribute; clear it */
                FAPI_TRY(l_cmeFir.saveMask(),
                         "ERROR: Failed to save CME FIR Mask to the attribute");

                FAPI_TRY(l_cmeFir.setAllRegBits(p9pmFIR::REG_FIRMASK),
                         "ERROR: Faled to set the CME FIR MASK");

                FAPI_TRY(l_cmeFir.put(),
                         "ERROR:Failed to write to the CME FIR MASK");
            }
        }
    }

    if (firinit_done_flag == fapi2::ENUM_ATTR_PM_FIRINIT_DONE_ONCE_FLAG_NO_INIT)
    {
        firinit_done_flag   =   fapi2::ENUM_ATTR_PM_FIRINIT_DONE_ONCE_FLAG_FIRS_RESET_IN_HB;
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_PM_FIRINIT_DONE_ONCE_FLAG, i_target, firinit_done_flag ),
                 "ERROR: Failed to set attribute PM_FIRINIT_DONE_ONCE_FLAG to RESET_IN_HB in pm_cme_fir_reset");
    }

fapi_try_exit:
    return fapi2::current_err;
}
fapi2::ReturnCode p9_io_obus_firmask_restore(const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target_chip,
        const std::vector<fapi2::Target<fapi2::TARGET_TYPE_OBUS>> i_obus_targets)
{
    FAPI_IMP("p9_io_obus_firmask_restore: Entering...");
    uint64_t l_restoreValue;

    // Read the proc's obus firmask value we stored previously
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_IO_PB_IOOFIR_MASK,
                           i_target_chip,
                           l_restoreValue),
             "failed to get attribute ATTR_IO_PB_IOOFIR_MASK");

    // If ATTR_IO_PB_IOOFIR_MASK is zero that indicates that firmask_save has not been
    // called yet so we will not restore this firmask
    // Note: it was decided to keep these attribute checks seperate to allow
    //       attribute overrides of these attributes to take effect on HBRT reset
    if(l_restoreValue)
    {
        // Write the stored value back to the scom register
        FAPI_TRY(fapi2::putScom(i_target_chip,
                                PU_IOE_PB_IOO_FIR_MASK_REG,
                                l_restoreValue),
                 "putScom of PU_IOE_PB_IOO_FIR_MASK_REG failed");

        // Need to write 0 to ATTR_IO_PB_IOOFIR_MASK to ensure
        // we do not re-write the obus firmask values on HBRT
        // reboots or MPIPLs
        l_restoreValue = 0;
        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_IO_PB_IOOFIR_MASK,
                               i_target_chip,
                               l_restoreValue),
                 "failed to set attribute ATTR_IO_PB_IOOFIR_MASK");
    }
    else
    {
        FAPI_IMP("p9_io_obus_firmask_restore: Skipping restore of PU_IOE_PB_IOO_FIR_MASK_REG because ATTR_IO_PB_IOOFIR_MASK  is 0");
    }


    // Loop through obus targets and restore the IOO LFIR value if necessary
    for(const auto& l_obusTarget : i_obus_targets)
    {
        // Read the obus's obus firmask value we stored previously
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_IO_OLLFIR_MASK,
                               l_obusTarget,
                               l_restoreValue),
                 "failed to get attribute ATTR_IO_OLLFIR_MASK");

        // If ATTR_IO_OLLFIR_MASK is zero that indicates that firmask_save has not been
        // called yet so we will not restore this firmask
        // Note: it was decided to keep these attribute checks seperate to allow
        //       attribute overrides of these attributes to take effect on HBRT reset
        if(l_restoreValue)
        {

            // Write the stored value back to the scom register
            FAPI_TRY(fapi2::putScom(l_obusTarget,
                                    OBUS_LL0_LL0_LL0_PB_IOOL_FIR_MASK_REG,
                                    l_restoreValue),
                     "putScom of OBUS_LL0_LL0_LL0_PB_IOOL_FIR_MASK_REG failed");

            // Need to write 0 to ATTR_IO_OLLFIR_MASK to ensure
            // we do not re-write the obus firmask values on HBRT
            // reboots or MPIPLs
            l_restoreValue = 0;
            FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_IO_OLLFIR_MASK,
                                   l_obusTarget,
                                   l_restoreValue),
                     "failed to set attribute ATTR_IO_OLLFIR_MASK");
        }
        else
        {
            FAPI_IMP("p9_io_obus_firmask_restore: Skipping restore of OBUS_LL0_LL0_LL0_PB_IOOL_FIR_MASK_REG because ATTR_IO_OLLFIR_MASK is 0");
        }
    }

fapi_try_exit:
    FAPI_IMP("p9_io_obus_firmask_restore: Exiting...");
    return fapi2::current_err;
}
Example #10
0
///
/// @brief Calculate target epsilon settings to apply based on
///        system configuration
///
/// @param[in] i_target                System target
/// @param[in] i_core_floor_ratio      Fabric/core floor enum
/// @param[in] i_core_ceiling_ratio    Fabric/core ceiling enum
/// @param[in] i_freq_fbc              Absolute fabric frequency
/// @param[in] i_freq_core_ceiling     Absolute core ceiling frequency
///
/// @return fapi2::ReturnCode. FAPI2_RC_SUCCESS if success, else error code.
///
fapi2::ReturnCode
p9_fbc_eff_config_calc_epsilons(
    const fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>& i_target,
    const fapi2::ATTR_PROC_FABRIC_CORE_FLOOR_RATIO_Type i_core_floor_ratio,
    const fapi2::ATTR_PROC_FABRIC_CORE_CEILING_RATIO_Type i_core_ceiling_ratio,
    const fapi2::ATTR_FREQ_PB_MHZ_Type i_freq_fbc,
    const fapi2::ATTR_FREQ_CORE_CEILING_MHZ_Type i_freq_core_ceiling)
{
    FAPI_DBG("Start");

    // epsilon output attributes
    uint32_t l_eps_r[NUM_EPSILON_READ_TIERS];
    uint32_t l_eps_w[NUM_EPSILON_WRITE_TIERS];
    fapi2::ATTR_PROC_EPS_GB_PERCENTAGE_Type l_eps_gb;

    // fetch epsilon table type/pump mode attributes
    fapi2::ATTR_PROC_EPS_TABLE_TYPE_Type l_eps_table_type;
    fapi2::ATTR_PROC_FABRIC_PUMP_MODE_Type l_pump_mode;
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PROC_EPS_TABLE_TYPE, i_target, l_eps_table_type),
             "Error from FAPI_ATTR_GET(ATTR_PROC_EPS_TABLE_TYPE)");

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PROC_FABRIC_PUMP_MODE, i_target, l_pump_mode),
             "Error from FAPI_ATTR_GET(ATTR_PROC_FABRIC_PUMP_MODE)");

    switch(l_eps_table_type)
    {
        case fapi2::ENUM_ATTR_PROC_EPS_TABLE_TYPE_EPS_TYPE_HE:

            if (l_pump_mode == fapi2::ENUM_ATTR_PROC_FABRIC_PUMP_MODE_CHIP_IS_NODE)
            {
                l_eps_r[0] = EPSILON_R_T0_HE[i_core_floor_ratio];
                l_eps_r[1] = EPSILON_R_T1_HE[i_core_floor_ratio];
                l_eps_r[2] = EPSILON_R_T2_HE[i_core_floor_ratio];

                l_eps_w[0] = EPSILON_W_T0_HE[i_core_floor_ratio];
                l_eps_w[1] = EPSILON_W_T1_HE[i_core_floor_ratio];
            }
            else
            {
                l_eps_r[0] = EPSILON_R_T0_F4[i_core_floor_ratio];
                l_eps_r[1] = EPSILON_R_T1_F4[i_core_floor_ratio];
                l_eps_r[2] = EPSILON_R_T2_F4[i_core_floor_ratio];

                l_eps_w[0] = EPSILON_W_T0_F4[i_core_floor_ratio];
                l_eps_w[1] = EPSILON_W_T1_F4[i_core_floor_ratio];
            }

            break;

        case fapi2::ENUM_ATTR_PROC_EPS_TABLE_TYPE_EPS_TYPE_HE_F8:
            l_eps_r[0] = EPSILON_R_T0_F8[i_core_floor_ratio];

            if (l_pump_mode == fapi2::ENUM_ATTR_PROC_FABRIC_PUMP_MODE_CHIP_IS_NODE)
            {
                l_eps_r[1] = EPSILON_R_T1_F8[i_core_floor_ratio];
            }
            else
            {
                l_eps_r[1] = EPSILON_R_T0_F8[i_core_floor_ratio];
            }

            l_eps_r[2] = EPSILON_R_T2_F8[i_core_floor_ratio];

            l_eps_w[0] = EPSILON_W_T0_F8[i_core_floor_ratio];
            l_eps_w[1] = EPSILON_W_T1_F8[i_core_floor_ratio];
            break;

        case fapi2::ENUM_ATTR_PROC_EPS_TABLE_TYPE_EPS_TYPE_LE:
            l_eps_r[0] = EPSILON_R_T0_LE[i_core_floor_ratio];

            if (l_pump_mode == fapi2::ENUM_ATTR_PROC_FABRIC_PUMP_MODE_CHIP_IS_NODE)
            {
                l_eps_r[1] = EPSILON_R_T1_LE[i_core_floor_ratio];
            }
            else
            {
                l_eps_r[1] = EPSILON_R_T0_LE[i_core_floor_ratio];
            }

            l_eps_r[2] = EPSILON_R_T2_LE[i_core_floor_ratio];

            l_eps_w[0] = EPSILON_W_T0_LE[i_core_floor_ratio];
            l_eps_w[1] = EPSILON_W_T1_LE[i_core_floor_ratio];
            break;

        default:
            FAPI_ASSERT(false,
                        fapi2::P9_FBC_EFF_CONFIG_EPSILON_INVALID_TABLE_TYPE_ERR()
                        .set_TABLE_TYPE(l_eps_table_type),
                        "Invalid epsilon table type 0x%.8X", l_eps_table_type);
            break;
    }

    // dump base epsilon values
    FAPI_DBG("Base epsilon values read from table:");

    for (uint32_t ii = 0; ii < NUM_EPSILON_READ_TIERS; ii++)
    {
        FAPI_DBG(" R_T[%d] = %d", ii, l_eps_r[ii]);
    }

    for (uint32_t ii = 0; ii < NUM_EPSILON_WRITE_TIERS; ii++)
    {
        FAPI_DBG(" W_T[%d] = %d", ii, l_eps_w[ii]);
    }

    // set guardband default value to +20%
    l_eps_gb = +20;
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_PROC_EPS_GB_PERCENTAGE, i_target, l_eps_gb),
             "Error from FAPI_ATTR_SET (ATTR_PROC_EPS_GB_PERCENTAGE)");

    // get gardband attribute
    // Note: if a user makes an attribute override with CONST, it would
    // override the above default value settings. This mechanism is to
    // allow users to change the default settings for testing.
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PROC_EPS_GB_PERCENTAGE, i_target, l_eps_gb),
             "Error from FAPI_ATTR_GET (ATTR_PROC_EPS_GB_PERCENTAGE)");

    FAPI_DBG("ATTR_PROC_EPS_GB_PERCENTAGE %s%d, ",
             (l_eps_gb >= 0) ? ("+") : ("-"), l_eps_gb);

    // scale base epsilon values if core is running 2x nest frequency
    if (i_core_ceiling_ratio == fapi2::ENUM_ATTR_PROC_FABRIC_CORE_CEILING_RATIO_RATIO_8_8)
    {
        FAPI_DBG("Scaling based on ceiling frequency");
        uint8_t l_scale_percentage =
            100 *
            i_freq_core_ceiling /
            (2 * i_freq_fbc);
        l_scale_percentage -= 100;

        // scale/apply guardband read epsilons
        for (uint32_t ii = 0; ii < NUM_EPSILON_READ_TIERS; ii++)
        {
            p9_fbc_eff_config_guardband_epsilon(l_scale_percentage, l_eps_r[ii]);

        }

        // Scale write epsilons
        for (uint32_t ii = 0; ii < NUM_EPSILON_WRITE_TIERS; ii++)
        {
            p9_fbc_eff_config_guardband_epsilon(l_scale_percentage, l_eps_w[ii]);
        }
    }

    // scale based on guardband, and output final values
    FAPI_DBG("Scaled epsilon values based on %s%d percent guardband:",
             (l_eps_gb >= 0) ? ("+") : ("-"),
             l_eps_gb);

    for (uint32_t ii = 0; ii < NUM_EPSILON_READ_TIERS; ii++)
    {
        p9_fbc_eff_config_guardband_epsilon(l_eps_gb, l_eps_r[ii]);
        FAPI_DBG(" R_T[%d] = %d", ii, l_eps_r[ii]);
    }

    for (uint32_t ii = 0; ii < NUM_EPSILON_WRITE_TIERS; ii++)
    {
        p9_fbc_eff_config_guardband_epsilon(l_eps_gb, l_eps_w[ii]);
        FAPI_DBG(" W_T[%d] = %d", ii, l_eps_w[ii]);
    }

    // check relationship of epsilon counters:
    //   read tier values are strictly increasing
    //   write tier values are strictly increaing
    if ((l_eps_r[0] > l_eps_r[1]) ||
        (l_eps_r[1] > l_eps_r[2]) ||
        (l_eps_w[0] > l_eps_w[1]))
    {
        FAPI_ASSERT(false,
                    fapi2::P9_FBC_EFF_CONFIG_EPSILON_INVALID_TABLE_ERR()
                    .set_TABLE_TYPE(l_eps_table_type)
                    .set_EPS_GB_PERCENTAGE(l_eps_gb)
                    .set_PUMP_MODE(l_pump_mode)
                    .set_R_T0(l_eps_r[0])
                    .set_R_T1(l_eps_r[1])
                    .set_R_T2(l_eps_r[2])
                    .set_W_T0(l_eps_w[0])
                    .set_W_T1(l_eps_w[1]),
                    "Invalid relationship between base epsilon values");
    }

    // write attributes
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_PROC_EPS_READ_CYCLES_T0, i_target, l_eps_r[0]),
             "Error from FAPI_ATTR_SET (ATTR_PROC_EPS_READ_CYCLES_T0)");
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_PROC_EPS_READ_CYCLES_T1, i_target, l_eps_r[1]),
             "Error from FAPI_ATTR_SET (ATTR_PROC_EPS_READ_CYCLES_T1)");
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_PROC_EPS_READ_CYCLES_T2, i_target, l_eps_r[2]),
             "Error from FAPI_ATTR_SET (ATTR_PROC_EPS_READ_CYCLES_T2)");

    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_PROC_EPS_WRITE_CYCLES_T1, i_target, l_eps_w[0]),
             "Error from FAPI_ATTR_SET (ATTR_PROC_EPS_WRITE_CYCLES_T1)");
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_PROC_EPS_WRITE_CYCLES_T2, i_target, l_eps_w[1]),
             "Error from FAPI_ATTR_SET (ATTR_PROC_EPS_WRITE_CYCLES_T2)");

fapi_try_exit:
    FAPI_INF("End");
    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
Example #12
0
static fapi2::ReturnCode setup_memory_work_around_attributes(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
    const fapi2::buffer<uint64_t>& i_ecid_part)
{
    uint8_t l_version = 0;
    fapi2::ATTR_MINI_EC_Type l_miniEc = 0;
    fapi2::ATTR_EC_Type l_chipEc = 0;

    FAPI_TRY(FAPI_ATTR_GET_PRIVILEGED(fapi2::ATTR_EC, i_target, l_chipEc));

    if( l_chipEc != 0x10 )
    {
        // Nothing to do if this isn't DD1.0
        return fapi2::FAPI2_RC_SUCCESS;
    }

    i_ecid_part.extractToRight<DD_LEVEL, DD_LEVEL_LEN>(l_version);

    // Workarounds for modules which are before 1.02 (memory part 1)
    if (l_version < ddLevelMemoryPart1)
    {
        FAPI_DBG("seeing version < 1.02 (0x%x) setting attributes", l_version);

        // All these attributes have 1 as their 'YES' enum value
        uint8_t l_value = 1;
        FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_DO_MSS_WR_VREF, i_target, l_value) );
        FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_DO_MSS_VREF_DAC, i_target, l_value) );
        // The value for this is SKIP - we want to skip in sub DD1.02 HW
        FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_SKIP_HW_VREF_CAL,  i_target, l_value) );
    }

    // Workarounds for modules which are before 1.03 (memory part 2)
    if (l_version < ddLevelMemoryPart2)
    {
        FAPI_DBG("seeing version < 1.03 (0x%x) setting attributes", l_version);

        // All these attributes have 1 as their 'YES' enum value
        uint8_t l_value = 1;
        FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_DO_MSS_TRAINING_BAD_BITS, i_target, l_value) );
        // The value for this is SKIP - we want to skip in sub DD1.03 HW
        FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_SKIP_RD_VREF_VREFSENSE_OVERRIDE,  i_target, l_value) );
    }

    // Set the Mini-EC level for firmware to consume
    switch( l_version )
    {
        case(dd_101):
            l_miniEc = 1;
            break;

        case(dd_102):
            l_miniEc = 2;
            break;

        case(dd_103):
            l_miniEc = 3;
            break;
    }

    FAPI_INF("MiniEC=%d", l_miniEc);
    FAPI_TRY( FAPI_ATTR_SET(fapi2::ATTR_MINI_EC, i_target, l_miniEc) );

    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    return fapi2::current_err;
}
Example #13
0
///
/// @brief Process fabric/core frequency attributes and generate
///        derived attributes to drive fabric configuration
///
/// @param[in]     i_target                System target
/// @param[in/out] io_core_floor_ratio     Fabric/core floor enum
/// @param[in/out] io_core_ceiling_ratio   Fabric/core ceiling enum
/// @param[in/out] io_freq_fbc             Absolute fabric frequency
/// @param[in/out] io_freq_core_ceiling    Absolute core ceiling frequency
///
/// @return fapi2::ReturnCode. FAPI2_RC_SUCCESS if success, else error code.
///
fapi2::ReturnCode
p9_fbc_eff_config_process_freq_attributes(
    const fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>& i_target,
    fapi2::ATTR_PROC_FABRIC_CORE_FLOOR_RATIO_Type& io_core_floor_ratio,
    fapi2::ATTR_PROC_FABRIC_CORE_CEILING_RATIO_Type& io_core_ceiling_ratio,
    fapi2::ATTR_FREQ_PB_MHZ_Type& io_freq_fbc,
    fapi2::ATTR_FREQ_CORE_CEILING_MHZ_Type& io_freq_core_ceiling)
{
    FAPI_DBG("Start");
    uint32_t l_freq_core_floor;
    uint32_t l_freq_core_nom;
    uint8_t l_async_safe_mode = fapi2::ENUM_ATTR_PROC_FABRIC_ASYNC_SAFE_MODE_PERFORMANCE_MODE;

    // get core floor/nominal/ceiling frequency attributes
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_FREQ_CORE_FLOOR_MHZ, i_target, l_freq_core_floor),
             "Error from FAPI_ATTR_GET (ATTR_FREQ_CORE_FLOOR_MHZ)");

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_FREQ_CORE_NOMINAL_MHZ, i_target, l_freq_core_nom),
             "Error from FAPI_ATTR_GET (ATTR_FREQ_CORE_NOMINAL_MHZ)");

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_FREQ_CORE_CEILING_MHZ, i_target, io_freq_core_ceiling),
             "Error from FAPI_ATTR_GET (ATTR_FREQ_CORE_CEILING_MHZ)");

    // verify the floor/nominal/ceiling frequencies
    // expect ceiling >= nominal, nominal >= floor
    FAPI_ASSERT(((io_freq_core_ceiling >= l_freq_core_nom) &&
                 (l_freq_core_nom >= l_freq_core_floor)),
                fapi2::P9_FBC_EFF_CONFIG_CORE_FREQ_RANGE_ERR()
                .set_FREQ_CORE_CEILING(io_freq_core_ceiling)
                .set_FREQ_CORE_NOM(l_freq_core_nom)
                .set_FREQ_CORE_FLOOR(l_freq_core_floor),
                "Invalid core frequency ranges: FLOOR: 0x%.8X, NOMINAL: 0x%.8X, CEILING: 0x%.8X",
                l_freq_core_floor, l_freq_core_nom, io_freq_core_ceiling);

    // calculate fabric/core frequency ratio attributes
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_FREQ_PB_MHZ, i_target, io_freq_fbc),
             "Error from FAPI_ATTR_GET (ATTR_FREQ_PB_MHZ)");

    // determine table index based on fabric/core floor frequency ratio
    // breakpoint ratio: core floor 4.0, pb 2.0 (cache floor :: pb = 8/8)
    if ((l_freq_core_floor) >= (2 * io_freq_fbc))
    {
        io_core_floor_ratio = fapi2::ENUM_ATTR_PROC_FABRIC_CORE_FLOOR_RATIO_RATIO_8_8;
    }
    // breakpoint ratio: core floor 3.5, pb 2.0 (cache floor :: pb = 7/8)
    else if ((4 * l_freq_core_floor) >= (7 * io_freq_fbc))
    {
        io_core_floor_ratio = fapi2::ENUM_ATTR_PROC_FABRIC_CORE_FLOOR_RATIO_RATIO_7_8;
    }
    // breakpoint ratio: core floor 3.0, pb 2.0 (cache floor :: pb = 6/8)
    else if ((2 * l_freq_core_floor) >= (3 * io_freq_fbc))
    {
        io_core_floor_ratio = fapi2::ENUM_ATTR_PROC_FABRIC_CORE_FLOOR_RATIO_RATIO_6_8;
    }
    // breakpoint ratio: core floor 2.5, pb 2.0 (cache floor :: pb = 5/8)
    else if ((4 * l_freq_core_floor) >= (5 * io_freq_fbc))
    {
        io_core_floor_ratio = fapi2::ENUM_ATTR_PROC_FABRIC_CORE_FLOOR_RATIO_RATIO_5_8;
    }
    // breakpoint ratio: core floor 2.0, pb 2.0 (cache floor :: pb = 4/8)
    else if (l_freq_core_floor >= io_freq_fbc)
    {
        io_core_floor_ratio = fapi2::ENUM_ATTR_PROC_FABRIC_CORE_FLOOR_RATIO_RATIO_4_8;
    }
    // breakpoint ratio: core floor 1.0, pb 2.0 (cache floor :: pb = 2/8)
    else if ((2 * l_freq_core_floor) >= io_freq_fbc)
    {
        io_core_floor_ratio = fapi2::ENUM_ATTR_PROC_FABRIC_CORE_FLOOR_RATIO_RATIO_2_8;
    }
    // Under-range, raise error
    else
    {
        FAPI_ASSERT(false,
                    fapi2::P9_FBC_EFF_CONFIG_CORE_FLOOR_FREQ_RATIO_ERR()
                    .set_FREQ_PB(io_freq_fbc)
                    .set_FREQ_CORE_FLOOR(l_freq_core_floor)
                    .set_FREQ_CORE_FLOOR_MIN_SUPPORTED(io_freq_fbc / 2),
                    "Unsupported core floor/PB frequency ratio = (%d/%d)",
                    l_freq_core_floor, io_freq_fbc);
    }

    // determine table index based on fabric/core ceiling frequency ratio
    // breakpoint ratio: core ceiling 4.0, pb 2.0 (cache ceiling :: pb = 8/8)
    if ((io_freq_core_ceiling) >= (2 * io_freq_fbc))
    {
        io_core_ceiling_ratio = fapi2::ENUM_ATTR_PROC_FABRIC_CORE_CEILING_RATIO_RATIO_8_8;
    }
    // breakpoint ratio: core ceiling 3.5, pb 2.0 (cache ceiling :: pb = 7/8)
    else if ((4 * io_freq_core_ceiling) >= (7 * io_freq_fbc))
    {
        io_core_ceiling_ratio = fapi2::ENUM_ATTR_PROC_FABRIC_CORE_CEILING_RATIO_RATIO_7_8;
    }
    // breakpoint ratio: core ceiling 3.0, pb 2.0 (cache ceiling :: pb = 6/8)
    else if ((2 * io_freq_core_ceiling) >= (3 * io_freq_fbc))
    {
        io_core_ceiling_ratio = fapi2::ENUM_ATTR_PROC_FABRIC_CORE_CEILING_RATIO_RATIO_6_8;
    }
    // breakpoint ratio: core ceiling 2.5, pb 2.0 (cache ceiling :: pb = 5/8)
    else if ((4 * io_freq_core_ceiling) >= (5 * io_freq_fbc))
    {
        io_core_ceiling_ratio = fapi2::ENUM_ATTR_PROC_FABRIC_CORE_CEILING_RATIO_RATIO_5_8;
    }
    // breakpoint ratio: core ceiling 2.0, pb 2.0 (cache ceiling :: pb = 4/8)
    else if (io_freq_core_ceiling >= io_freq_fbc)
    {
        io_core_ceiling_ratio = fapi2::ENUM_ATTR_PROC_FABRIC_CORE_CEILING_RATIO_RATIO_4_8;
    }
    // breakpoint ratio: core ceiling 1.0, pb 2.0 (cache ceiling :: pb = 2/8)
    else if ((2 * io_freq_core_ceiling) >= io_freq_fbc)
    {
        io_core_ceiling_ratio = fapi2::ENUM_ATTR_PROC_FABRIC_CORE_CEILING_RATIO_RATIO_2_8;
    }
    // Under-range, raise error
    else
    {
        FAPI_ASSERT(false,
                    fapi2::P9_FBC_EFF_CONFIG_CORE_CEILING_FREQ_RATIO_ERR()
                    .set_FREQ_PB(io_freq_fbc)
                    .set_FREQ_CORE_CEILING(io_freq_core_ceiling)
                    .set_FREQ_CORE_CEILING_MIN_SUPPORTED(io_freq_fbc / 2),
                    "Unsupported core ceiling/PB frequency ratio = (%d/%d)",
                    io_freq_core_ceiling, io_freq_fbc);
    }

    // write attributes
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_PROC_FABRIC_CORE_FLOOR_RATIO, i_target, io_core_floor_ratio),
             "Error from FAPI_ATTR_SET (ATTR_PROC_FABRIC_CORE_FLOOR_RATIO)");

    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_PROC_FABRIC_CORE_CEILING_RATIO, i_target, io_core_ceiling_ratio),
             "Error from FAPI_ATTR_SET (ATTR_PROC_FABRIC_CORE_CEILING_RATIO)");

    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_PROC_FABRIC_ASYNC_SAFE_MODE, i_target, l_async_safe_mode),
             "Error from FAPI_ATTR_SET (ATTR_PROC_FABRIC_ASYNC_SAFE_MODE)");

fapi_try_exit:
    FAPI_DBG("End");
    return fapi2::current_err;
}
Example #14
0
// HWP entry point
fapi::ReturnCode proc_getecid(
    const fapi::Target& i_target,
    ecmdDataBufferBase& io_fuseString)
{
    // return code
    fapi::ReturnCode rc;
    uint32_t rc_ecmd = 0;
    uint64_t attr_data[2];

    // mark HWP entry
    FAPI_DBG("proc_getecid: Start");

    io_fuseString.setBitLength(112); // sets size and zeros out buffer
    ecmdDataBufferBase otprom_mode_data(64);
    ecmdDataBufferBase ecid_data(64);

    do
    {

      //
      // clear ECC enable before reading ECID data (read-modify-write OTPROM Mode register)
      //

      rc = fapiGetScom(i_target, OTPC_M_MODE_REGISTER_0x00010008, otprom_mode_data);
      if (!rc.ok())
      {
          FAPI_ERR("proc_getecid: fapiGetScom error (OTPC_M_MODE_REGISTER_0x00010008) for %s",
                   i_target.toEcmdString());
          break;
      }

      rc_ecmd |= otprom_mode_data.clearBit(OTPC_M_MODE_REGISTER_ECC_ENABLE_BIT);
      if (rc_ecmd)
      {
          FAPI_ERR("proc_getecid: Error 0x%X setting up OTPROM Mode register data buffer",
                   rc_ecmd);
          rc.setEcmdError(rc_ecmd);
          break;
      }

      rc = fapiPutScom(i_target, OTPC_M_MODE_REGISTER_0x00010008, otprom_mode_data);
      if (!rc.ok())
      {
          FAPI_ERR("proc_getecid: fapiPutScom error (OTPC_M_MODE_REGISTER_0x00010008) for %s",
                   i_target.toEcmdString());
          break;
      }


      //
      // extract and manipulate ECID data
      //

      rc = fapiGetScom(i_target, ECID_PART_0_0x00018000, ecid_data);
      if (!rc.ok())
      {
          FAPI_ERR("proc_getecid: fapiGetScom error (ECID_PART_0_0x00018000) for %s",
                   i_target.toEcmdString());
          break;
      }

      // 0:63 become 63:0
      rc_ecmd |= ecid_data.reverse();
      // copy bits 0:63 from the scom into 0:63 of the fuseString/attribute data
      rc_ecmd |= io_fuseString.insert(ecid_data,  0, 64);
      attr_data[0] = ecid_data.getDoubleWord(0);

      if (rc_ecmd)
      {
          FAPI_ERR("proc_getecid: Error 0x%X processing ECID (part 0) data buffer",
                   rc_ecmd);
          rc.setEcmdError(rc_ecmd);
          break;
      }

      rc = fapiGetScom(i_target, ECID_PART_1_0x00018001, ecid_data);
      if (!rc.ok())
      {
          FAPI_ERR("proc_getecid: fapiGetScom error (ECID_PART_1_0x00018001) for %s",
                   i_target.toEcmdString());
          break;
      }

      // 0:63 become 63:0
      rc_ecmd |= ecid_data.reverse();
      // copy bits 0:47 from the scom into 64:111 of the fuseString
      // all bits into attribute data
      rc_ecmd |= io_fuseString.insert(ecid_data, 64, 48);
      attr_data[1] = ecid_data.getDoubleWord(0);

      if (rc_ecmd)
      {
          FAPI_ERR("proc_getecid: Error 0x%X processing ECID (part 1) data buffer",
                   rc_ecmd);
          rc.setEcmdError(rc_ecmd);
          break;
      }

      // push fuse string into attribute
      rc = FAPI_ATTR_SET(ATTR_ECID,
                         &i_target,
                         attr_data);
      if (!rc.ok())
      {
          FAPI_ERR("proc_getecid: Error from FAPI_ATTR_SET (ATTR_ECID) for %s (attr_data[0] = %016llX, attr_data[1] = %016llX",
                   i_target.toEcmdString(), attr_data[0], attr_data[1]);
          break;
      }

      //
      // restore ECC enable setting
      //

      rc_ecmd |= otprom_mode_data.setBit(OTPC_M_MODE_REGISTER_ECC_ENABLE_BIT);
      if (rc_ecmd)
      {
          FAPI_ERR("proc_getecid: Error 0x%X setting up OTPROM Mode register data buffer",
                   rc_ecmd);
          rc.setEcmdError(rc_ecmd);
          break;
      }

      rc = fapiPutScom(i_target, OTPC_M_MODE_REGISTER_0x00010008, otprom_mode_data);
      if (!rc.ok())
      {
          FAPI_ERR("proc_getecid: fapiPutScom error (OTPC_M_MODE_REGISTER_0x00010008) for %s",
                   i_target.toEcmdString());
          break;
      }

    } while(0);

    // mark HWP exit
    FAPI_DBG("proc_getecid: End");
    return rc;
}
fapi2::ReturnCode p9_io_obus_firmask_save(const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target_chip,
        const std::vector<fapi2::Target<fapi2::TARGET_TYPE_OBUS>> i_obus_targets)
{
    FAPI_IMP("p9_io_obus_firmask_save: Entering...");

    fapi2::buffer<uint64_t> l_scomBuffer = 0;
    fapi2::buffer<uint64_t> l_action0Buffer = 0;
    fapi2::buffer<uint64_t> l_action1Buffer = 0;

    // First read the PB IOO fir mask register
    FAPI_TRY(fapi2::getScom(i_target_chip,
                            PU_IOE_PB_IOO_FIR_MASK_REG,
                            l_scomBuffer),
             "getScom of PU_IOE_PB_IOO_FIR_MASK_REG failed");

    // Save off scom value we read into ATTR_IO_PB_IOOFIR_MASK
    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_IO_PB_IOOFIR_MASK,
                           i_target_chip,
                           l_scomBuffer),
             "failed to set attribute ATTR_IO_PB_IOOFIR_MASK");

    // Apply mask required for Hostboot IPL time
    // Set bits 28-35 (see above for more details)
    l_scomBuffer.insertFromRight<PU_IOE_PB_IOO_FIR_MASK_REG_PARSER00_ATTN,
                                 SET_LENGTH_8>(SET_BYTE);
    // Set bits 52-59 (see above for more details)
    l_scomBuffer.insertFromRight<PU_IOE_PB_IOO_FIR_MASK_REG_DOB01_ERR,
                                 SET_LENGTH_8>(SET_BYTE);

    // Write modified mask back to scom register
    FAPI_TRY(fapi2::putScom(i_target_chip,
                            PU_IOE_PB_IOO_FIR_MASK_REG,
                            l_scomBuffer),
             "putScom of PU_IOE_PB_IOO_FIR_MASK_REG failed");

    // Loop through obus targets and save off IOO LFIR
    for(const auto& l_obusTarget : i_obus_targets)
    {
        // For each obus target read the IOOL FIR mask and store it in
        // the ATTR_IO_OLLFIR_MASK attribute for later
        FAPI_TRY(fapi2::getScom(l_obusTarget,
                                OBUS_LL0_LL0_LL0_PB_IOOL_FIR_MASK_REG,
                                l_scomBuffer),
                 "getScom of OBUS_LL0_LL0_LL0_PB_IOOL_FIR_MASK_REG failed");

        FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_IO_OLLFIR_MASK,
                               l_obusTarget,
                               l_scomBuffer),
                 "failed to set attribute ATTR_IO_OLLFIR_MASK");

        // For each obus target read the IOOL FIR action registers
        FAPI_TRY(fapi2::getScom(l_obusTarget,
                                OBUS_LL0_PB_IOOL_FIR_ACTION0_REG,
                                l_action0Buffer),
                 "getScom of OBUS_LL0_LL0_LL0_PB_IOOL_FIR_MASK_REG failed");

        FAPI_TRY(fapi2::getScom(l_obusTarget,
                                OBUS_LL0_PB_IOOL_FIR_ACTION1_REG,
                                l_action1Buffer),
                 "getScom of OBUS_LL0_LL0_LL0_PB_IOOL_FIR_MASK_REG failed");

        // Apply mask required for Hostboot IPL time, we must mask additional
        // bits during IPL time because Hostboot does not know about OBUS
        // peer targets yet. When PRD attempts to handle some of these FIRs
        // it will expect the PEER_TARGET information to be there.

        // Set bits 42-47 if the action register indicate the error as recoverable
        for(uint64_t i = PB_IOOL_FIR_MASK_REG_FIR_LINK0_NO_SPARE_MASK;
            i <= OBUS_LL0_LL0_LL0_PB_IOOL_FIR_MASK_REG_LINK1_TOO_MANY_CRC_ERRORS;
            i++)
        {
            if(l_action0Buffer.getBit(i) == 0 &&
               l_action1Buffer.getBit(i) == 1 )
            {
                l_scomBuffer.setBit(i);
            }
        }

        // Set bits 52-59 if the action register indicate the error as recoverable
        for(uint64_t i = OBUS_LL0_LL0_LL0_PB_IOOL_FIR_MASK_REG_LINK0_CORRECTABLE_ARRAY_ERROR;
            i <= OBUS_LL0_LL0_LL0_PB_IOOL_FIR_MASK_REG_LINK1_TOO_MANY_CRC_ERRORS;
            i++)
        {
            if(l_action0Buffer.getBit(i) == 0 &&
               l_action1Buffer.getBit(i) == 1 )
            {
                l_scomBuffer.setBit(i);
            }
        }

        // Write modified mask back to scom register
        FAPI_TRY(fapi2::putScom(l_obusTarget,
                                OBUS_LL0_LL0_LL0_PB_IOOL_FIR_MASK_REG,
                                l_scomBuffer),
                 "putScom of OBUS_LL0_LL0_LL0_PB_IOOL_FIR_MASK_REG failed");
    }

fapi_try_exit:
    FAPI_IMP("p9_io_obus_firmask_restore: Exiting...");
    return fapi2::current_err;
}
Example #16
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;
}
fapi2::ReturnCode p9_chiplet_fabric_scominit(const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target)
{
    fapi2::ReturnCode l_rc;
    char l_procTargetStr[fapi2::MAX_ECMD_STRING_LEN];
    char l_chipletTargetStr[fapi2::MAX_ECMD_STRING_LEN];
    fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> FAPI_SYSTEM;
    std::vector<fapi2::Target<fapi2::TARGET_TYPE_XBUS>> l_xbus_chiplets;
    std::vector<fapi2::Target<fapi2::TARGET_TYPE_OBUS>> l_obus_chiplets;

    fapi2::ATTR_PROC_FABRIC_OPTICS_CONFIG_MODE_Type l_fbc_optics_cfg_mode = { fapi2::ENUM_ATTR_PROC_FABRIC_OPTICS_CONFIG_MODE_SMP };
    FAPI_DBG("Start");

    // Get proc target string
    fapi2::toString(i_target, l_procTargetStr, sizeof(l_procTargetStr));

    // apply FBC non-hotplug initfile
    FAPI_DBG("Invoking p9.fbc.no_hp.scom.initfile on target %s...", l_procTargetStr);
    FAPI_EXEC_HWP(l_rc, p9_fbc_no_hp_scom, i_target, FAPI_SYSTEM);

    if (l_rc)
    {
        FAPI_ERR("Error from p9_fbc_no_hp_scom");
        fapi2::current_err = l_rc;
        goto fapi_try_exit;
    }

    // setup IOE (XBUS FBC IO) TL SCOMs
    FAPI_DBG("Invoking p9.fbc.ioe_tl.scom.initfile on target %s...", l_procTargetStr);
    FAPI_EXEC_HWP(l_rc, p9_fbc_ioe_tl_scom, i_target, FAPI_SYSTEM);

    if (l_rc)
    {
        FAPI_ERR("Error from p9_fbc_ioe_tl_scom");
        fapi2::current_err = l_rc;
        goto fapi_try_exit;
    }

    l_xbus_chiplets = i_target.getChildren<fapi2::TARGET_TYPE_XBUS>();

    if (l_xbus_chiplets.size())
    {
        FAPI_TRY(fapi2::putScom(i_target, PU_PB_IOE_FIR_ACTION0_REG, FBC_IOE_TL_FIR_ACTION0),
                 "Error from putScom (PU_PB_IOE_FIR_ACTION0_REG)");
        FAPI_TRY(fapi2::putScom(i_target, PU_PB_IOE_FIR_ACTION1_REG, FBC_IOE_TL_FIR_ACTION1),
                 "Error from putScom (PU_PB_IOE_FIR_ACTION1_REG)");
        FAPI_TRY(fapi2::putScom(i_target, PU_PB_IOE_FIR_MASK_REG, FBC_IOE_TL_FIR_MASK),
                 "Error from putScom (PU_PB_IOE_FIR_MASK_REG)");
    }

    // setup IOE (XBUS FBC IO) DL SCOMs
    for (auto l_iter = l_xbus_chiplets.begin();
         l_iter != l_xbus_chiplets.end();
         l_iter++)
    {
        fapi2::toString(*l_iter, l_chipletTargetStr, sizeof(l_chipletTargetStr));
        FAPI_DBG("Invoking p9.fbc.ioe_dl.scom.initfile on target %s...", l_chipletTargetStr);
        FAPI_EXEC_HWP(l_rc, p9_fbc_ioe_dl_scom, *l_iter, i_target);

        if (l_rc)
        {
            FAPI_ERR("Error from p9_fbc_ioe_dl_scom");
            fapi2::current_err = l_rc;
            goto fapi_try_exit;
        }

        // configure action registers & unmask
        FAPI_TRY(fapi2::putScom(*l_iter, XBUS_LL0_IOEL_FIR_ACTION0_REG, FBC_IOE_DL_FIR_ACTION0),
                 "Error from putScom (XBUS_LL0_IOEL_FIR_ACTION0_REG)");
        FAPI_TRY(fapi2::putScom(*l_iter, XBUS_LL0_IOEL_FIR_ACTION1_REG, FBC_IOE_DL_FIR_ACTION1),
                 "Error from putScom (XBUS_LL0_IOEL_FIR_ACTION1_REG)");
        FAPI_TRY(fapi2::putScom(*l_iter, XBUS_LL0_LL0_LL0_IOEL_FIR_MASK_REG, FBC_IOE_DL_FIR_MASK),
                 "Error from putScom (XBUS_LL0_LL0_LL0_IOEL_FIR_MASK_REG)");
    }

    // set FBC optics config mode attribute
    l_obus_chiplets = i_target.getChildren<fapi2::TARGET_TYPE_OBUS>();

    for (auto l_iter = l_obus_chiplets.begin();
         l_iter != l_obus_chiplets.end();
         l_iter++)
    {
        uint8_t l_unit_pos;
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, *l_iter, l_unit_pos),
                 "Error from FAPI_ATTR_GET(ATTR_CHIP_UNIT_POS)");
        FAPI_INF("Updating index: %d\n", l_unit_pos);
        FAPI_INF("  before: %d\n", l_fbc_optics_cfg_mode[l_unit_pos]);
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_OPTICS_CONFIG_MODE, *l_iter, l_fbc_optics_cfg_mode[l_unit_pos]),
                 "Error from FAPI_ATTR_GET(ATTR_OPTICS_CONFIG_MODE)");
        FAPI_INF("  after: %d\n", l_fbc_optics_cfg_mode[l_unit_pos]);
    }

    FAPI_TRY(FAPI_ATTR_SET(fapi2::ATTR_PROC_FABRIC_OPTICS_CONFIG_MODE, i_target, l_fbc_optics_cfg_mode),
             "Error from FAPI_ATTR_SET(ATTR_PROC_FABRIC_OPTICS_CONFIG_MODE)");

fapi_try_exit:
    FAPI_DBG("End");
    return fapi2::current_err;
}